開發(一)中,我們介紹了怎麼掃描到IBeacon。這節我們去看看怎麼修改IBeacon的參數。
IBeacon裏的參數,主要有這幾個
name:設備名稱
major:主參數
minor:副參數
mac:mac地址
UUID:IBeacon的UUID,相當與使用這個模塊對映的應用的標識
rssi:信號強度
txPower:1m距離的信號強度參考值,他和rssi通過公司,可大體計算出距離來
通過上一章的掃描,我們獲得了一個IBeacon的列表ArrayList,當我們想修改某個IBeacon的信息的時候,就要用到這個IBeacon的mac了
通過點擊等等方式呢,我們可以獲得某IBeacon的mac,
1 /** 2 * Connects to the GATT server hosted on the Bluetooth LE device. 3 * 4 * @param address 5 * The device address of the destination device. 6 * @return Return true if the connection is initiated successfully. The 7 * connection result 8 * is reported asynchronously through the 9 * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} 10 * callback. 11 */ 12 public boolean connect(final String address) 13 { 14 if (mBluetoothAdapter == null || address == null) 15 { 16 Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); 17 return false; 18 } 19 20 // Previously connected device. Try to reconnect. 21 if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) 22 { 23 Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); 24 if (mBluetoothGatt.connect()) 25 { 26 return true; 27 } 28 else 29 { 30 return false; 31 } 32 } 33 34 final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); 35 if (device == null) 36 { 37 Log.w(TAG, "Device not found. Unable to connect."); 38 return false; 39 } 40 // We want to directly connect to the device, so we are setting the autoConnect 41 // parameter to false. 42 mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback); 43 Log.d(TAG, "Trying to create a new connection."); 44 mBluetoothDeviceAddress = address; 45 return true; 46 } 47
根據大神的代碼呢,我們connect (mac地址),這樣呢我們就可以獲得BluetoothGatt。但是,連接完成了,再幹嘛???
我們少了N步。
在大神的代碼BluetoothLeClass類裏,我們看到了好幾個接口,這些接口是幹嘛的?
OnConnectListener:當連接成功時調用
OnDisconnectListener:連接關閉是調用
OnServiceDiscoverListener:當services被發現的時候調用
OnDataAvailableListener:當有數據交互的時候調用
這裏有個問題了,services是啥,是幹神馬的?
看了大神的解釋,還是一頭霧水啊。然後我就去看了BLE藍牙的協議棧和其他N種東西,搞明白了他。
services是這樣滴。每個IBeacon 都是基於BLE的,而BLE信息交互的時候,需要有個東西當接口啊,services就是這種東東。
就例如 BLE要做一個鐘錶,那就得有個service能不斷的發送當前時間給顯示器,like
同理,我們和IBeacon 通信,就是去調用BLE裏的某個Service。
我們知道IBeacon裏的參數有好幾個呢,一個service夠嗎?跟你說,夠了。
每個service下邊還有多個Characteristic,就相當於service是端口,Characteristic是程序,不同的程序處理不同的東西,但數據都通過同一個端口(service)進出。
當然,service下邊還有多個Descriptor,就是描述符,沒啥大用。
對了,services,Characteristic這些東東,都是通過UUID來標識的,就相當於UUID是service、Characteristic的名字一樣。
下邊我們看看大神定義的接口都是怎麼工作的。
1 // Implements callback methods for GATT events that the app cares about. For example, 2 // connection change and services discovered. 3 private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() 4 { 5 @Override 6 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) 7 { 8 Log.e(TAG, "onConnectionStateChange完成"); 9 if (newState == BluetoothProfile.STATE_CONNECTED) 10 { 11 if (mOnConnectListener != null) 12 mOnConnectListener.onConnect(gatt); 13 Log.i(TAG, "Connected to GATT server."); 14 // Attempts to discover services after successful connection. 15 Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); 16 17 } 18 else if (newState == BluetoothProfile.STATE_DISCONNECTED) 19 { 20 if (mOnDisconnectListener != null) 21 mOnDisconnectListener.onDisconnect(gatt); 22 Log.i(TAG, "Disconnected from GATT server."); 23 } 24 } 25 26 @Override 27 public void onServicesDiscovered(BluetoothGatt gatt, int status) 28 { 29 Log.e(TAG, "onServicesDiscovered完成"); 30 if (status == BluetoothGatt.GATT_SUCCESS && mOnServiceDiscoverListener != null) 31 { 32 mOnServiceDiscoverListener.onServiceDiscover(gatt); 33 } 34 else 35 { 36 Log.w(TAG, "onServicesDiscovered received: " + status); 37 } 38 } 39 40 @Override 41 public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) 42 { 43 Log.e(TAG, "onCharacteristicRead完成"); 44 if (mOnDataAvailableListener != null) 45 mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status); 46 } 47 48 @Override 49 public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) 50 { 51 Log.e(TAG, "onCharacteristicWrite完成"); 52 if (mOnDataAvailableListener != null) 53 mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic, status); 54 } 55 @Override 56 public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) 57 { 58 Log.e(TAG, "onCharacteristicChanged完成"); 59 if (mOnDataAvailableListener != null) 60 mOnDataAvailableListener.onCharacteristicChanged(gatt, characteristic); 61 } 62 };
這裏我改了下代碼,
1 public interface OnDataAvailableListener 2 { 3 public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status); 4 5 public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); 6 7 public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status); 8 }
OnConnectListener、OnDisconnectListener這兩個接口,一看就是一對
onCharacteristicRead、onCharacteristicWrite、onCharacteristicChanged這三個,從函數名上也能看出作用來。
那麼,定義好這些個listener,嗯,C#裏邊就是委託了,我就就得看看他是怎麼工作的了。
本文一開始就說connect函數了,當connect成功後,就回去調用 onConnectionStateChange(連接狀態改變事件),然後根據某值,分離出是連接成功還是連接失敗。
在大神的代碼了,我看到了調用OnConnectListener,但是怎麼發現service呢。
大神開了個玩笑啊,將最重要的一句代碼寫在了Log.i裏邊,我狂暈啊,找了好半天呢。
mBluetoothGatt.discoverServices()就這句。。。。。。解釋一下這句代碼?——發現service
發現services,發現的services在哪?
好吧,android還是調用回調,onServicesDiscovered
發現services完成後,調用onServiceDiscover,這樣我們就能獲得BluetoothGatt,然後調用BluetoothGatt.getServices()獲取所有的services了,當然你還可以根據你所開發的IBeacon的文檔中定義的service的UUID,通過調用BluetoothGatt.getService(某個UUID)直接找這個service。
我所用的service的UUID是 0000fff0-0000-1000-8000-00805f9b34fb
我們獲取了service,就可以通信了。
1 private void displayGattServices(List<BluetoothGattService> gattServices) 2 { 3 if (gattServices == null) 4 return; 5 6 for (BluetoothGattService gattService : gattServices) 7 { 8 //-----Service的字段信息-----// 9 int type = gattService.getType(); 10 Log.e(TAG, "-->service type:" + Utils.getServiceType(type)); 11 Log.e(TAG, "-->includedServices size:" + gattService.getIncludedServices().size()); 12 Log.e(TAG, "-->service uuid:" + gattService.getUuid()); 13 14 //-----Characteristics的字段信息-----// 15 List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); 16 for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) 17 { 18 Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid()); 19 20 int permission = gattCharacteristic.getPermissions(); 21 Log.e(TAG, "---->char permission:" + Utils.getCharPermission(permission)); 22 23 int property = gattCharacteristic.getProperties(); 24 Log.e(TAG, "---->char property:" + Utils.getCharPropertie(property)); 25 26 byte[] data = gattCharacteristic.getValue(); 27 if (data != null && data.length > 0) 28 { 29 Log.e(TAG, "---->char value:" + new String(data)); 30 } 31 32 //UUID_KEY_DATA是可以跟藍牙模塊串口通信的Characteristic 33 if (gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)) 34 { 35 //測試讀取當前Characteristic數據,會觸發mOnDataAvailable.onCharacteristicRead() 36 mHandler.postDelayed(new Runnable() 37 { 38 @Override 39 public void run() 40 { 41 mBLE.readCharacteristic(gattCharacteristic); 42 } 43 }, 500); 44 45 //接受Characteristic被寫的通知,收到藍牙模塊的數據後會觸發mOnDataAvailable.onCharacteristicWrite() 46 mBLE.setCharacteristicNotification(gattCharacteristic, true); 47 //設置數據內容 48 byte[] bytes = new byte[6]; 49 50 bytes[0] = 1; 51 bytes[1] = 2; 52 bytes[2] = 3; 53 bytes[3] = 4; 54 bytes[4] = 5; 55 bytes[5] = 6; 56 gattCharacteristic.setValue("123456"); 57 //往藍牙模塊寫入數據 58 mBLE.writeCharacteristic(gattCharacteristic); 59 Log.v(TAG, "寫入"); 60 } 61 62 //-----Descriptors的字段信息-----// 63 List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors(); 64 for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) 65 { 66 Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid()); 67 int descPermission = gattDescriptor.getPermissions(); 68 Log.e(TAG, "-------->desc permission:" + Utils.getDescPermission(descPermission)); 69 70 byte[] desData = gattDescriptor.getValue(); 71 if (desData != null && desData.length > 0) 72 { 73 Log.e(TAG, "-------->desc value:" + new String(desData)); 74 } 75 } 76 } 77 }// 78 79 }
大神的代碼裏,把所有的services,Characteristic都顯示出來了,每個Characteristic也都讀取了一遍。然後又在 UUID_KEY_DATA 表示的那個Characteristic裏邊寫了點什麼。
一開始我不太懂,爲啥還得等500毫秒,後來我知道了,BLE是單雙工通信的。
解釋一下,“雙工通信”是指的兩邊都可以發送信息,也都可以接收信息,“單”代表通信雙方不能同時收發信息。
就是說,我發送信息(讀、寫)給IBeacon,在IBeacon返回信息之前,我不能有任何操作。
好了,言歸正傳。
我們只看到了mBLE.readCharacteristic(gattCharacteristic);mBLE.writeCharacteristic(gattCharacteristic);,但是讀寫出來的數據呢?
在這個mBLE.setCharacteristicNotification(gattCharacteristic, true);之前的註釋裏,我們看到
//接受Characteristic被寫的通知,收到藍牙模塊的數據後會觸發mOnDataAvailable.onCharacteristicWrite()
好吧,我們知道了,他會去調用mOnDataAvailable裏的函數。
大體流程就是這樣滴。