Bluetooth Low Energy (BLE) is used in various scenarios, such as pedometers, heart rate monitors, light control, and smart locks.
When devices interact with each other through BLE, they play different roles as follows:

This codelab describes how to enable BLE communication between devices and covers the following content:
Applying for Permissions
BLE Advertising and Scanning
Creating a GATT Server and a GATT Client
Setting Up a GATT Connection and Discovering Services
Communication Between Devices

The procedure is as follows:

Declare the following permissions in the reqPermissions field in the entry\src\main\config.json file:

  1. ohos.permission.USE_BLUETOOTH: allows an app to access Bluetooth configurations.
  2. ohos.permission.DISCOVER_BLUETOOTH: allows an app to configure Bluetooth on the current device and to discover and pair with other Bluetooth devices.
  3. ohos.permission.LOCATION: allows an app running in the foreground to obtain the location.
The sample code is as follows:
"module": { ...... "reqPermissions": [ { "name": "ohos.permission.USE_BLUETOOTH" }, { "name": "ohos.permission.DISCOVER_BLUETOOTH" }, { "name": "ohos.permission.LOCATION", "reason": "$string:permreason_location", "usedScene": { "ability": [ ".BleCentralAbility" ], "when": "inuse" } } ] }

ohos.permission.LOCATION is a sensitive permission. You must explicitly declare it in the code. The sample code is as follows:

