android BLE Peripheral 作外設模擬設備,供ios、android 鏈接通信。

爲了能讓其它設備能夠發現其設備,先啓動特定廣播。看本身須要什麼廣播格式。html

對於廣播可見的mac address:android

在調用startAdvertising();時,mac address 就會改變。ios

而且跟mBluetoothAdapter.getAddress();獲取到的藍牙mac 地址不同。shell

這是由於在android 5.0 以後,爲了保護真正的mac address。編程

在廣播出來的地址,是通過隨機可解析隱祕轉換的(Resolvable private address)。數組

因此要在廣播數據中添加mac address 輸出,就要用靜態藍牙地址。安全

BLE設備的地址類型:

一個BLE設備,可使用兩種類型的地址(一個BLE設備可同時具有兩種地址):dom

一、 Public Device Address (公有地址)ide

     該地址須要向IEEE申請(購買),IEEE保證地址的惟一性。函數

二、Random Device Address (隨機地址)

     設備地址不是固定分配的,而是在設備設備啓動後隨機生成的。

     Random Device Address分爲:

     (1)Static Device Address (靜態地址)

       在一個上電週期內保持不變。地址隨機生成。

     (2)Private Device Address (私有地址)

            經過定時更新和地址加密兩種方法,提升藍牙地址的可靠性和安全性。

            Private Device Address分爲

                1) Non-resolvable Private Address (不可解析私有地址)

                會定時更新。以T_GAP(private_addr_int)爲週期,建議15分鐘。

                2) Resolvable Private Address  (可解析私有地址)

                以T_GAP(private_addr_int)爲週期,定時更新。哪怕在廣播、掃描、已鏈接等過程當中,也可能改變。它經過一個隨機數和一個稱做identity resolving key (IRK) 的密碼生成,所以只能被擁有相同IPK的設備掃描到,能夠防止被未知設備掃描和追蹤。

android 對外發出廣播,都同樣,只是更改其中的方法:

android BLE Peripheral 模擬 ibeacon 發出ble 廣播

開始廣播: 增長使用BluetoothGattServer

 1 public void startAdvertising(MockServerCallBack callBack) {
 2         //獲取BluetoothLeAdvertiser,BLE發送BLE廣播用的一個API
 3         if (mBluetoothAdvertiser == null) {
 4             mBluetoothAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
 5         }
 6         //建立BluetoothGattServerCallback,
 7         // MockServerCallBack這個類繼承自BluetoothGattServerCallback
 8         // BluetoothGattServerCallback這個回調類主要是一些BLE讀寫的接口
 9         // 關於BLE讀寫的操做都在這個Callback中完成
10         if (mBluetoothAdvertiser != null) {
11             mMockServerCallBack = callBack;
12             //打開BluetoothGattServer
13             mGattServer = mBluetoothManager.openGattServer(mActivity, mMockServerCallBack);
14             if (mGattServer == null) {
15                 Log.e(TAG, "gatt is null");
16             }
17             try {
18                 mMockServerCallBack.setupServices(mActivity, mGattServer);
20                 mBluetoothAdvertiser.startAdvertising(createAdvSettings(true, 0)
21                         , createAdvertiseData(BluetoothUUID.bleServerUUID), mAdvCallback);
22             } catch (Exception e) {
23                 Log.v(TAG, "Fail to setup BleService");
24             }
25         }
26 
27         isAdvertising = true;
28     }

建立廣播,添加serviceUuid,廣播內容,自行決定。

addServiceUuid(ParcelUuid serviceUuid) 的做用。

廣播數據加入serviceUuid , 當其它設備掃描時,就能夠根據此serviceUuid進行特定掃描.

掃描BLE設備的時候:啓動掃描時,有可選參數,傳入uuid數組。

BluetoothAdapter
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback);

使用該函數啓動掃描的,會根據所傳入的uuid,去掃描過濾,只返回符合條件的設備。

注意:部分手機可能設置uuid後,掃描不到設備,可能底層掃描問題。

 1  public static AdvertiseData createAdvertiseData(UUID proximityUuid) {
 2     AdvertiseData.Builder builder = new AdvertiseData.Builder();
 4     builder.addManufacturerData(0x0301, new byte[]{0x01, 0x03});
 5     builder.addServiceUuid(ParcelUuid.fromString(BluetoothUUID.bleServerUUID.toString())
 7     AdvertiseData adv = builder.build();
10     return adv;
11  }

 

BluetoothGattServerCallback:服務事件的回調

打開notification 對應的value爲 BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE

打開indication 對應的value爲 BluetoothGattDescriptor.ENABLE_INDICATION_VALUE

關閉notification 對應的value均爲BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE

服務事件響應過程:

(1) 當客戶端開始寫入數據時: 觸發回調方法 onDescriptorWriteRequest

(2) 在 onDescriptorWriteRequest 方法中,執行下面的方法表示 寫入成功 BluetoothGatt.GATT_SUCCESS

1 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
2 // 執行 sendResponse後,會觸發回調方法 onCharacteristicWriteRequest

(3) 在 onCharacteristicWriteRequest方法中:

1 public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId
2 , BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
3        // 這個裏能夠得到 來自客戶端發來的數據 requestBytes
4 }

