Android BLE basic operation framework, based on callback, simple operation. Includes scanning, multiple connections, broadcast packet resolution, service read and write, and notification functions.

  • Project address: github.com/xiaoyaoyou1…

  • Project relies on: the compile ‘com. Press vise. Xiaoyaoyou: baseble: 2.0.0’

function

  • Support multi-device connection management;

  • Support broadcast packet parsing;

  • Supports user-defined scan filtering conditions.

  • Scanning devices can be filtered by device names using regular expressions.

  • Filter scanning devices based on the minimum device signal value.

  • Filter scanning devices by device name or MAC address list.

  • Filter and scan devices based on device UUID.

  • You can search for a specified device by device name or MAC address.

  • Retry after device connection failure.

  • Retry after device data operations fail.

  • Data sending and receiving channels can be bound. Multiple channels can be bound to the same capability.

  • Support for registration and unnotification listening;

  • The maximum number of connections can be configured. When the maximum number of connections is exceeded, the device that has not been used for a long time is automatically disconnected based on the Lru algorithm.

  • Supports setting timeout periods for scanning, connection, and operation data.

  • You can set the retry times and retry interval for connection and operation data.

Introduction to the

The library is designed to simplify the process of accessing Bluetooth devices. The library is the basic framework of BLE operation. It only deals with BLE device communication logic and does not include specific data processing, such as data subcontracting and packet grouping. The library provides multi-device connection management, configurable maximum number of connections, and automatically disconnects the most recent unused device based on the Lru algorithm when the maximum number of connections is exceeded. The library also customizes common scanning device filtering rules and supports custom filtering rules. All operations in the library use callback mechanism to inform the upper layer of the call results, simple operation, convenient access.

Results show

BLE effect

Used to introduce

Access configuration

6.0 No permissions are required for the following systems. The following permissions have been configured in the library:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>Copy the code

If the mobile phone system is 6.0 or higher, you need to configure the following permissions:

<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>Copy the code

Since bluetooth above 6.0 uses the fuzzy location function, you need to add the fuzzy location permission.

The introduction of the SDK

Add the following dependencies to the dependencies in the build.gradle file of the project Module:

compile 'com. Press vise. Xiaoyaoyou: baseble: 2.0.0'Copy the code

Once built, you can use the library’s functionality directly.

Initialize the

The library needs to be initialized before it can be used. The initialization code is as follows:

Viseb.config ().setscantimeout (-1) SetConnectTimeout (10 x 1000)// Connection timeout time. setOperateTimeout(5 x 1000)// Set the data operation timeout time SetConnectRetryCount (3)// Sets the number of retry times for connection failures. SetConnectRetryInterval (1000)// Sets the interval for retry times for connection failures. SetOperateRetryCount (3)// Sets the number of retry times for data operation failures .setOperateretryInterval (1000)// Set the retry interval for data operations. SetMaxConnectCount (3); // Set the maximum number of connected devices // Bluetooth message initialization, globally unique, must be called viseb.getInstance ().init(this);Copy the code

The initialization can be done in the Application or MainActivity, as long as it is done before using Bluetooth. Note that the Bluetooth configuration must be modified before bluetooth initialization. If the default configuration meets the requirements, the configuration may not be modified.

Scanning equipment

