android IBeacon 開發(二)修改IBeacon參數

開發(一)中,我們介紹了怎麼掃描到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裏的函數。

大體流程就是這樣滴。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章