(4) 處理響應內容

BluetoothGattServerCallback :

  1 public class MockServerCallBack extends BluetoothGattServerCallback {
  2 
  3 public void setupServices(Context context, BluetoothGattServer gattServer) throws InterruptedException {
  4         if (gattServer == null) {
  5             throw new IllegalArgumentException("gattServer is null");
  6         }
  7         mGattServer = gattServer;
  8         // 設置一個GattService以及BluetoothGattCharacteristic
  9         BluetoothGattService service = new BluetoothGattService(BluetoothUUID.bleServerUUID,
 10                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
 11 
 12         BluetoothGattService service2 = new BluetoothGattService(BluetoothUUID.bleServerUUID2,
 13                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
 14 
 15         //add a read characteristic.
 16         // 當是ios設備鏈接過來時,需添加BluetoothGattCharacteristic.PROPERTY_INDICATE或者notify進行兼容。
 17         mCharacteristicRead = new BluetoothGattCharacteristic(BluetoothUUID.readDataUUID
 18                 , BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_INDICATE
 19                 , BluetoothGattCharacteristic.PERMISSION_READ);
 20         //add a descriptor
 21         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(BluetoothUUID.CLIENT_CHARACTERISTIC_CONFIG
 22                 , BluetoothGattCharacteristic.PERMISSION_WRITE);
 23         mCharacteristicRead.addDescriptor(descriptor);
 24         service.addCharacteristic(mCharacteristicRead);
 25 
 26         BluetoothGattCharacteristic write = new BluetoothGattCharacteristic(
 27                 BluetoothUUID.writeDataUUID,
 28                 BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_INDICATE,
 29                 BluetoothGattCharacteristic.PERMISSION_WRITE);
 30 
 31         service.addCharacteristic(write);
 32 
 33         if (mGattServer != null && service != null) {
 34             mGattServer.addService(service);
 35             mGattServer.addService(service2);
 36         }
 37 
 38     }
 39 
 40     //當添加一個GattService成功後會回調改接口。
 41     public void onServiceAdded(int status, BluetoothGattService service) {
 42         super.onServiceAdded(status, service);
 43         if (status == BluetoothGatt.GATT_SUCCESS) {
 44             Log.d(TAG, "onServiceAdded status=GATT_SUCCESS service=" + service.getUuid().toString());
 45         } else {
 46             Log.d(TAG, "onServiceAdded status!=GATT_SUCCESS");
 47         }
 48     }
 49 
 50     //BLE設備鏈接狀態發生改變後回調的接口
 51     public void onConnectionStateChange(android.bluetooth.BluetoothDevice device, int status,
 52                                         int newState) {
 53         super.onConnectionStateChange(device, status, newState);
 54         Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s"
 55                 , device.getName(), device.getAddress()));
 56         Log.d(TAG, "onConnectionStateChange status=" + status + "->" + newState);
 57         if (newState == BluetoothProfile.STATE_DISCONNECTED) {
 58             btClient = null; // 移除客戶端鏈接設備  59         }
 60     }
 61 
 62     //當有客戶端來讀數據時回調的接口
 64     /**
 65      * 特徵被讀取。當回覆響應成功後,客戶端會讀取而後觸發本方法, 
 66      */
 67     public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device,
 68                                             int requestId, int offset, BluetoothGattCharacteristic characteristic) {
 69         super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
 70         characteristic.setValue(new byte[]{0x03, 0x01});
 71         Log.e(TAG, String.format("1.onCharacteristicReadRequest:device name = %s, address = %s"
 72                 , device.getName(), device.getAddress()));
 73         Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));
 74         boolean result = mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
 75 
 76         Log.e(TAG, "read request send response:" + result);
 77     }
 78 
 79     //當有客戶端來寫數據時回調的接口
 81     /**
 82      * 接受具體數據字節
*/ 86 @Override 87 public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, 88 int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, 89 boolean responseNeeded, int offset, byte[] value) { 90 super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); 91 // 需調用 sendResponse 來響應,爲了保持鏈接。 92 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); 93 94 // 處理其它設備寫進來的數據 95 value. // 處理數據 byte[] value,記住鏈接設備 96 97 } 98
// 當有客戶端來寫Descriptor 時回調的接口 99 /** 描述被寫入時,在這裏執行bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS...) 時
* 觸發onCharacteristicWriteRequest **/
100 @Override 101 public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 102 super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); 103 104 Log.d(TAG, "onDescriptorWriteRequest:" + Arrays.toString(value)); 105 // now tell the connected device that this was all successfull 106 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 107 } 108 109 }

 

經過adb 獲取 藍牙 mac address: 

1 adb shell settings get secure bluetooth_address

或者

1 // for Android 4.4.4
2 adb shell service call bluetooth_manager 10 
3 // for Android 5.0+
4 adb shell service call bluetooth_manager 12 

編程獲取bluetooth mac address :

1 String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");

 

 

推薦文章:

藍牙4.2保護隱私

藍牙協議分析_BLE地址類型

相關文章
相關標籤/搜索