Android 藍芽BLE掃描
阿新 • • 發佈:2020-12-18
1.宣告藍芽許可權和定位許可權
<!--藍芽許可權-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- LE Beacons位置相關許可權-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--藍芽模組 設定為true表示只有支援藍芽的手機才能安裝-->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
由於藍芽掃描需要用到模糊定位許可權,所以android6.0之後,除了在 AndroidManifest.xml中 申明許可權之外,還需要動態申請定位許可權,才可進行藍芽掃描,否則不會掃描到任何Ble裝置。
2. 中心裝置與外圍裝置
Ble開發中,存在著兩個角色:中心裝置角色和外圍裝置角色。粗略瞭解下:
- 外圍裝置:一般指非常小或者低功耗裝置,更強大的中心裝置可以連線外圍裝置為中心裝置提供資料。外設會不停的向外廣播,讓中心裝置知道它的存在。 例如小米手環。
- 中心裝置:可以掃描並連線多個外圍裝置,從外設中獲取資訊。
外圍裝置會設定一個廣播間隔,每個廣播間隔中,都會發送自己的廣播資料。廣播間隔越長,越省電。一個沒有被連線的Ble外設會不斷髮送廣播資料,這時可以被多箇中心裝置發現。一旦外設被連線,則會馬上停止廣播。
android 4.3 時引入的Ble核心Api只支援android手機作為中心裝置角色,當android 5.0 更新Api後,android手機支援充當作為外設角色和中心角色。即 android 5.0 引入了外設角色的Api,同時也更新了部分中心角色的Api。比如:中心角色中,更新了藍芽掃描的Api。
3. 開啟藍芽
//初始化ble設配器
BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = manager.getAdapter();
//判斷藍芽是否開啟,如果關閉則請求開啟藍芽
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
//方式一:請求開啟藍芽
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
//方式二:半靜默開啟藍芽
//低版本android會靜默開啟藍芽,高版本android會請求開啟藍芽
//mBluetoothAdapter.enable();
}
mBluetoothAdapter.isEnabled()判斷當前藍芽是否開啟,如果藍芽處於開啟狀態返回true。
同時可以在activity層通過廣播監聽藍芽的關閉與開啟,進行自己的邏輯處理:
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//獲取藍芽廣播 本地藍芽介面卡的狀態改變時觸發
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
//獲取藍芽廣播中的藍芽新狀態
int blueNewState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
//獲取藍芽廣播中的藍芽舊狀態
int blueOldState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
switch (blueNewState) {
//正在開啟藍芽
case BluetoothAdapter.STATE_TURNING_ON:
break;
//藍芽已開啟
case BluetoothAdapter.STATE_ON:
break;
//正在關閉藍芽
case BluetoothAdapter.STATE_TURNING_OFF:
break;
//藍芽已關閉
case BluetoothAdapter.STATE_OFF:
break;
}
}
}
};
4. 掃描
4.1 android 4.3 掃描
在android 4.3 和 android 4.4進行藍芽掃描中,可使用BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback)進行藍芽掃描。
//開始掃描
mBluetoothAdapter.startLeScan(mLeScanCallback);
//停止掃描
mBluetoothAdapter.stopLeScan(mLeScanCallback);
4.2 android 5.0以上 掃描
在 android 5.0之後的版本(包括 5.0)建議使用新的Api進行藍芽掃描:
- BluetoothLeScanner.startScan(ScanCallback)或
- BluetoothLeScanner.startScan(List, ScanSettings, ScanCallback)。
//獲取 5.0 的掃描類例項
mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
//開始掃描
//可設定過濾條件,在第一個引數傳入,但一般不設定過濾。
mBLEScanner.startScan(null,mScanSettings,mScanCallback);
//停止掃描
mBLEScanner.stopScan(mScanCallback);
4.3 藍芽掃描示例:
//如果沒開啟藍芽,不進行掃描操作,或請求開啟藍芽。
if(!mBluetoothAdapter.isEnabled()) {
return;
}
//處於未掃描的狀態
if (!mScanning){
//android 5.0後
if(android.os.Build.VERSION.SDK_INT >= 21) {
//標記當前的為掃描狀態
mScanning = true;
//獲取5.0新添的掃描類
if (mBLEScanner == null){
//mBLEScanner是5.0新新增的掃描類,通過BluetoothAdapter例項獲取。
mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
}
//開始掃描
//mScanSettings是ScanSettings例項,mScanCallback是ScanCallback例項,後面進行講解。
mBLEScanner.startScan(null,mScanSettings,mScanCallback);
} else {
//標記當前的為掃描狀態
mScanning = true;
//5.0以下 開始掃描
//mLeScanCallback是BluetoothAdapter.LeScanCallback例項
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
//設定結束掃描
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//停止掃描裝置
if(android.os.Build.VERSION.SDK_INT >= 21) {
//標記當前的為未掃描狀態
mScanning = false;
mBLEScanner.stopScan(mScanCallback);
} else {
//標記當前的為未掃描狀態
mScanning = false;
//5.0以下 停止掃描
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
},SCAN_TIME);
}
掃描程式碼如上述所示,當掃描到所需要的裝置的時候,就要手動馬上停止藍芽掃描,因為藍芽掃描是耗電操作。
注意事項:
- android 6.0 以上需要獲取到定位許可權。否則會爆如下執行時異常:
image
- android 7.0 後不能在30秒內掃描和停止超過5次。(官網沒特意說明,可自行測試,設定掃描時長為3秒,連續掃描10次,穩定復現5次後不能掃描到任何裝置。android 藍芽模組會列印當前應用掃描太頻繁的log日誌,並在android 5.0 的ScanCallback回撥中觸發onScanFailed(int),返回錯誤碼:ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app無法註冊,無法開始掃描)。