public class MainAbility extends Ability { @Override public void onStart(Intent intent) { String[] permissions = {"ohos.permission.LOCATION"}; requestPermissionsFromUser(permissions, 0); super.onStart(intent); } }
  1. To perform BLE advertising, a peripheral device needs to perform the following operations: implementing the BleAdvertiseCallback class, obtaining a BleAdvertiser object, building a BleAdvertiseData instance and a BleAdvertiseSettings instance, and calling the startAdvertising() method to start advertising. The sample code is as follows:
    // Implement the BleAdvertiseCallback class. private class MyBleAdvertiseCallback extends BleAdvertiseCallback { @Override public void startResultEvent(int result) { if (result == BleAdvertiseCallback.RESULT_SUCC) { // Called when the BLE advertising is started successfully. } } } // Build a BleAdvertiseData instance. private BleAdvertiseData advertiseData = new BleAdvertiseData.Builder() .addServiceData(SequenceUuid.uuidFromString(SERVICE_UUID), "12".getBytes(StandardCharsets.UTF_8)) .addServiceUuid(SequenceUuid.uuidFromString(SERVICE_UUID)) .build(); // Build a BleAdvertiseSettings instance. private BleAdvertiseSettings advertiseSettings = new BleAdvertiseSettings.Builder() .setConnectable(true) .setInterval(BleAdvertiseSettings.INTERVAL_SLOT_MIN) .setTxPower(BleAdvertiseSettings.TX_POWER_MAX) .build(); // Obtain a BleAdvertiseCallback. private MyBleAdvertiseCallback advertiseCallback = new MyBleAdvertiseCallback(); // Obtain a BleAdvertiser object. private BleAdvertiser advertiser = new BleAdvertiser(this, advertiseCallback); // Start BLE advertising. advertiser.startAdvertising(advertiseSettings, advertiseData, null);
  2. To perform a BLE scan, the central device needs to perform the following operations: implementing the BleCentralManagerCallback class, obtaining a BleCentralManager object, creating BLE scan filters, and calling the startScan() method to start a scan. The sample code is as follows:
    // Implement the BleCentralManagerCallback class. private class MyBleCentralManagerCallback implements BleCentralManagerCallback { // Called to send a notification of the scan result after a BLE scan is complete. @Override public void scanResultEvent(BleScanResult bleScanResult) { // Obtain the BlePeripheralDevice instance based on the scan result. } // Called when the scan fails. @Override public void scanFailedEvent(int i) { // Scan failure event } // Called when a group of BLE scan results is reported. @Override public void groupScanResultsEvent(List list) { // You can define how to handle the scan results in this callback. } } // Obtain a BleCentralManagerCallback object. private MyBleCentralManagerCallback centralManagerCallback = new MyBleCentralManagerCallback(); // Obtain a BleCentralManager object. private BleCentralManager centralManager = new BleCentralManager(this, centralManagerCallback); // Create BLE scan filters. private List filters = new ArrayList<>(); // Start scanning for specified BLE devices with filters. centralManager.startScan(filters);
  1. Create the GATT server on the BLE peripheral device. The procedure is as follows: Implement the BlePeripheralManagerCallback class, obtain a BlePeripheralManager object, create a GattService object and two GattCharacteristic objects with a specified UUID, and add the GattService object to the BlePeripheralManager object after the BLE advertising is successful. The sample code is as follows:
    // Implement the BlePeripheralManagerCallback class. private class MyBlePeripheralManagerCallback extends BlePeripheralManagerCallback { // Called when the connection state changes. @Override public void connectionStateChangeEvent( BlePeripheralDevice device, int interval, int latency, int timeout, int status) { if (status == BlePeripheralDevice.OPERATION_SUCC) { // A connection has been set up. } } // Called when the GATT client requests to write a characteristic. @Override public void receiveCharacteristicWriteEvent( BlePeripheralDevice device, int transId, GattCharacteristic characteristic, boolean isPrep, boolean needRsp, int offset, byte[] value) { // Obtain the data written by the central device (GATT client). } } // Obtain a BlePeripheralManagerCallback object. private MyBlePeripheralManagerCallback peripheralManagerCallback = new MyBlePeripheralManagerCallback(); // Obtain a BlePeripheralManager object. private BlePeripheralManager blePeripheralManager = new BlePeripheralManager(this, peripheralManagerCallback, 1); // Create a GattService object with a specified UUID. private GattService gattService = new GattService(UUID.fromString(SERVICE_UUID), true); // Create a GattCharacteristic object to send data to the central device. private GattCharacteristic notifyCharacteristic = new GattCharacteristic( UUID.fromString(NOTIFY_CHARACTER_UUID), 1 | GATT_CHARACTERISTIC_PERMISSIONS, GattCharacteristic.PROPERTY_READ | GattCharacteristic.PROPERTY_WRITE | GattCharacteristic.PROPERTY_WRITE_NO_RESPONSE); // Create another GattCharacteristic object to receive data from the central device. private GattCharacteristic writeCharacteristic = new GattCharacteristic( UUID.fromString(WRITE_CHARACTER_UUID), 1 | GATT_CHARACTERISTIC_PERMISSIONS, GattCharacteristic.PROPERTY_READ | GattCharacteristic.PROPERTY_WRITE | GattCharacteristic.PROPERTY_WRITE_NO_RESPONSE); public void startResultEvent(int result) { if (result == BleAdvertiseCallback.RESULT_SUCC) { // Add one or more characteristics to the GattService object. gattService.addCharacteristic(notifyCharacteristic); gattService.addCharacteristic(writeCharacteristic); // Clear all services. blePeripheralManager.clearServices(); // Add the GattService object to the BlePeripheralManager object. blePeripheralManager.addService(gattService); } }
  2. Create the GATT client on the BLE central device. You need to implement the BlePeripheralCallback class. The sample code is as follows:
    // Implement the BlePeripheralCallback class. private class MyBlePeripheralCallback extends BlePeripheralCallback { // Called when services are discovered on the peripheral device. @Override public void servicesDiscoveredEvent(int status) { super.servicesDiscoveredEvent(status); // After the service discovery operation succeeds, this callback is invoked to send a notification and obtain a GattCharacteristic object. } // Called when the connection state changes. @Override public void connectionStateChangeEvent(int connectionState) { super.connectionStateChangeEvent(connectionState); // After a connection is set up, discover GATT services on the peripheral device. } // Called when a characteristic changes. @Override public void characteristicChangedEvent(GattCharacteristic characteristic) { super.characteristicChangedEvent(characteristic); // Receive the data sent by the peripheral device. } } // Obtain a BlePeripheralCallback object. private MyBlePeripheralCallback blePeripheralCallback = new MyBlePeripheralCallback();
  1. After performing a scan on the central device successfully, obtain the SERVICE_UUID in the advertisement data via the scanResultEvent() callback, and obtain the BlePeripheralDevice instance based on the SERVICE_UUID. The sample code is as follows:
    public void scanResultEvent(BleScanResult bleScanResult) { if (peripheralDevice == null) { // Obtain service UUIDs. List<UUID> uuids = bleScanResult.getServiceUuids(); for (UUID uuid : uuids) { if (SERVICE_UUID.equals(uuid.toString())) { // Obtain the BlePeripheralDevice instance based on the scan result. peripheralDevice = bleScanResult.getPeripheralDevice(); } } } }
  2. After obtaining the BlePeripheralDevice instance, call the connect() method on the central device to set up a GATT connection with the peripheral device. After the connection is set up, call the discoverServices() method to discover GATT services on the peripheral device. The sample code is as follows:
    // Set up a GATT connection with the peripheral device. peripheralDevice.connect(false, blePeripheralCallback); public void connectionStateChangeEvent(int connectionState) { super.connectionStateChangeEvent(connectionState); if (connectionState == ProfileBase.STATE_CONNECTED) { isConnected = true; // After a connection is set up, discover GATT services on the peripheral device. peripheralDevice.discoverServices(); } }
  3. When the central device performs a service discovery operation, the servicesDiscoveredEvent() callback is invoked to send notifications of the discovery result. If the operation is successful, the UUID of the discovered service is used to determine the subsequent operation. If the UUID is equal to NOTIFY_CHARACTER_UUID, the setNotifyCharacteristic() method is called to enable characteristic notifications. If the UUID is equal to WRITE_CHARACTER_UUID, the GattCharacteristic instance will be obtained. The sample code is as follows:
    public void servicesDiscoveredEvent(int status) { super.servicesDiscoveredEvent(status); if (status == BlePeripheralDevice.OPERATION_SUCC) { for (GattService service : peripheralDevice.getServices()) { checkGattCharacteristic(service); } } } private void checkGattCharacteristic(GattService service) { for (GattCharacteristic tmpChara : service.getCharacteristics()) { if (tmpChara.getUuid().equals(UUID.fromString(NOTIFY_CHARACTER_UUID))) { // Enable characteristic notifications. peripheralDevice.setNotifyCharacteristic(tmpChara, true); } if (tmpChara.getUuid().equals(UUID.fromString(WRITE_CHARACTER_UUID))) { // Obtain the GattCharacteristic instance. writeCharacteristic = tmpChara; } } }
  1. The central device receives data. When the peripheral device calls the notifyCharacteristicChanged() method to send a notification of a characteristic change, the characteristicChangedEvent() callback is invoked on the central device. The characteristic.getValue() method in the callback can be used to obtain the data received from the peripheral device. The sample code is as follows:
    public void characteristicChangedEvent(GattCharacteristic characteristic) { super.characteristicChangedEvent(characteristic); // Call the characteristic.getValue() method to obtain the data received from the peripheral device. }
  2. The central device sends data. After obtaining the writeCharacteristic instance, call the writeCharacteristic.setValue() method to write data to the writeCharacteristic instance and then call the peripheralDevice.writeCharacteristic() method to write a characteristic to the peripheral device. The sample code is as follows:
    // Send data to the peripheral device. writeCharacteristic.setValue("I am the central device".getBytes(StandardCharsets.UTF_8)); peripheralDevice.writeCharacteristic(writeCharacteristic);
  3. The peripheral device receives data. When the central device calls the writeCharacteristic() method to write a characteristic to the peripheral device, the receiveCharacteristicWriteEvent() callback is invoked to receive the characteristic. The input parameter byte[] value indicates the characteristic written by the central device. The sample code is as follows:
    public void receiveCharacteristicWriteEvent( BlePeripheralDevice device, int transId, GattCharacteristic characteristic, boolean isPrep, boolean needRsp, int offset, byte[] value) { // Obtain the data written by the central device. }
  4. The peripheral device sends data. Call the notifyCharacteristic.setValue() method to write data to the notifyCharacteristic object, and then call the notifyCharacteristicChanged() method to notify the central device that the characteristic has been updated. The sample code is as follows:
    // Send data to the central device. notifyCharacteristic.setValue("I am the peripheral device".getBytes(StandardCharsets.UTF_8)); blePeripheralManager.notifyCharacteristicChanged(peripheralDevice, notifyCharacteristic, false);
  1. Initial UIs of the peripheral device and central device:

  2. The peripheral device starts advertising, and the central device starts a scan.

  3. The central device and peripheral device set up a connection.

  4. The peripheral device sends data, and the central device receives data.

  5. The central device sends data, and the peripheral device receives data.

Well done! You have completed this codelab and learned how to enable BLE communication between devices.

Code Structure

For your convenience, we provide the complete code for a sample BLE project. The code structure is as follows:

Writing the Page Layout and Style

On HUAWEI DevEco Studio, create a project with Phone and Empty Feature Ability (Java) as the device type and template, respectively. Then create two Page abilities, BleCentralAbility and BlePeripheralAbility.

  1. In the ability_main.xml file, configure the buttons for accessing the central device page and peripheral device page, respectively. The sample code is as follows:
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:alignment="center" ohos:orientation="vertical"> <Button ohos:id="$+id:ble_central" ohos:height="50vp" ohos:width="match_parent" ohos:background_element="#33A1C9" ohos:layout_alignment="center" ohos:margin="20vp" ohos:text="Central device page" ohos:text_size="18fp"/> <Button ohos:id="$+id:ble_peripheral" ohos:height="50vp" ohos:width="match_parent" ohos:background_element="#33A1C9" ohos:layout_alignment="center" ohos:margin="20vp" ohos:text="Peripheral device page" ohos:text_size="18fp"/> </DirectionalLayout>
  2. Modify the ability_ble_central.xml file. On top of the page, draw a Text component to display the devices discovered in a scan, and draw a Button component on the right of the Text component for starting or stopping a scan. Below that Text component, draw another Text component to display whether the current device is connected to a peripheral device, and draw a Button component on the right of the Text component for connecting to or disconnecting from the device. In the third line on the page, draw a TextField component for inputting data, and draw a Button component on the right of the TextField component for sending data. The area at the bottom of this page displays the data received from the peripheral device. The sample code is as follows:
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:background_element="#F0FFFF" ohos:orientation="vertical"> <DirectionalLayout ohos:height="60vp" ohos:width="match_parent" ohos:orientation="horizontal"> <Text ohos:id="$+id:device_info" ohos:height="match_parent" ohos:width="0vp" ohos:margin="8vp" ohos:text="Device: none" ohos:text_alignment="left" ohos:text_size="18fp" ohos:weight="3"/> <Button ohos:id="$+id:scan" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="#33A1C9" ohos:margin="5vp" ohos:text="Start scanning" ohos:text_alignment="center" ohos:text_size="18fp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="60vp" ohos:width="match_parent" ohos:orientation="horizontal"> <Text ohos:id="$+id:status" ohos:height="match_parent" ohos:width="0vp" ohos:margin="8vp" ohos:text="Status: disconnected" ohos:text_alignment="left" ohos:text_size="18fp" ohos:weight="3"/> <Button ohos:id="$+id:connect" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="#33A1C9" ohos:margin="5vp" ohos:text="Connect" ohos:text_alignment="center" ohos:text_size="18fp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="60vp" ohos:width="match_parent" ohos:orientation="horizontal"> <TextField ohos:id="$+id:input" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="$graphic:textfield_element" ohos:hint="Enter" ohos:margin="8vp" ohos:text_alignment="vertical_center|left" ohos:text_size="18fp" ohos:weight="3"/> <Button ohos:id="$+id:send" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="#33A1C9" ohos:margin="5vp" ohos:text="Send data" ohos:text_alignment="center" ohos:text_size="18fp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="400vp" ohos:width="match_parent" ohos:background_element="#FFFFCD" ohos:margin="10vp" ohos:orientation="vertical"> <Text ohos:height="40vp" ohos:width="match_parent" ohos:text="Peripheral device:" ohos:text_size="18fp"/> <Text ohos:id="$+id:data" ohos:height="320vp" ohos:width="match_parent" ohos:text_alignment="top|left" ohos:text_size="18fp"/> </DirectionalLayout> </DirectionalLayout>
  3. Modify the ability_ble_peripheral.xml file. On top of the page, draw a Text component to display whether the current device is advertising or connected to the central device, and draw a Button component on the right of the Text component for starting or stopping advertising. In the second line, draw a TextField component for inputting data, and draw a Button component on the right of the TextField component for sending data. The area at the bottom of this page displays the data received from the central device. The sample code is as follows:
    <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:background_element="#F0FFFF" ohos:orientation="vertical"> <DirectionalLayout ohos:height="50vp" ohos:width="match_parent" ohos:orientation="horizontal"> <Text ohos:id="$+id:status" ohos:height="match_parent" ohos:width="0vp" ohos:margin="8vp" ohos:text="Status: not advertising" ohos:text_alignment="left" ohos:text_size="18fp" ohos:weight="3"/> <Button ohos:id="$+id:advertise" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="#33A1C9" ohos:margin="5vp" ohos:text="Start advertising" ohos:text_alignment="center" ohos:text_size="18fp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="50vp" ohos:width="match_parent" ohos:orientation="horizontal"> <TextField ohos:id="$+id:input" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="$graphic:textfield_element" ohos:hint="Enter" ohos:margin="8vp" ohos:text_alignment="vertical_center|left" ohos:text_size="18fp" ohos:weight="3"/> <Button ohos:id="$+id:send" ohos:height="match_parent" ohos:width="0vp" ohos:background_element="#33A1C9" ohos:margin="5vp" ohos:text="Send data" ohos:text_alignment="center" ohos:text_size="18fp" ohos:weight="1"/> </DirectionalLayout> <DirectionalLayout ohos:height="400vp" ohos:width="match_parent" ohos:background_element="#FFFFCD" ohos:margin="10vp" ohos:orientation="vertical"> <Text ohos:height="40vp" ohos:width="match_parent" ohos:text="Central device:" ohos:text_size="18fp"/> <Text ohos:id="$+id:data" ohos:height="320vp" ohos:width="match_parent" ohos:text_alignment="top|left" ohos:text_size="18fp"/> </DirectionalLayout> </DirectionalLayout>
  4. Create the textfield_element.xml file to define the background attributes of TextField. The sample code is as follows:
    <?xml version="1.0" encoding="utf-8"?> <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <corners ohos:radius="50"/> <solid ohos:color="#D1FCFF"/> </shape>

Writing the Service Logic

  1. Explicitly declare the sensitive permission ohos.permission.LOCATION in the MainAbility class. The sample code is as follows:
    public class MainAbility extends Ability { @Override public void onStart(Intent intent) { String[] permissions = {"ohos.permission.LOCATION"}; requestPermissionsFromUser(permissions, 0); super.onStart(intent); super.setMainRoute(MainAbilitySlice.class.getName()); } }
  2. In the MainAbilitySlice class, enable Bluetooth and redirection to the central device page and peripheral device page respectively upon a click on the corresponding button. The sample code is as follows:
    public class MainAbilitySlice extends AbilitySlice { // Replace " ABILITY_NAME" with the actual ability name in the project private static final String CENTRAL_ABILITY_NAME = "com.huawei.blebluetooth.BleCentralAbility"; private static final String PERIPHERAL_ABILITY_NAME = "com.huawei.blebluetooth.BlePeripheralAbility"; // Obtain the BluetoothHost instance for managing Bluetooth on the local device. private BluetoothHost bluetooth = BluetoothHost.getDefaultHost(this); @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initComponent(); if (bluetooth.getBtState() != BluetoothHost.STATE_ON) { bluetooth.enableBt(); } } private void initComponent() { findComponentById(ResourceTable.Id_ble_central).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withDeviceId("") .withBundleName(getBundleName()) .withAbilityName(CENTRAL_ABILITY_NAME) .build(); intent.setOperation(operation); startAbility(intent); } }); findComponentById(ResourceTable.Id_ble_peripheral).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder() .withDeviceId("") .withBundleName(getBundleName()) .withAbilityName(PERIPHERAL_ABILITY_NAME) .build(); intent.setOperation(operation); startAbility(intent); } }); } }
  3. In the BleCentralAbilitySlice class, implement functions such as starting and stopping a scan, connecting to and disconnecting from a device, and sending and receiving data. The sample code is as follows:
    public class BleCentralAbilitySlice extends AbilitySlice { private static final String SERVICE_UUID = "00001887-0000-1000-8000-00805f9b34fb"; private static final String NOTIFY_CHARACTER_UUID = "00002a10-0000-1000-8000-00805f9b34fb"; private static final String WRITE_CHARACTER_UUID = "00002a11-0000-1000-8000-00805f9b34fb"; private static final int CUT_LENGTH = 7; private BlePeripheralDevice peripheralDevice = null; private GattCharacteristic writeCharacteristic; private boolean isConnected = false; private boolean isScanning = false; private Text deviceText; private Text statusText; private TextField field; private Text dataText; private Button scanButton; private Button connectButton; private Button sendButton; /** * Implement the BlePeripheralCallback class. * * @since 2021-02-09 */ private class MyBlePeripheralCallback extends BlePeripheralCallback { // Called when services are discovered on the peripheral device. @Override public void servicesDiscoveredEvent(int status) { super.servicesDiscoveredEvent(status); if (status == BlePeripheralDevice.OPERATION_SUCC) { for (GattService service : peripheralDevice.getServices()) { checkGattCharacteristic(service); } } } private void checkGattCharacteristic(GattService service) { for (GattCharacteristic tmpChara : service.getCharacteristics()) { if (tmpChara.getUuid().equals(UUID.fromString(NOTIFY_CHARACTER_UUID))) { // Enable characteristic notifications. peripheralDevice.setNotifyCharacteristic(tmpChara, true); } if (tmpChara.getUuid().equals(UUID.fromString(WRITE_CHARACTER_UUID))) { // Obtain a GattCharacteristic instance. writeCharacteristic = tmpChara; } } } // Called when the connection state changes. @Override public void connectionStateChangeEvent(int connectionState) { super.connectionStateChangeEvent(connectionState); if (connectionState == ProfileBase.STATE_CONNECTED && !isConnected) { isConnected = true; // After a connection is set up, discover GATT services on the peripheral device. peripheralDevice.discoverServices(); updateComponent(statusText, "Status: connected"); } } // Called when a characteristic changes. @Override public void characteristicChangedEvent(GattCharacteristic characteristic) { super.characteristicChangedEvent(characteristic); // Receive the data sent by the peripheral device. updateComponent(dataText, new String(characteristic.getValue())); } } // Obtain a BlePeripheralCallback object. private MyBlePeripheralCallback blePeripheralCallback = new MyBlePeripheralCallback(); /** * Implement the BleCentralManagerCallback class. * * @since 2021-02-09 */ private class MyBleCentralManagerCallback implements BleCentralManagerCallback { // Called to send a notification of the scan result after a BLE scan is complete. @Override public void scanResultEvent(BleScanResult bleScanResult) { // Obtain the BlePeripheralDevice instance based on the scan result. if (peripheralDevice == null) { // Obtain service UUIDs. List<UUID> uuids = bleScanResult.getServiceUuids(); for (UUID uuid : uuids) { if (SERVICE_UUID.equals(uuid.toString())) { peripheralDevice = bleScanResult.getPeripheralDevice(); int length = peripheralDevice.toString().length(); String deviceId = peripheralDevice.toString().substring(length - CUT_LENGTH, length); updateComponent(deviceText, "Device:" + deviceId); } } } } // Called when the scan fails. @Override public void scanFailedEvent(int event) { updateComponent(deviceText, "Device: Scan failed. Please try again."); } // Called when a group of BLE scan results is reported. @Override public void groupScanResultsEvent(List<BleScanResult> list) { // You can define how to handle the scan results in this callback. } } // Obtain a BleCentralManagerCallback object. private MyBleCentralManagerCallback centralManagerCallback = new MyBleCentralManagerCallback(); // Obtain a BleCentralManager object. private BleCentralManager centralManager = new BleCentralManager(this, centralManagerCallback); // Create BLE scan filters. private List<BleScanFilter> filters = new ArrayList<>(); @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_ble_central); initComponent(); initClickedListener(); } // Initialize a component. private void initComponent() { if (findComponentById(ResourceTable.Id_device_info) instanceof Text) { deviceText = (Text) findComponentById(ResourceTable.Id_device_info); } if (findComponentById(ResourceTable.Id_status) instanceof Text) { statusText = (Text) findComponentById(ResourceTable.Id_status); } if (findComponentById(ResourceTable.Id_data) instanceof Text) { dataText = (Text) findComponentById(ResourceTable.Id_data); } if (findComponentById(ResourceTable.Id_input) instanceof TextField) { field = (TextField) findComponentById(ResourceTable.Id_input); } if (findComponentById(ResourceTable.Id_scan) instanceof Button) { scanButton = (Button) findComponentById(ResourceTable.Id_scan); } if (findComponentById(ResourceTable.Id_connect) instanceof Button) { connectButton = (Button) findComponentById(ResourceTable.Id_connect); } if (findComponentById(ResourceTable.Id_send) instanceof Button) { sendButton = (Button) findComponentById(ResourceTable.Id_send); } } private void updateComponent(Text text, String content) { getUITaskDispatcher().syncDispatch(new Runnable() { @Override public void run() { text.setText(content); } }); } private void startOrStopScan() { if (!isScanning) { isScanning = true; scanButton.setText("Stop scanning"); deviceText.setText("Device: scanning..."); // Start scanning for specified BLE devices with filters. centralManager.startScan(filters); } else { isScanning = false; scanButton.setText("Start scanning"); deviceText.setText("Device: none"); // Stop scanning. centralManager.stopScan(); } } // Initialize the click event listener. private void initClickedListener() { scanButton.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { startOrStopScan(); } }); connectButton.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (peripheralDevice == null) { statusText.setText("Status: scan to start obtaining device information"); return; } if (!isConnected) { connectButton.setText("Disconnect"); statusText.setText("Status: connecting..."; // Connect to the BLE peripheral device. peripheralDevice.connect(false, blePeripheralCallback); } else { isConnected = false; connectButton.setText("Connect"); statusText.setText("Status: disconnected"); deviceText.setText("Device: none"); writeCharacteristic.setValue("Disconnect".getBytes(StandardCharsets.UTF_8)); peripheralDevice.writeCharacteristic(writeCharacteristic); // Disconnect from the BLE peripheral device. peripheralDevice.disconnect(); peripheralDevice = null; } } }); sendButton.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (field.getText().isEmpty() || (peripheralDevice == null) || !isConnected) { return; } // Send data to the peripheral device. writeCharacteristic.setValue(field.getText().getBytes(StandardCharsets.UTF_8)); peripheralDevice.writeCharacteristic(writeCharacteristic); } }); } }
  4. In the BlePeripheralAbilitySlice class, implement functions such as starting and stopping advertising, and sending and receiving data. The sample code is as follows:
    public class BlePeripheralAbilitySlice extends AbilitySlice { private static final String SERVICE_UUID = "00001887-0000-1000-8000-00805f9b34fb"; private static final String NOTIFY_CHARACTER_UUID = "00002a10-0000-1000-8000-00805f9b34fb"; private static final String WRITE_CHARACTER_UUID = "00002a11-0000-1000-8000-00805f9b34fb"; private static final int GATT_CHARACTERISTIC_PERMISSIONS = 16; private BlePeripheralDevice peripheralDevice = null; private boolean isAdvertising = false; private boolean isConnected = false; private Text statusText; private TextField field; private Text dataText; private Button advertiseButton; private Button sendButton; /** * Implement the BlePeripheralManagerCallback class. * * @since 2021-02-09 */ private class MyBlePeripheralManagerCallback extends BlePeripheralManagerCallback { // Called when the connection state changes. @Override public void connectionStateChangeEvent( BlePeripheralDevice device, int interval, int latency, int timeout, int status) { if (status == BlePeripheralDevice.OPERATION_SUCC && !isConnected) { isConnected = true; peripheralDevice = device; updateComponent(statusText, "Status: connected"); } } // Called when the GATT client requests to write a characteristic. @Override public void receiveCharacteristicWriteEvent( BlePeripheralDevice device, int transId, GattCharacteristic characteristic, boolean isPrep, boolean needRsp, int offset, byte[] value) { if (Arrays.equals("Disconnect".getBytes(StandardCharsets.UTF_8), value)) { isConnected = false; peripheralDevice = null; updateComponent(statusText, "Status: advertising and waiting to be connected"); return; } // Obtain the data written by the central device. updateComponent(dataText, new String(value, Charset.defaultCharset())); } } // Obtain a BlePeripheralManagerCallback object. private MyBlePeripheralManagerCallback peripheralManagerCallback = new MyBlePeripheralManagerCallback(); // Obtain a BlePeripheralManager object. private BlePeripheralManager blePeripheralManager = new BlePeripheralManager(this, peripheralManagerCallback, 1); // Create a GattService object with a specified UUID. private GattService gattService = new GattService(UUID.fromString(SERVICE_UUID), true); // Create a GattCharacteristic object to send data to the central device. private GattCharacteristic notifyCharacteristic = new GattCharacteristic( UUID.fromString(NOTIFY_CHARACTER_UUID), 1 | GATT_CHARACTERISTIC_PERMISSIONS, GattCharacteristic.PROPERTY_READ | GattCharacteristic.PROPERTY_WRITE | GattCharacteristic.PROPERTY_WRITE_NO_RESPONSE); // Create another GattCharacteristic object to send data to the central device. private GattCharacteristic writeCharacteristic = new GattCharacteristic( UUID.fromString(WRITE_CHARACTER_UUID), 1 | GATT_CHARACTERISTIC_PERMISSIONS, GattCharacteristic.PROPERTY_READ | GattCharacteristic.PROPERTY_WRITE | GattCharacteristic.PROPERTY_WRITE_NO_RESPONSE); /** * Implement the BleAdvertiseCallback class. * * @since 2021-02-09 */ private class MyBleAdvertiseCallback extends BleAdvertiseCallback { // Called when BLE advertising is started. @Override public void startResultEvent(int result) { if (result == BleAdvertiseCallback.RESULT_SUCC) { // Add one or more characteristics to the GattService object. gattService.addCharacteristic(notifyCharacteristic); gattService.addCharacteristic(writeCharacteristic); // Clear all services. blePeripheralManager.clearServices(); // Add the GattService object to the BlePeripheralManager object. blePeripheralManager.addService(gattService); } } } // Build a BleAdvertiseData object. private BleAdvertiseData advertiseData = new BleAdvertiseData.Builder() .addServiceData(SequenceUuid.uuidFromString(SERVICE_UUID), "12".getBytes(StandardCharsets.UTF_8)) .addServiceUuid(SequenceUuid.uuidFromString(SERVICE_UUID)) .build(); // Build a BleAdvertiseSettings object. private BleAdvertiseSettings advertiseSettings = new BleAdvertiseSettings.Builder() .setConnectable(true) .setInterval(BleAdvertiseSettings.INTERVAL_SLOT_MIN) .setTxPower(BleAdvertiseSettings.TX_POWER_MAX) .build(); // Obtain a BleAdvertiseCallback object. private MyBleAdvertiseCallback advertiseCallback = new MyBleAdvertiseCallback(); // Obtain a BleAdvertiser object. private BleAdvertiser advertiser = new BleAdvertiser(this, advertiseCallback); @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_ble_peripheral); initComponent(); initClickedListener(); } // Initialize a component. private void initComponent() { if (findComponentById(ResourceTable.Id_status) instanceof Text) { statusText = (Text) findComponentById(ResourceTable.Id_status); } if (findComponentById(ResourceTable.Id_data) instanceof Text) { dataText = (Text) findComponentById(ResourceTable.Id_data); } if (findComponentById(ResourceTable.Id_input) instanceof TextField) { field = (TextField) findComponentById(ResourceTable.Id_input); } if (findComponentById(ResourceTable.Id_advertise) instanceof Button) { advertiseButton = (Button) findComponentById(ResourceTable.Id_advertise); } if (findComponentById(ResourceTable.Id_send) instanceof Button) { sendButton = (Button) findComponentById(ResourceTable.Id_send); } } // Initialize the click event listener. private void initClickedListener() { advertiseButton.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (!isAdvertising) { advertiseButton.setText("Stop advertising"); statusText.setText("Status: advertising and waiting to be connected"); // Start BLE advertising. advertiser.startAdvertising(advertiseSettings, advertiseData, null); isAdvertising = true; } else { advertiseButton.setText("Start advertising"); statusText.setText("Status: advertising stopped"); // Stop BLE advertising. advertiser.stopAdvertising(); isAdvertising = false; } } }); sendButton.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (field.getText().isEmpty() || (blePeripheralManager == null) || !isConnected) { return; } // Send data to the central device. notifyCharacteristic.setValue(field.getText().getBytes(StandardCharsets.UTF_8)); blePeripheralManager.notifyCharacteristicChanged(peripheralDevice, notifyCharacteristic, false); } }); } private void updateComponent(Text text, String content) { getUITaskDispatcher().syncDispatch(new Runnable() { @Override public void run() { text.setText(content); } }); } }
Code copied