目錄
[TOC]
Bluetooth Low Energy
- 簡(jiǎn)介:
- 與傳統(tǒng)藍(lán)牙相比鼓拧,低功耗藍(lán)牙的設(shè)計(jì)對(duì)電量消耗更低驯杜。
- 只支持Android 4.3以上的系統(tǒng)版本迅办,即 API Level>=18。
藍(lán)牙開(kāi)發(fā)對(duì)象
-
BluetoothManager
-
獲取對(duì)象:
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
注意:BluetoothManager僅在Android4.3以上的系統(tǒng)版本支持套利,即 API Level>=18奴璃。
-
-
BluetoothAdapter
-
獲取對(duì)象:
BluetoothAdapter mBluetoothAdapter = BluetoothManager.getAdapter(); // 或者 BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- 注意:一個(gè)Android系統(tǒng)只有一個(gè)BluetoothAdapter悉默。
-
方法描述:
- 藍(lán)牙狀態(tài)
- isEnabled()
- 判斷系統(tǒng)藍(lán)牙是否打開(kāi)
- disable()
- 隱式關(guān)閉系統(tǒng)藍(lán)牙
- enable()
- 隱式打開(kāi)系統(tǒng)藍(lán)牙
- isEnabled()
- 藍(lán)牙設(shè)備搜索
- startDiscovery()/cancelDiscovery()
- 開(kāi)始/取消搜索設(shè)備(經(jīng)典藍(lán)牙 和 低功耗藍(lán)牙)
- 執(zhí)行過(guò)程(耗時(shí)12秒):
- 系統(tǒng)發(fā)送 BluetoothAdapter.ACTIOIN_DISCOVERY_STARTED 的廣播
- 搜索藍(lán)牙設(shè)備...
- 只要找到一個(gè)設(shè)備就發(fā)送一個(gè) BluetoothDevice.ACTION_FOUND 的廣播
- 從廣播接收器中就可以得到這個(gè)BluetoothDevice對(duì)象
- 系統(tǒng)發(fā)送 BluetoothAdapter.ACTION_FINISHED 的廣播
- startLeScan()/stopLeScan()
- 開(kāi)始/取消搜索設(shè)備(低功耗藍(lán)牙)
- 注意:
- 在API Level-21以上被標(biāo)記廢棄使用
- startDiscovery()/cancelDiscovery()
- 藍(lán)牙狀態(tài)
-
-
BluetoothLeScanner
-
獲取對(duì)象:
BluetoothLeScanner mBluetoothLeScanner= BluetoothAdapter.getBluetoothLeScanner();
-
方法描述:
- startScan()/stopScan()
- 開(kāi)始/取消搜索設(shè)備(低功耗藍(lán)牙)
- 注意:
- 在API Level-21以上使用
- startScan()/stopScan()
-
-
BluetoothDevice
- 代表了一個(gè)遠(yuǎn)程的藍(lán)牙設(shè)備, 通過(guò)這個(gè)類(lèi)可以查詢(xún)遠(yuǎn)程設(shè)備的物理地址, 名稱(chēng), 連接狀態(tài)等信息,
- 獲取對(duì)象:
-
物理地址對(duì)應(yīng)的Device:
BluetoothAdapter.getRemoteDevice(address);
-
已經(jīng)配對(duì)的Device集合:
BluetoothAdapter.getBoundedDevices();
-
掃描結(jié)果回調(diào)中的Device:
BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { } };
-
-
BluetoothGatt
- BluetoothGatt繼承BluetoothProfile苟穆,
- 通過(guò)BluetoothGatt可以連接設(shè)備(connect),發(fā)現(xiàn)服務(wù)(discoverServices)麦牺,并把相應(yīng)地屬性返回到 BluetoothGattCallback,
- 獲取對(duì)象:
- BluetoothGattCallback回調(diào)方法中獲取鞭缭。
-
BluetoothProfile
- 一個(gè)通用的規(guī)范剖膳,按照這個(gè)規(guī)范來(lái)收發(fā)數(shù)據(jù)。
連接成功后岭辣,我們首先需要獲得服務(wù)吱晒,然后是該服務(wù)所包含的特征,最后是特征的描述符沦童。
-
服務(wù)(Service):
- BluetoothGattService
- 一個(gè) Service 可以包含多個(gè) Characteristic仑濒,
- 獲取對(duì)象:
-
通過(guò)指定的 UUID 從 BluetoothGatt 實(shí)例中獲得:
BluetoothGattService service = BluetoothGatt.getService(UUID.fromString(BLE_SERVICE));
-
- BluetoothGattService
-
特征(Characteristic):
- BluetoothGattCharacteristic
- 一個(gè) Characteristic 包含一個(gè) Value 和多個(gè) Descriptor,
- 相當(dāng)于一個(gè)數(shù)據(jù)類(lèi)型偷遗,它包括一個(gè)value和0~n個(gè)value的描述(Descriptor)墩瞳,
- 獲取對(duì)象:
-
通過(guò)指定的 UUID 從 BluetoothGattService 中得到:
BluetoothGattCharacteristic characteristic = BluetoothGattService.getCharacteristic(UUID.fromString(BLE_CHARACTERISTIC))
-
- BluetoothGattCharacteristic
-
描述符(Descriptor):
- BluetoothGattDescriptor
- 一個(gè) Descriptor 包含一個(gè) Value,
- 對(duì) Characteristic 的描述氏豌,包括范圍喉酌、計(jì)量單位等,
- 獲取對(duì)象:
-
通過(guò)指定的 UUID 從 BluetoothGattCharacteristic 對(duì)象中獲得:
List<BluetoothGattDescriptor> descriptorList = BluetoothGattCharacteristic.getDescriptors(); // 或者 BluetoothGattDescriptor descriptor = BluetoothGattCharacteristic.getDescriptor(UUID.fromString("BLE_DESCRIPTOR"));
-
- BluetoothGattDescriptor
低功耗藍(lán)牙開(kāi)發(fā)基本流程
-
申請(qǐng)權(quán)限
-
基礎(chǔ)權(quán)限:
<!-- 執(zhí)行所有的藍(lán)牙通信泵喘,如請(qǐng)求連接泪电,接受連接和傳輸數(shù)據(jù) --> <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- 初始化設(shè)備發(fā)現(xiàn)或者操縱藍(lán)牙設(shè)置 --> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-
注意:
- 如果應(yīng)用僅支持低功耗藍(lán)牙
-
在 AndroidManifest.xml 添加以下聲明:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
-
動(dòng)態(tài)判斷:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "該設(shè)備不支持低功耗藍(lán)牙", Toast.LENGTH_SHORT).show(); }
-
-
在 Android 6.0 及以上的系統(tǒng)版本,需動(dòng)態(tài)申請(qǐng)位置權(quán)限纪铺。
如果應(yīng)用沒(méi)有位置權(quán)限相速,藍(lán)牙掃描功能不能使用(其它藍(lán)牙操作例如連接藍(lán)牙設(shè)備和寫(xiě)入數(shù)據(jù)不受影響)。-
在 AndroidManifest.xml 添加以下聲明:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 或 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
動(dòng)態(tài)申請(qǐng):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_COARSE_LOCATION: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 權(quán)限申請(qǐng)成功鲜锚,處理業(yè)務(wù)邏輯 } break; default: break; } }
-
- 如果應(yīng)用僅支持低功耗藍(lán)牙
-
-
是否支持藍(lán)牙
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager.getAdapter() == null) { Toast.makeText(Context, "沒(méi)有發(fā)現(xiàn)藍(lán)牙模塊", Toast.LENGTH_SHORT).show(); }
-
開(kāi)啟/關(guān)閉藍(lán)牙
-
檢查藍(lán)牙是否開(kāi)啟
BluetoothAdapter.isEnabled();
-
開(kāi)啟
-
隱式開(kāi)啟
BluetoothAdapter.enable();
- 注意:
-
需要注冊(cè)權(quán)限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
在 Android 6.0 及以上的系統(tǒng)版本突诬,隱式開(kāi)啟依舊會(huì)提示用戶(hù)苫拍。
-
- 注意:
-
顯示開(kāi)啟
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUESTCODE_BLUETOOTH);
-
確認(rèn)結(jié)果:
-
方法一:注冊(cè)廣播
IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//藍(lán)牙狀態(tài) intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);// 掃描開(kāi)始 intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 掃描結(jié)束 registerReceiver(new BluetoothReceiver(), intentFilter); private class BluetoothReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { switch (BluetoothAdapter.getDefaultAdapter().getState()) { case BluetoothAdapter.STATE_ON:// 打開(kāi) break; case BluetoothAdapter.STATE_OFF:// 關(guān)閉 break; case BluetoothAdapter.STATE_TURNING_OFF:// 藍(lán)牙處于關(guān)閉過(guò)程中 break; case BluetoothAdapter.STATE_TURNING_ON:// 藍(lán)牙處于打開(kāi)過(guò)程中 break; default: break; } } } }
-
方法二:重寫(xiě)onActivityResult()
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) {//藍(lán)牙開(kāi)啟成功 switch (requestCode) { case REQUESTCODE_BLUETOOTH: break; default: break; } } else if (resultCode == RESULT_CANCELED) {//藍(lán)牙開(kāi)啟失敗 ToastUtils.showShort("藍(lán)牙開(kāi)啟失敗,請(qǐng)手動(dòng)開(kāi)啟藍(lán)牙"); } }
-
-
前往系統(tǒng)設(shè)置界面
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
-
-
-
關(guān)閉
-
隱式關(guān)閉
BluetoothAdapter.disable();
-
前往系統(tǒng)設(shè)置界面
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
-
-
-
掃描藍(lán)牙設(shè)備
- 開(kāi)啟/關(guān)閉掃描設(shè)備
-
開(kāi)啟
-
掃描全部藍(lán)牙設(shè)備
BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback callback)
-
只掃描含有特定 UUID Service 的藍(lán)牙設(shè)備
BluetoothAdapter.startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback)
-
-
關(guān)閉
BluetoothAdapter.stopLeScan(BluetoothAdapter.LeScanCallback callback)
-
- 開(kāi)啟/關(guān)閉掃描設(shè)備
-
連接設(shè)備
BluetoothGatt BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) {}
- autoConnect:表示是否需要自動(dòng)連接旺隙。
- 設(shè)置為 true 表示如果設(shè)備斷開(kāi)了怯疤,會(huì)不斷的嘗試自動(dòng)連接。
- 設(shè)置為 false 表示只進(jìn)行一次連接嘗試催束。
- BluetoothGattCallback:表示連接后進(jìn)行的一系列操作的回調(diào),共計(jì)9個(gè)回調(diào)方法伏社,以下列舉常用的5個(gè)抠刺。
-
連接狀態(tài)變化
void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {}
-
執(zhí)行BluetoothGatt.discoverServices();后回調(diào),發(fā)現(xiàn)服務(wù)
void onServicesDiscovered(BluetoothGatt gatt, int status) {}
-
執(zhí)行BluetoothGatt.writeCharacteristic();后回調(diào)摘昌,寫(xiě)入數(shù)據(jù)執(zhí)行結(jié)果
void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
-
執(zhí)行BluetoothGatt.setCharacteristicNotification();后回調(diào)速妖,Characteristic值發(fā)生改變
void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {}
-
執(zhí)行BluetoothGatt.writeDescriptor();后回調(diào)
void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
-
- autoConnect:表示是否需要自動(dòng)連接旺隙。
-
發(fā)現(xiàn)服務(wù)
-
在onConnectionStateChange()中,判斷連接狀態(tài)聪黎,連接成功罕容,搜索連接設(shè)備所支持的service
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothGatt.STATE_CONNECTED) {//連接成功 gatt.discoverServices();//搜索連接設(shè)備所支持的service } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {//連接斷開(kāi) } }
-
discoverServices()被執(zhí)行后,在onServicesDiscovered()中稿饰,獲取指定UUID Service锦秒,存下BluetoothGatt對(duì)象
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); BluetoothGattService service = gatt.getService(UUID.fromString(BLE_SERVICE)); if (service != null) { mBluetoothGatt = gatt; } }
-
-
讀寫(xiě)數(shù)據(jù)
- 寫(xiě):
獲取指定 UUID Serivce 的 BluetoothGattService 對(duì)象,
從而得到指定 UUID Characteristic 的 BluetoothGattCharacteristic 對(duì)象喉镰,將數(shù)據(jù)設(shè)置進(jìn)去旅择,
-
最后用 BluetoothGatt 對(duì)象向藍(lán)牙設(shè)備寫(xiě)入數(shù)據(jù)
public void writeCharacteristic() { byte[] data = {0x00};//封包數(shù)據(jù),根據(jù)硬件協(xié)議填寫(xiě) BluetoothGattCharacteristic characteristic = mBluetoothGatt.getService(UUID.fromString(BLE_SERVICE)).getCharacteristic(UUID.fromString(BLE_WRITE)); characteristic.setValue(data);//設(shè)置數(shù)據(jù) mBluetoothGatt.writeCharacteristic(characteristic);//寫(xiě)入設(shè)備 }
- 讀:
在 writeCharacteristic() 調(diào)用后侣姆,
會(huì)走 onCharacteristicChanged() 回調(diào)生真,
在 BluetoothGattCharacteristic 對(duì)象中獲取藍(lán)牙設(shè)備傳回的數(shù)據(jù),
-
通過(guò)藍(lán)牙硬件協(xié)議判斷并做出相應(yīng)處理捺宗。
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); byte[] value = characteristic.getValue(); switch (value[0]) {//判斷協(xié)議柱蟀,對(duì)應(yīng)處理 case 0x00: break; default: break; } }
- 寫(xiě):
-
斷開(kāi)連接
BluetoothGatt.disconnect(); BluetoothGatt.close();