蓝牙4.0分为标准蓝牙和低功耗蓝牙(BLE),标准蓝牙就是手机上常用的那种,低功能耗蓝牙由于其具有最大化的待机时间、快速连接和低峰值的发送和接收特性,被广泛用于智能手表、智能手环等可穿戴设备上。
标准蓝牙的的开发和BLE不同。标准蓝牙连接里有两个角色一个是客户端一个是服务器,当客户端搜索到蓝牙服务器后并与之配对后,才能通过UUID(这个是唯一的,服务器端必须与客户端一致)建立socket,然后使用流像文件读写和网络通信那样传输数据就行了。在BLE里,变成了中心设备(central)和外围设备(peripheral),中心设备就是你的手机,外围设备就是智能手环一类的东西。开发BLE的应用都得遵守Generic Attribute Profile (GATT),一个BLE蓝牙设备包含多个service,每个service又包含多个characteristic。每个characteristic有一个value和多个descriptor,通过characteristic中心设备与外围设备进行通信。descriptor顾名思义,包含了BLE设备的一些信息。不同service、characteristic和descriptor都有各自己唯一的UUID。想要跟BLE设备通信,首先通过UUID获取目标服务,然后再通过UUID获取characteristic,charateristic起着载体的作用,通过writeCharacteristic()和readCharacteristic(),可以写入和读出信息。每个characteristic都有一些自己的属性,其中在property里,说明了该characteristic的属性,例如READ|WRITE|WRITE_NO_RESPONSE|NOTIFY。
在android 4.3中,谷歌发布了官方的BLE开发的API,而在android 5.0后引入了新的API。所以在开发的时候,需要注意版本的兼容性。例如,minSdkVersion =13,targetSdkVersion = 19,而编译环境compileSdkVersion 22,如果直接用4.3 API中提供的方法,会无法编译,原因是minSdkVersion的版本低于18,其次,compileSdkVersion 大于21。针对这些问题,接下来,我会详细说明BLE的开发。
1、权限
在AndroidManifest.xml里加入
<!-- 允许程序连接到已配对的蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 允许程序发现和配对蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
还需要
<!-- BLE需要 Android 5.0以前的权限-->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
<!-- BLE需要 Android 5.0之后的权限-->
<uses-feature android:name="android.bluetooth.le" android:required="false"/>
其中,required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
...
}
2、版本的兼容性问题
用@TargetApi注解的方式
因为BLE的API需要基于android 18以上,所以需要
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class TestActivity extends BaseActivity {
又由于android 21的API不一样,如果在android 22的编译环境中使用旧的API,这样编译的API运行之后,调用旧的API方法是不会执行本应该实现的方法。所以需要判断版本。例如:
private void initCallBack(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
initScanCallBack();
}else{
initLeScanCallBack();
}
}
3、获取BluetoothAdapter
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
//启动蓝牙
mBluetoothAdapter.enable();
4、获取执行回调的ScanCallBack
Android 4.3 是
BluetoothAdapter.LeScanCallback leScanCallback;
通过startScan()方法扫描周围的BLE设备。当搜索到目标设备或者搜索一定时间后通过BluetoothScanner的stopScan()方法停止搜索。
Android 5.0是
ScanCallback scanCallback;
BluetoothLeScanner scanner
scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
通过scanner的startScan()方法扫描周围的BLE设备。当搜索到目标设备或者搜索一定时间后通过scanner的stopScan()方法停止搜索。
5、从ScanCallBack的回调函数中获取的广播数据的解析
Android 4.3中,
leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
final iBeacon ibeacon = iBeaconClass.fromScanData(device, rssi, scanRecord);
@Override
public void run() {
}
});
}
};
Android 5.0
scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
final iBeacon ibeacon = iBeaconClass.fromScanData(result.getDevice(),
result.getRssi(), result.getScanRecord().getBytes());
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
// a scan error occurred
}
};
Android 4.3的scanRecord和 Android 5.0 ScanResult.getScanRecord().getBytes()携带了Beacon设备广播的字符串,接下来,就是对字符串的解析。