Android蓝牙SDK文档

SDK流程示意图

Demo

https://github.com/iKangtai/ScBluetoothSdkDemo_Android.git

国际化

English | 中文文档

接入指南

SDK功能

功能项 功能描述
扫描附近蓝牙设备 扫描手机附近的蓝牙设备,每秒刷新一次设备列表
连接孕橙体温计同步数据     连接体温计同步数据,设置体温计温度单位、时间,获取固件版本号
连接孕橙额温枪同步数据   连接额温枪同步数据,获取固件版本号
连接Shecare胎心仪同步数据   连接胎心仪同步数据并获取固件版本号
连接Shecare体温贴同步数据   连接体温贴同步数据并获取固件版本号

集成SDK

1.第一种方式
在工程build.gradle配置脚本中buildscript和allprojects段中添加蓝牙SDK新maven仓库地址:

1
maven { url 'https://dl.bintray.com/ikangtaijcenter123/ikangtai' }

在工程App 对应build.gradle配置脚本dependencies段中添加统计SDK库依赖:

1
implementation 'com.ikangtai.buletoothsdk:ScBuletoothLib:1.1.6'

2.第二种方式,将SDK aar文件复制到项目的app/libs/目录,然后配置gradle

1
2
3
4
5
6
7
8
9
10
11
android {
repositories {
flatDir {
dirs 'libs'
}
}
}

dependencies {
implementation(name: 'scbluetoothlib-release-v1.1.6', ext: 'aar')
}

3.第三种方式,将Demo的ScBluetoothLib模块配置复制到项目中,然后添加实现项目(’:ScBluetoothLib’)来建立依赖关系

权限授予

SDK需要宿主APP授予如下权限:

权限 用途
BLUETOOTH 连接蓝牙设备所需权限
BLUETOOTH_ADMIN 连接蓝牙设备所需权限
ACCESS_COARSE_LOCATION     Android 7.0从安全和功耗的角度出发,BLE扫描跟定位权限绑在一起
ACCESS_FINE_LOCATION Android 7.0从安全和功耗的角度出发,BLE扫描跟定位权限绑在一起
READ_EXTERNAL_STORAGE 读写日志文件
WRITE_EXTERNAL_STORAGE 读写日志文件

下面给出AndroidManifest.xml清单文件示例:

1
2
3
4
5
6
7
8
<manifest ……>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application ……>

初始化SDK

使用SDK之前,需要在宿主应用UI线程中调用初始化函数,后面相关回调函数也都会在UI线程:

1
ScPeripheralManager.getInstance().init(getContext());

扫描附近蓝牙设备

扫描方法是一个持续的过程,每秒返回一次最新设备列表,需要在扫描完成后手动调用scPeripheralManager.stopScan()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    if (!checkBleFeatures()) {
return;
}
scPeripheralManager.startScan(new ScanResultListener() {
/**
* 扫描附近的设备时,通过此方法调用设备列表。
* 该方法调用将每秒触发一次,直到调用stopScanDevice方法为止。
* @param deviceList
*/
public void onScannerResult(List<ScPeripheral> deviceList) {

}
});
```

在开始扫描之前,需要检查6.0以上的定位服务开关,6.0以上的系统的定位权限以及蓝牙开关,具体实现方法可以看Demo中checkBleFeatures()
```java
private boolean checkBleFeatures() {
//Check Bluetooth Location Service
if (!BleTools.isLocationEnable(getContext())) {
Intent locationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(locationIntent, REQUEST_LOCATION_SETTINGS);
return false;
}
//Check Bluetooth location permission
if (!BleTools.checkBlePermission(getContext())) {
XXPermissions.with(getActivity())
.permission(Permission.Group.LOCATION)
.request(callback);
return false;
}
//Check the Bluetooth switch
if (!BleTools.checkBleEnable()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_BLE_SETTINGS_CODE);
return false;
}
return true;
}

