android藍牙BLE(一) —— 掃描

android BLE系列:

android藍牙BLE(一) —— 掃描android

android藍牙BLE(二) —— 通訊bash

android藍牙BLE(三) —— 廣播app

android藍牙BLE(四) —— 實戰ide

前序

    Google在android 4.3(API Level 18)的android版本中引入了低功耗藍牙BLE核心API。低功耗藍牙BLE也就是咱們常常說的藍牙4.0, 該技術擁有極低的運行和待機功耗,使用一粒鈕釦電池甚至可連續工做數年之久。先不講藍牙協議與藍牙模塊一些類的做用與之間的關係,本章僅僅記錄android Ble開發中的掃描模塊及其一些細節。
函數

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設備。post

2、中心設備與外圍設備

    Ble開發中,存在着兩個角色:中心設備角色和外圍設備角色。粗略瞭解下:測試

  • 外圍設備:通常指很是小或者低功耗設備,更強大的中心設備能夠鏈接外圍設備爲中心設備提供數據。外設會不停的向外廣播,讓中心設備知道它的存在。 例如小米手環。
  • 中心設備:能夠掃描並鏈接多個外圍設備,從外設中獲取信息。


    外圍設備會設定一個廣播間隔,每一個廣播間隔中,都會發送本身的廣播數據。廣播間隔越長,越省電。一個沒有被鏈接的Ble外設會不斷髮送廣播數據,這時能夠被多箇中心設備發現。一旦外設被鏈接,則會立刻中止廣播。ui


    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。spa

    同時能夠在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、掃描

android 4.3 掃描

    在android 4.3 和 android 4.4進行藍牙掃描中,可以使用BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback)進行藍牙掃描。

//開始掃描
mBluetoothAdapter.startLeScan(mLeScanCallback);
//中止掃描
mBluetoothAdapter.stopLeScan(mLeScanCallback);
複製代碼

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);
複製代碼

藍牙掃描示例:

//若是沒打開藍牙,不進行掃描操做,或請求打開藍牙。
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 以上須要獲取到定位權限。不然會爆以下運行時異常:

  • android 7.0 後不能在30秒內掃描和中止超過5次。(官網沒特地說明,可自行測試,設置掃描時長爲3秒,連續掃描10次,穩定復現5次後不能掃描到任何設備。android 藍牙模塊會打印當前應用掃描太頻繁的log日誌,並在android 5.0 的ScanCallback回調中觸發onScanFailed(int),返回錯誤碼:ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app沒法註冊,沒法開始掃描)。

5、掃描回調

android 4.3 掃描回調:LeScanCallback

    一、android 4.3 的掃描回調接口BluetoothAdapter.LeScanCallback:

    回調接口中只有一個回調函數onLeScan,掃描到的設備會經過該方法返回。
參數:

  • BluetoothDevice 掃描到的設備實例,可從實例中獲取到相應的信息。如:名稱,mac地址
  • rssi 可理解成設備的信號值。該數值是一個負數,越大則信號越強。
  • scanRecord 遠程設備提供的廣播數據的內容。
//5.0如下
mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        //對掃描到的設備進行操做。如:獲取設備信息。
        
    }
};
複製代碼

獲取BluetoothDevice中的信息:

    能夠從中獲取到設備的mac地址,設備名稱,綁定狀態和設備類型等信息,並做相應的保存。

  • mac可用於再建立BluetoothDevice對象進行gatt鏈接。

  • 綁定狀態:
            BOND_NONE:數值 10
        表示遠程設備未綁定,沒有共享連接密鑰,所以通訊(若是容許的話)將是未經身份驗證和未加密的。(掃描到未綁定的小米手環)

    BOND_BONDING:數值 11     表示正在與遠程設備進行綁定;

    BOND_BONDED:數值 12     表示遠程設備已綁定,遠程設備本地存儲共享鏈接的密鑰,所以能夠對通訊進行身份驗證和加密。(掃描到已綁定的小米手環)

  • 設備類型:通常是2,表示LE設備

注:回調函數中儘可能不要作耗時操做!

android 5.0 掃描回調:ScanCallback