The library defines several common filtering rules for device scanning. If you do not meet the requirements, you can also define your own filtering rules. The following describes how to use the filtering rules provided in the library:

  • Scanning all devices

    ViseBle.getInstance().startScan(new ScanCallback(new IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {}}));Copy the code
  • Scans the MAC address of the specified device

    Viseb.getinstance ().startscan (new SingleFilterScanCallback(new)IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {
    
      }
    }).setDeviceMac(deviceMac));Copy the code
  • Scans the specified device name

    Viseb.getinstance ().startscan (new SingleFilterScanCallback(new)IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {
    
      }
    }).setDeviceName(deviceName));Copy the code
  • Scans devices with a specified UUID

    ViseBle.getInstance().startScan(new UuidFilterScanCallback(new IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {
    
      }
    }).setUuid(uuid));Copy the code
  • Scans devices with a specified MAC address or name set

    ViseBle.getInstance().startScan(new ListFilterScanCallback(new IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {
    
      }
    }).setDeviceMacList(deviceMacList).setDeviceNameList(deviceNameList));Copy the code
  • Scans devices with a specified signal range or device canonical name

    ViseBle.getInstance().startScan(new RegularFilterScanCallback(new IScanCallback() {
      @Override
      public void onDeviceFound(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanFinish(BluetoothLeDeviceStore bluetoothLeDeviceStore) {
    
      }
    
      @Override
      public void onScanTimeout() {
    
      }
    }).setDeviceRssi(rssi).setRegularDeviceName(regularDeviceName));Copy the code

The scanned device list is managed by BluetoothLeDevice core, and the single device information is unified in BluetoothLeDevice, which contains all the information of the device, such as device name, device address, broadcast packet resolution information, etc. The device information is described in device details.

Device to connect

There are three methods for device connection. One is to connect to the device directly based on the device information. The other two methods are to connect to the device directly based on the device name or MAC address without scanning. The three connection modes are as follows:

  • Connect the device based on the device information

    ViseBle.getInstance().connect(bluetoothLeDevice, new IConnectCallback() {
      @Override
      public void onConnectSuccess(DeviceMirror deviceMirror) {
    
      }
    
      @Override
      public void onConnectFailure(BleException exception) {
    
      }
    
      @Override
      public void onDisconnect(boolean isActive) {
    
      }
    });Copy the code
  • Scan and connect based on the MAC address of the device

    ViseBle.getInstance().connectByMac(deviceMac, new IConnectCallback() {
      @Override
      public void onConnectSuccess(DeviceMirror deviceMirror) {
    
      }
    
      @Override
      public void onConnectFailure(BleException exception) {
    
      }
    
      @Override
      public void onDisconnect(boolean isActive) {
    
      }
    });Copy the code
  • Scan and connect directly according to the device name

    ViseBle.getInstance().connectByName(deviceName, new IConnectCallback() {
      @Override
      public void onConnectSuccess(DeviceMirror deviceMirror) {
    
      }
    
      @Override
      public void onConnectFailure(BleException exception) {
    
      }
    
      @Override
      public void onDisconnect(boolean isActive) {
    
      }
    });Copy the code

Equipment details

DEVICE INFO

  • Get Device Name:bluetoothLeDevice.getName();
  • Obtain Device Address:bluetoothLeDevice.getAddress();
  • Get Device Class:bluetoothLeDevice.getBluetoothDeviceClassName();
  • Get Major device classes:bluetoothLeDevice.getBluetoothDeviceMajorClassName();
  • Get Service Class:bluetoothLeDevice.getBluetoothDeviceKnownSupportedServices();
  • Obtain the Bonding State:bluetoothLeDevice.getBluetoothDeviceBondState();

RSSI INFO

  • Obtain the First Timestamp:bluetoothLeDevice.getFirstTimestamp();
  • Obtain the First RSSI:bluetoothLeDevice.getFirstRssi();
  • Obtain the Last signal Timestamp (Last Timestamp):bluetoothLeDevice.getTimestamp();
  • Obtain the Last RSSI:bluetoothLeDevice.getRssi();
  • Obtain the Running Average RSSI:bluetoothLeDevice.getRunningAverageRssi();

SCAN RECORD INFO

Get the type number of a broadcast data unit AdRecord according to the broadcast packet AdRecordStore. Record.gettype () Again according to the serial number for a type description of the broadcasting data unit record. GetHumanReadableType () and the length of the broadcast data unit and data content, Finally through AdRecordUtil. GetRecordDataAsString (record) to convert the data content to specific string. For more information on broadcast packet parsing, see the Data Parsing section of the Android BLE Study Notes.

To send data

Before sending data, bind the write data channel and set the callback listening for the write data at the same time. The code example is as follows:

BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
        .setBluetoothGatt(deviceMirror.getBluetoothGatt())
        .setPropertyType(PropertyType.PROPERTY_WRITE)
        .setServiceUUID(serviceUUID)
        .setCharacteristicUUID(characteristicUUID)
        .setDescriptorUUID(descriptorUUID)
        .builder();
deviceMirror.bindChannel(new IBleCallback() {
    @Override
    public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {

    }

    @Override
    public void onFailure(BleException exception) {

    }
}, bluetoothGattChannel);
deviceMirror.writeData(data);Copy the code

In this case, deviceMirror can be obtained after the device is successfully connected. It should be noted that the channel for writing data only needs to be registered once when the service is the same. If there are multiple channels for writing data, multiple channels can be bound. Write data must be written after binding the write channel, and can be written multiple times in different places.

Receive data

Like sending data, the data sent by the receiving device also needs to be bound to the receiving data channel. There are two ways, one is notifiable and the other is indicator, which are used as follows:

  • Notifiable mode

    BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
          .setBluetoothGatt(deviceMirror.getBluetoothGatt())
          .setPropertyType(PropertyType.PROPERTY_NOTIFY)
          .setServiceUUID(serviceUUID)
          .setCharacteristicUUID(characteristicUUID)
          .setDescriptorUUID(descriptorUUID)
          .builder();
    deviceMirror.bindChannel(new IBleCallback() {
      @Override
      public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {
    
      }
    
      @Override
      public void onFailure(BleException exception) {
    
      }
    }, bluetoothGattChannel);
    deviceMirror.registerNotify(false);Copy the code
  • Indicator mode

    BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
          .setBluetoothGatt(deviceMirror.getBluetoothGatt())
          .setPropertyType(PropertyType.PROPERTY_INDICATE)
          .setServiceUUID(serviceUUID)
          .setCharacteristicUUID(characteristicUUID)
          .setDescriptorUUID(descriptorUUID)
          .builder();
    deviceMirror.bindChannel(new IBleCallback() {
      @Override
      public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {
    
      }
    
      @Override
      public void onFailure(BleException exception) {
    
      }
    }, bluetoothGattChannel);
    deviceMirror.registerNotify(true);Copy the code

    You need to register notification after binding the channel, and you need to set up the listener by calling the following code when you receive a successful callback:

    deviceMirror.setNotifyListener(bluetoothGattInfo.getGattInfoKey(), new IBleCallback() {
      @Override
      public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {
    
      }
    
      @Override
      public void onFailure(BleException exception) {
    
      }
    });Copy the code

    All data sent from the device will be obtained through the above listener. If you do not want to listen, you can also cancel the registration, using the following method:

    deviceMirror.unregisterNotify(isIndicate);Copy the code

    IsIndicate Indicates whether it is an indicator.

Read the data

As the channel of reading device information is basically different every time, so here is a little different from the above data sending and receiving, each time reading data needs to bind a channel, as shown in the following example:

BluetoothGattChannel bluetoothGattChannel = new BluetoothGattChannel.Builder()
        .setBluetoothGatt(deviceMirror.getBluetoothGatt())
        .setPropertyType(PropertyType.PROPERTY_READ)
        .setServiceUUID(serviceUUID)
        .setCharacteristicUUID(characteristicUUID)
        .setDescriptorUUID(descriptorUUID)
        .builder();
deviceMirror.bindChannel(new IBleCallback() {
    @Override
    public void onSuccess(byte[] data, BluetoothGattChannel bluetoothGattChannel, BluetoothLeDevice bluetoothLeDevice) {

    }

    @Override
    public void onFailure(BleException exception) {

    }
}, bluetoothGattChannel);
deviceMirror.readData();Copy the code

conclusion

As can be seen from the above description, all device-related operations are handled by ViseBle in a unified manner. In addition, ViseBle is a singleton mode, and there is only one global class, making it easy to manage. To use the functionality provided by the library, you must call viseb.getInstance ().init(context); Initialize. A device image is added to the device mirror pool for each device that is successfully connected. The device image is the core class for all operations performed after the device is successfully connected. The device image is removed from the mirror pool when the device is disconnected. Then the device mirroring pool automatically removes and disconnects the latest and longest unused devices based on the Lru algorithm. ViseBle encapsulates several commonly used apis, such as start scan and stop scan, connect and disconnect, and clean up resources. The library provides functionality that is as simple as possible, which is the purpose of the project.