连接蓝牙设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
ReceiveDataListenerAdapter receiveDataListenerAdapter = new ReceiveDataListenerAdapter() {
/**
*
* @param macAddress
* @param 扫描到设备列表,每秒返回一次最新设备列表
*/
public void onReceiveData(String macAddress, List<ScPeripheralData> scPeripheralDataList) {
appendConsoleContent("New data received " + macAddress);
}
/**
* 连接的设备发生错误时回调方法.
*
* @param macAddress
* @param code errorCode ,see{@link com.ikangtai.bluetoothsdk.util.BleCode}
* @param msg errorMsg
*/
public void onReceiveError(String macAddress, int code, String msg) {
LogUtils.d("onReceiveError:" + code + " " + msg);
}

/**
* 当连接设备的状态更改时,将调用此方法。
*
* @param macAddress
* @param state connect state
*/
public void onConnectionStateChange(String macAddress, int state) {
if (state == BluetoothProfile.STATE_CONNECTED) {

} else if (state == BluetoothProfile.STATE_DISCONNECTED) {

}
}

/**
*
* @param macAddress
* @param 指令类型,type see {@link com.ikangtai.bluetoothsdk.BleCommand}
* @param 结果执行命令返回的状态将返回true或false。
* @param 通过执行命令返回的结果值。
*/
public void onReceiveCommandData(String macAddress, int type, boolean state, String value) {
LogUtils.d("onReceiveCommandData:" + type + " " + state + " " + value);
}

/**
*
* @param macAddress
* @param 指令类型,type see {@link com.ikangtai.bluetoothsdk.BleCommand}
* @param 执行命令返回的状态将返回true或false。
* @param 执行命令返回的结果值byte [] data,目前来自胎心仪监测的数据流。
*/
public void onReceiveCommandData(String macAddress, int type, boolean state, byte[] value) {
LogUtils.d("onReceiveCommandData:" + type + " " + resultCode + " " + BleUtils.byte2hex(value));
}
};
scPeripheralManager.connectPeripheral(macAddress, receiveDataListenerAdapter);

使用完毕手动断开连接释放资源

1
2
scPeripheralManager.stopScan();
scPeripheralManager.disconnectPeripheral();

与设备交互

指令通过scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand)方式调用,会在ReceiveDataListener.onReceiveCommandData(String macAddress, int type, boolean state, String value)收到发送指令结果。

获取设备体温数据

1
scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand.GET_DEVICE_DATA);

同步系统时间给设备

1
scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand.SYNC_TIME);

修改设备温度摄氏度单位

1
scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand.SYNC_THERMOMETER_UNIT_C);

修改设备温度华氏度单位

1
scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand.SYNC_THERMOMETER_UNIT_F);

SDK支持的指令列表:

类型 描述
SEND_TEMP_ACK = -1 发送接收到的温度指令数,外部不可用(SDK内部已处理)
SYNC_THERMOMETER_UNIT_C = 0      温度计单位设置为摄氏度(已废弃)
SYNC_THERMOMETER_UNIT_F = 1 温度计单位设置为华氏度(已废弃)
SYNC_TIME = 2 将系统时间与温度计同步
GET_TIME = 3 获取温度计时间
GET_POWER = 4 获取温度计电量
GET_FIRMWARE_VERSION = 5 获取温度计的固件版本号
GET_DEVICE_DATA = 6 在温度计中获取数据(只能获取一次)
GET_EWQ_FIRMWARE_VERSION = 7 获取额温枪的版本号
GET_THERMOMETER_UNIT = 8 获取温度计单位
SET_THERMOMETER_MODE = 9 设定温度计测温模式
GET_THERMOMETER_MODE = 10 获取温度计测温模式
GET_THERMOMETER_MEASURE_TIME = 11 获取温度计的温度测量时间
SET_THERMOMETER_MEASURE_TIME1 = 12 设置温度计的温度测量时间1
SET_THERMOMETER_MEASURE_TIME2 = 13 设置温度计的温度测量时间2
CLEAR_THERMOMETER_DATA = 14 清除温度计数据
GET_DEVICE_HISTORY_DATA = 15 获取体温计的历史数据
SEND_HISTORY_DATA_ACK = 16 发送临床体温计确认的历史数据,外部不可用(SDK内部已处理)
SYNC_THERMOMETER_UNIT = 17 同步温度计单位
THERMOMETER_OTA_UPGRADE = 18 设备ota升级
GET_THERMOMETER_OAD_IMG_TYPE = 19 获取设备oad img类型
THERMOMETER_OAD_UPGRADE = 20 设备oad升级
IFEVER_DEVICE_VERIFY = 21 IFEVER设备安全验证