mScanCallback = new ScanCallback() {
    //當一個藍牙ble廣播被發現時回調
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        //掃描類型有開始掃描時傳入的ScanSettings相關
        //對掃描到的設備進行操做。如:獲取設備信息。
        
    }

    //批量返回掃描結果
    //@param results 之前掃描到的掃描結果列表。
    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        super.onBatchScanResults(results);
        
    }

    //當掃描不能開啓時回調
    @Override
    public void onScanFailed(int errorCode) {
        super.onScanFailed(errorCode);
        //掃描太頻繁會返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app沒法註冊,沒法開始掃描。
    
    }
};
複製代碼

    ScanCallback掃描回調存在三個回調函數:

  • onScanResult(int,ScanResult):
    相似於BluetoothAdapter.LeScanCallback中的onLeScan(),可在ScanResult實例中獲取到BluetoothDevice藍牙設備對象,rssi信號值等信息,通常都是在該函數中回調獲取掃描到藍牙設備和信號值,在本函數中執行onLeScan()中相同的邏輯處理便可。
  • onBatchScanResults(List) 批量返回掃描結果
  • onScanFailed(int) 掃描失敗返回錯誤碼

    通常藍牙設備對象都是經過onScanResult(int,ScanResult)返回,而不會在onBatchScanResults(List)方法中返回,除非手機支持批量掃描模式而且開啓了批量掃描模式。批處理的開啓請查看ScanSettings。

6、ScanSettings:

        ScanSettings實例對象是經過ScanSettings.Builder構建的。經過Builder對象爲ScanSettings實例設置掃描模式、回調類型、匹配模式等參數,用於配置android 5.0 的掃描參數。

//建立ScanSettings的build對象用於設置參數
ScanSettings.Builder builder = new ScanSettings.Builder()
    //設置高功耗模式
    .setScanMode(SCAN_MODE_LOW_LATENCY);
    //android 6.0添加設置回調類型、匹配模式等
    if(android.os.Build.VERSION.SDK_INT >= 23) {
        //定義回調類型
        builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
        //設置藍牙LE掃描濾波器硬件匹配的匹配模式
        builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);
    }
//芯片組支持批處理芯片上的掃描
if (bluetoothadapter.isOffloadedScanBatchingSupported()) {
    //設置藍牙LE掃描的報告延遲的時間(以毫秒爲單位)
    //設置爲0以當即通知結果
    builder.setReportDelay(0L);
}
builder.build();
複製代碼

配置描述:

  • setScanMode() 設置掃描模式。可選擇模式主要三種:

     ScanSettings.SCAN_MODE_LOW_POWER 低功耗模式

     ScanSettings.SCAN_MODE_BALANCED 平衡模式

     ScanSettings.SCAN_MODE_LOW_LATENCY 高功耗模式

    從上到下,會愈來愈耗電,但掃描間隔愈來愈短,即掃描速度會愈來愈快。

  • setCallbackType() 設置回調類型
    可選擇模式主要三種:

    ScanSettings.CALLBACK_TYPE_ALL_MATCHES 數值: 1
        尋找符合過濾條件的藍牙廣播,若是沒有設置過濾條件,則返回所有廣播包

    ScanSettings.CALLBACK_TYPE_FIRST_MATCH 數值: 2
        僅針對與篩選條件匹配的第一個廣播包觸發結果回調。

    ScanSettings.CALLBACK_TYPE_MATCH_LOST 數值: 4

    回調類型通常設置ScanSettings.CALLBACK_TYPE_ALL_MATCHES,有過濾條件時過濾,返回符合過濾條件的藍牙廣播。無過濾條件時,返回所有藍牙廣播。

  • setMatchMode() 設置藍牙LE掃描濾波器硬件匹配的匹配模式
        通常設置ScanSettings.MATCH_MODE_STICKY

  • Bluetoothadapter.isOffloadedScanBatchingSupported()
        判斷當前手機藍牙芯片是否支持批處理掃描。若是支持掃描則使用批處理掃描,可經過ScanSettings.Builder對象調用setReportDelay(Long)方法來設置藍牙LE掃描的報告延遲的時間(以毫秒爲單位)來啓動批處理掃描模式。

  • ScanSettings.Builder.setReportDelay(Long);

    當設備藍牙芯片支持批處理掃描時,用來設置藍牙LE掃描的報告延遲的時間(以毫秒爲單位)。

    該參數默認爲 0,若是不修改它的值,則默認只會在onScanResult(int,ScanResult)中返回掃描到的藍牙設備,不會觸發不會觸發onBatchScanResults(List)方法。

    設置爲0以當即通知結果,不開啓批處理掃描模式。即ScanCallback藍牙回調中,不會觸發onBatchScanResults(List)方法,但會觸發onScanResult(int,ScanResult)方法,返回掃描到的藍牙設備。

    當設置的時間大於0L時,則會開啓批處理掃描模式。即觸發onBatchScanResults(List)方法,返回掃描到的藍牙設備列表。但不會觸發onScanResult(int,ScanResult)方法。

相關文章
相關標籤/搜索