android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser
生活随笔
收集整理的這篇文章主要介紹了
android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
android 從4.3系統開始可以連接BLE設備,這個大家都知道了。iOS是從7.0版本開始支持BLE。android 進入5.0時代時,開放了一個新功能,手機可以模擬設備發出BLE廣播, 這個新功能其實是 對標于 iOS系統的手機模擬iBeacon設備。先介紹一下BLE的廣播, BLE設備之所以能被手機掃描到,是因為 BLE設備一直在每隔 一段時間廣播一次,這個廣播里面包含很多數據。手機掃描BLE設備代碼如下:public void startScan(){bluetoothAdapter.startLeScan(leScanCallback);}public void stopScan(){bluetoothAdapter.stopLeScan(leScanCallback);}private LeScanCallback leScanCallback=new LeScanCallback() {@Overridepublic void onLeScan(BluetoothDevice bluetoothdeivce, int rssi, byte[] scandata) {//把byte數組轉成16進制字符串,方便查看Log.e("TAG","scandata:"+ CYUtils.Bytes2HexString(scandata));}};
ok,這段代碼大家在做連接BLE設備進行通訊的時候,已經很熟悉了。其中的 byte數組 scandata就是 BLE設備的廣播數據。那么接下來,我們開始使用 手機1 模擬成BLE設備來發送廣播,然后用手機2 來進行掃描查看廣播數據 scandata首先獲取 BluetoothAdapter, 熟悉的代碼:BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);bluetoothAdapter = bluetoothManager.getAdapter();進行廣播的時候需要用到BluetoothLeAdvertiser,進行實例化:mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
實例化好之后就可以進行廣播數據了,開啟廣播方法是:BluetoothLeAdvertiser:
public void startAdvertising(AdvertiseSettings settings,AdvertiseData advertiseData, final AdvertiseCallback callback)
其中, AdvertiseSettings 是廣播的一些設置,比如,廣播間隔,是否可以連接等等; AdvertiseData 就是廣播數據了, AdvertiseCallback是廣播回調,會告訴你廣播成功還是失敗。先給一段完整廣播代碼如下:public void startAction(View v){byte[] broadcastData ={0x34,0x56};mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(broadcastData), mAdvertiseCallback);}public void stopAction(View v) {mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);}public AdvertiseSettings createAdvSettings(boolean connectable, int timeoutMillis) {AdvertiseSettings.Builder mSettingsbuilder = new AdvertiseSettings.Builder();mSettingsbuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);mSettingsbuilder.setConnectable(connectable);mSettingsbuilder.setTimeout(timeoutMillis);AdvertiseSettings mAdvertiseSettings = mSettingsbuilder.build();return mAdvertiseSettings;}public AdvertiseData createAdvertiseData(byte[] data) {AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();mDataBuilder.addManufacturerData(0x01AC, data);AdvertiseData mAdvertiseData = mDataBuilder.build();return mAdvertiseData;}private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {@Overridepublic void onStartSuccess(AdvertiseSettings settingsInEffect) {super.onStartSuccess(settingsInEffect);ToastUtils.showToast(MainActivity.this, "開啟廣播成功", 2000);}@Overridepublic void onStartFailure(int errorCode) {super.onStartFailure(errorCode);ToastUtils.showToast(MainActivity.this, "開啟廣播失敗 errorCode:" + errorCode, 2000);}};其中,廣播數據broadcastData 我暫時直接先定死為2個字節 0x3456,同樣在createAdvertiseData里面也有定死的數據 0x01AC . 開啟成功之后我們使用手機2 來掃描看下廣播的數據是什么:E/TAG: scandata:02011A05FFAC0134560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
log打印出來的scandata 有效數據是 02011A05FFAC013456 . 給大家解釋一下這個數據的意思為了看清楚,我分段如下: 02011A 05 FF AC01 3456 (注,這里的都是16進制數字)02011A這3個字節,02表示后面一段數據長度為2字節,01表示數據類型是flag ,1A就是flag的數據了05 表示后面的一段數據長度為 5個字節, FF一個字節,AC01 兩個字節,3456兩個字節,加起來一共5個字節,老鐵沒毛病FF,是一個數據類型,這是我們通過代碼mDataBuilder.addManufacturerData(0x01AC, data); 添加廣播數據時候設置的ManufacturerData 是指設備廠商自定義數據,FF 就是代表下面的數據實體是廠商數據.第一個參數0x01AC,是廠商id,id長度為2個字節,不足2個字節系統會補0,可以看到log打印出來的是 AC01,順序是倒過來的,這點要注意!如果我代碼是這樣寫的 :mDataBuilder.addManufacturerData(0xAC, data); //只寫了一個字節的id
那么使用手機2 掃描出的scandata是:E/TAG: scandata:02011A05FFAC0034560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以看到,AC后面系統自動補了00廣播數據出除了可以添加ManufacturerData,還可以添加ServerUUID, 代碼如下:public AdvertiseData createAdvertiseData(byte[] data) {AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();mDataBuilder.addManufacturerData(0x01AC, data);mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));AdvertiseData mAdvertiseData = mDataBuilder.build();return mAdvertiseData;}
代碼添加了一個 AE8F的 server uuid, 使用手機2 掃描的scandata 如下:E/TAG: scandata:02011A05FFAC01345603038FAE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看03038FAE 這一段,第一個03 表示后面的一段數據長度為3個字節 第二個03 表示這個數據類型是 server uuid類型,uuid的數據就是8FAE,順序是倒過來的!有人會問: 如果 我把addServiceUuid代碼放在 addManufacturerData 前面,掃描的數據順序是什么樣的呢?答案 還是:E/TAG: scandata:02011A05FFAC01345603038FAE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以添加多個 server uuid嗎? 可以,代碼如下:public AdvertiseData createAdvertiseData(byte[] data) {AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addManufacturerData(0x01AC, data);AdvertiseData mAdvertiseData = mDataBuilder.build();return mAdvertiseData;}
掃描的結果是:E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看0503 8FAE E1FF 這一段, 05 表示后面的一段數據長度是5個字節,03表示數據類型是 server uuid, 8FAE是第一個uuid, E1FF是第二個uuid這個ServerUUID 有什么用呢? 不知大家在掃描BLE設備的時候,有沒有注意到這個方法:BluetoothAdapter
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)這個方法也可以用來掃描BLE設備,但是多了一個參數, UUID數組, 這個掃描方法是用來過濾BLE設備用的,比如 你公司開發一個 藍牙防丟器APP,你使用 startLeScan(callback)這個方法掃描的話,你會發現你掃描到周圍的所有的BLE設備,同事戴的小米手環可能也被你掃描到,這樣讓用戶來選擇設備進行連接的話可能就比較迷糊,startLeScan(serviceUuids,callback) 這個方法在掃描的時候會過濾廣播里的數據,只有符合的BLE設備才會被掃描回調。 所以,你們公司的藍牙防丟器設備可以在廣播字段里加入特定的server uuid, app掃描的時候可以過濾其他設備。我們來實現一下這個功能, 修改 手機2 的掃描代碼:public void startScan(){UUID[] serviceUuids = new UUID[] { UUID .fromString("0000ae8f-0000-1000-8000-00805f9b34fb") };bluetoothAdapter.startLeScan(serviceUuids, leScanCallback);}public void stopScan(){bluetoothAdapter.stopLeScan(leScanCallback);}private LeScanCallback leScanCallback=new LeScanCallback() {@Overridepublic void onLeScan(BluetoothDevice bluetoothdeivce, int rssi, byte[] scandata) {//把byte數組轉成16進制字符串,方便查看Log.e("TAG","scandata:"+ CYUtils.Bytes2HexString(scandata));}};
掃描結果是這樣的:05-23 16:13:30.522 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.625 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.735 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.847 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.955 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.061 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.192 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.283 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.369 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.480 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以發現,掃描結果里面只會出現擁有 AE8F 這個uuid的 BLE設備,搜索不到其他設備注意:部分手機使用startLeScan(serviceUuids,callback)這個方法過濾設備 會掃描不到設備,即使這個設備UUID符合過濾條件,我歸結為手機/系統問題,如三星手機這樣,我們知道,廣播數據可以添加ManufacturerData,還可以添加ServerUUID, 還有嗎? 有,代碼如下:public AdvertiseData createAdvertiseData(byte[] data) {AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x64,0x12});mDataBuilder.addManufacturerData(0x01AC, data);AdvertiseData mAdvertiseData = mDataBuilder.build();return mAdvertiseData;}掃描結果如下:E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE64120000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看05168FAE6412 這一段,05依然表示下面一段數據長度為5個字節,16表示數據類型為 server data, 8FAE表示這個數據的uuid是AE8F, 6412就是數據本體了.那么這個 server data能做什么呢?比如有這樣一個 產品:溫度計,溫度計硬件在廣播字段里的server data里面加入它測量的溫度,這樣APP可以不連接溫度計設備 只通過掃描就知道溫度了,是不是很方便.以下有幾個坑請大家注意一下:情況1:public AdvertiseData createAdvertiseData(byte[] data) {AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();// mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x64,0x12});mDataBuilder.addManufacturerData(0x01AC, data);AdvertiseData mAdvertiseData = mDataBuilder.build();return mAdvertiseData;}我注釋了一句代碼,廣播字段里我沒有 添加 ae8f這個 uuid,而直接添加了 ae8f的data 為 0x6412,那么掃描結果如何?使用startLeScan(serviceUuids,callback)過濾 ae8f這個uuid,沒有掃描結果;使用startLeScan(callback),掃描結果如下:E/TAG: scandata:02011A05FFAC0134560303E1FF05168FAE641200000000000000000000000000000000000000000000000000000000000000000000000000000000000000可以看到是有 ae8f對應的數據 6412,但是server uuid里面是沒有 ae8f的.情況2:代碼順序1:mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x44});mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x12});//掃描結果
E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE54120000000000000000000000000000000000000000000000000000000000000000000000000000000000代碼順序2:mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x11});mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x43});//掃描結果
E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE54110000000000000000000000000000000000000000000000000000000000000000000000000000000000代碼順序3:mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x1A});mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x47});//掃描結果
E/TAG: scandata:02011A05FFAC0134560503E1FF8FAE05168FAE541A0000000000000000000000000000000000000000000000000000000000000000000000000000000000代碼順序4:mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x48});mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x1B});//掃描結果
E/TAG: scandata:02011A05FFAC0134560503E1FF8FAE05168FAE541B0000000000000000000000000000000000000000000000000000000000000000000000000000000000情況2總結:從上面4個代碼順序的結果來看,總是掃描到 ae8f這個uuid對應的數據,沒有第二個 server data,但是為什么每次都是ae8f?我TM也不知道!!AdvertiseData介紹完畢,下面再稍微介紹一下 AdvertiseSettingsAdvertiseSettings.Builder mSettingsbuilder = new AdvertiseSettings.Builder();mSettingsbuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);mSettingsbuilder.setConnectable(connectable);mSettingsbuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);mSettingsbuilder.setTimeout(0);AdvertiseSettings mAdvertiseSettings = mSettingsbuilder.build();setAdvertiseMode(int advertiseMode)設置廣播的模式,低功耗,平衡和低延遲三種模式;對應 AdvertiseSettings.ADVERTISE_MODE_LOW_POWER ,ADVERTISE_MODE_BALANCED ,ADVERTISE_MODE_LOW_LATENCY從左右到右,廣播的間隔會越來越短 setConnectable(boolean connectable)設置是否可以連接。廣播分為可連接廣播和不可連接廣播,一般不可連接廣播應用在iBeacon設備上,這樣APP無法連接上iBeacon設備setTimeout(int timeoutMillis)設置廣播的最長時間,最大值為常量AdvertiseSettings.LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; 180秒設為0時,代表無時間限制會一直廣播setTxPowerLevel(int txPowerLevel)設置廣播的信號強度常量有AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,ADVERTISE_TX_POWER_LOW,ADVERTISE_TX_POWER_MEDIUM,ADVERTISE_TX_POWER_HIGH 從左到右分別表示強度越來越強. 舉例:當設置為ADVERTISE_TX_POWER_ULTRA_LOW時,手機1和手機2放在一起,手機2掃描到的rssi信號強度為-56左右,當設置為ADVERTISE_TX_POWER_HIGH 時, 掃描到的信號強度為-33左右,信號強度越大,表示手機和設備靠的越近好了,關于BluetoothLeAdvertiser 的用法介紹完畢!!!!可能有人會說,bluetoothAdapter.startLeScan(leScanCallback); 這個方法過時了怎么辦,那可以看一下我的另一篇文章《android BLE 掃描BLE設備 BluetoothLeScanner》源碼附件:模擬BLE廣播源碼:http://pan.baidu.com/s/1bptOQyb
手機2掃描打印的源碼就不放出了,很簡單。android BLE Peripheral 手機模擬設備發出BLE廣播 BluetoothLeAdvertiser
?
轉載于:https://www.cnblogs.com/Free-Thinker/p/9292183.html
總結
以上是生活随笔為你收集整理的android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 少送一把“钥匙” 国产宝马X5降价300
- 下一篇: Java08-java语法基础(七)构造