温度计支持以下指令集:

1
{SEND_TEMP_ACK, SYNC_THERMOMETER_UNIT_C, SYNC_THERMOMETER_UNIT_F, SYNC_TIME, GET_FIRMWARE_VERSION, GET_DEVICE_DATA, SYNC_THERMOMETER_UNIT, GET_POWER, GET_THERMOMETER_OAD_IMG_TYPE, THERMOMETER_OAD_UPGRADE};

额温枪支持以下指令集:

1
{GET_EWQ_FIRMWARE_VERSION, GET_EWQ_DEVICE_DATA}

安康源三代温度计支持以下指令集:

1
{SEND_TEMP_ACK, SYNC_TIME, GET_TIME, GET_FIRMWARE_VERSION, GET_DEVICE_DATA, SET_THERMOMETER_MODE, GET_THERMOMETER_MODE, GET_THERMOMETER_MEASURE_TIME, SET_THERMOMETER_MEASURE_TIME1, SET_THERMOMETER_MEASURE_TIME2, CLEAR_THERMOMETER_DATA, GET_DEVICE_HISTORY_DATA, SYNC_THERMOMETER_UNIT, GET_THERMOMETER_UNIT, GET_POWER,THERMOMETER_OTA_UPGRADE};

安康源四代温度计支持以下指令集:

1
{SEND_TEMP_ACK, SYNC_TIME, GET_TIME, GET_FIRMWARE_VERSION, GET_DEVICE_DATA, GET_THERMOMETER_MEASURE_TIME, SET_THERMOMETER_MEASURE_TIME1, SET_THERMOMETER_MEASURE_TIME2, CLEAR_THERMOMETER_DATA, GET_DEVICE_HISTORY_DATA, SYNC_THERMOMETER_UNIT, GET_THERMOMETER_UNIT, GET_POWER, THERMOMETER_OTA_UPGRADE};

胎心仪支持以下指令集:
{}
体温贴支持以下指令集:

1
{SYNC_TIME, GET_FIRMWARE_VERSION, GET_DEVICE_DATA, GET_POWER, IFEVER_DEVICE_VERIFY};

混淆配置

如果您的应用使用了代码混淆,请添加如下配置,以避免SDK被错误混淆导致SDK不可用。

1
2
-dontwarn  com.ikangtai.bluetoothsdk.**
-keep class com.ikangtai.bluetoothsdk.** {*;}

查看日志

可以通过调用如下方法控制SDK运行调试日志是否输出、输出路径,默认情况下SDK运行调试日志打开。用户可以手动关闭。
也可以通过Locat过滤”sc-ble-log”Tag显示SDK特定日志。

1
2
3
4
5
6
7
8
9
/**
* 配置Log文件路径
* 1. {@link Config.Builder#logWriter(Writer)}
* 2. {@link Config.Builder#logFilePath(String)}
*/
LogUtils.LOG_SWITCH=true;
Config config = new Config.Builder().logWriter(logWriter).build();
//Config config = new Config.Builder().logFilePath(logFilePath).build();
scPeripheralManager.init(getContext(), config);

错误码说明

每次调用SDK接口时,可能获得正确或错误的返回码,开发者可以根据返回码信息调试接口,排查错误。

返回码 说明
-1      未知错误,sdk内部无法处理错误
-2 macAddress错误
-3 系统定位开关未打开
-4 App缺少定位权限
-5 蓝牙未打开
-6 设备当前不支持此命令
-7 当前设备未连接
-8 当前连接设备数量超过上限(最多5个)

