藍牙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設備廣播的字符串,接下來,就是對字符串的解析。