常见问题

  • 为什么连接体温计后,没有发送SYNC_DATA指令,也会收到onReceveData回调

    SDK内部在连接体温计成功后,会主动通过”SYNC_DATA指令”获取一次离线数据,通过onReceveData回调,并且在获取数据结束后通过”SYNC_TIME指令”给体温计同步系统时间

  • SDK指令调用时序

    当体温计未连接时,发送指令会直接返回错误码。当在连接过程中发送指令,会在连接成功后调用指令队列中的指令。SDK每次处理一条指令,同时发送多条相同指令,SDK只执行一次。同时发送多条不同指令,SDK会存到指令队列中,依次执行。

  • ACK指令含义

    当收到温度数据时,SDK需要回复体温计这个”SYNC_ACK指令”,并带上当前收到的条数。当同步的温度数据大于10时,会分成10条数据一组。正常是SDK内部处理这条指令,不需要额外处理。SDK发送这条指令,可能造成收到重复的温度数据。
    如果你非常想自己在外部调用ACK指令,需要修改Config,new Config.Builder().forceOutsideSendAck(true),然后调用scPeripheralManager.sendPeripheralCommand(macAddress, BleCommand.SEND_TEMP_ACK, scPeripheralDataList.size());

  • SDK操作需要在UI线程

    目前SDK向外回调数据时,会主动切到UI线程

  • 设置温度单位失败,同步时间失败

    发送指令失败一般是出现体温计还未连接,或者连接不稳定的情况出现,建议查看SDK日志输出排查问题

  • 体温计始终同步重复温度数据

    体温计内有异常的温度数据,造成SDK处理温度条数出现错误Case,可以联系SDK提供方携带,注意携带日志文件。

    SDK介绍

ScPeripheralManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class ScPeripheralManager {

/**
* 开始扫描附近的设备,并通过这个方法返回 {@link ScanResultListener#onScannerResult(List)}.
* 该方法调用将每秒触发一次,直到调用{@link #stopScan()}方法为止。
*
* @param scanResultListener
*/
public void startScan(ScanResultListener scanResultListener) {
BleManager.getInstance().startScanAllDevice(scanResultListener);
}

/**
* 停止扫描设备
*/
public void stopScan() {
BleManager.getInstance().stopScanDevice();
}

/**
* 将listener添加到将在设备连接期间发送事件的一组侦听器。
* 当您想断开设备的连接时,需要主动调用{@link ScPeripheralManager#removeReceiveDataListener(ReceiveDataListener)}
*
* @param receiveDataListener将被添加到{@link com.ikangtai.bluetoothsdk.BleManager}的当前侦听器集中的侦听器。
*/
public void addReceiveDataListener(ReceiveDataListener receiveDataListener) {
BleManager.getInstance().addReceiveDataListener(receiveDataListener);
}

/**
* 从集合中删除一个listener,监听{@link com.ikangtai.bluetoothsdk.BleManager}的数据更新。
*
* @param receiveDataListener listener将从{@link com.ikangtai.bluetoothsdk.BleManager}的当前更新监听器集中删除。
*
*/
public void removeReceiveDataListener(ReceiveDataListener receiveDataListener) {
BleManager.getInstance().removeReceiveDataListener(receiveDataListener);
}

/**
* 连接设备,需要设置全局Listener{@link #addReceiveDataListener(ReceiveDataListener)}接收数据更新。
*
* @param macAddress
*/
public void connectPeripheral(String macAddress) {
BleManager.getInstance().startConnectDevice(macAddress, null);
}

/**
* 连接设备,将侦听器添加到侦听器集
* 接收{@link com.ikangtai.bluetoothsdk.BleManager}数据更新事件。
*
* @param macAddress
* @param receiveDataListener
*/

public void connectPeripheral(String macAddress, ReceiveDataListener receiveDataListener) {
BleManager.getInstance().startConnectDevice(macAddress, receiveDataListener);
}

/**
* 发送指令
*
* @param type
*/
public void sendPeripheraleCommand(String macAddress, int type) {
BleManager.getInstance().sendDeviceCommand(macAddress, type);
}

/**
* 获取设备连接状态
*
* @param macAddress
* @return either one of state {@link android.bluetooth.BluetoothProfile }
*/
public int getConnectState(String macAddress) {
return BleManager.getInstance().getConnectState(macAddress);
}

/**
* 断开设备连接
*
* @param macAddress
*/
public void disconnectPeripheral(String macAddress) {
BleManager.getInstance().disconnect(macAddress);
}

public void disconnectPeripheral(String macAddress, ReceiveDataListener receiveDataListener) {
BleManager.getInstance().disconnect(macAddress, receiveDataListener);
}

/**
* 断开所有的设备
*/
public void disconnectPeripheral() {
BleManager.getInstance().disconnect();
}
}