本文简单结合两篇文章



在BLE协议中,有两个角色,周边(Periphery)和中央(Central),一个中央可以同时连接多个周边,但是一个周边某一时刻只能连接一个中央。但是不管是Periphery还是Central都是可以实现 GATT server 和 GATT client去传输数据,但是无法同时都是。


大概了解了概念后,看看Android BLE SDK的四个关键类(class):

a) BluetoothGattServer作为周边来提供数据;BluetoothGattServerCallback返回周边的状态。

b) BluetoothGatt作为中央来使用和处理数据;BluetoothGattCallback返回中央的状态和周边提供的数据。

因为我们讨论的是Android的BLE SDK,下面所有的BluetoothGattServer代表周边,BluetoothGatt代表中央。

          

一.创建一个周边(虽然目前周边API在Android手机上不工作,但还是看看)

 a)先看看周边用到的class,蓝色椭圆

android 蓝牙 inputStream android 蓝牙读取数据_Android

b)说明:

每一个周边BluetoothGattServer,包含多个服务Service,每一个Service包含多个特征Characteristic。

1.new一个特征:

character = new BluetoothGattCharacteristic(
UUID.fromString(characteristicUUID),
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);

2.new一个服务:service = new BluetoothGattService(UUID.fromString(serviceUUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);

3.把特征添加到服务:service.addCharacteristic(character);

4.获取BluetoothManager:manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

5.获取/打开周边:BluetoothGattServer server = manager.openGattServer(this,
new BluetoothGattServerCallback(){...}); 

6.把service添加到周边:server.addService(service);

7.开始广播service:Google还没有广播Service的API,等吧!!!!!所以目前我们还不能让一个Android手机作为周边来提供数据。


二.创建一个中央(这次不会让你失望,可以成功创建并且连接到周边的)

a)先看看中央用到的class,蓝色椭圆

android 蓝牙 inputStream android 蓝牙读取数据_Android_02


b)说明:

为了拿到中央BluetoothGatt,可要爬山涉水十八弯:

1.先拿到BluetoothManager:bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

2.再拿到BluetoothAdapt:btAdapter = bluetoothManager.getAdapter();

3.开始扫描:btAdapter.startLeScan( BluetoothAdapter.LeScanCallback);

4.从LeScanCallback中得到BluetoothDevice:public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {.....}

5.用BluetoothDevice得到BluetoothGatt:gatt = device.connectGatt(this, true, gattCallback);

终于拿到中央BluetoothGatt了,它有一堆方法(查API吧),调用这些方法,你就可以通过BluetoothGattCallback和周边BluetoothGattServer交互了。


官方有给出BLE 通信的sample ,下面是牛人简化了代码,简化得简单明了


本文来自 ,引用必须注明出处!

最近穿戴设备发展得很火,把相关技术也带旺了,其中一项是BLE(Bluetooth Low Energy)。BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接,超低功耗保持连接和传输数据,弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于穿戴设备。Android 4.3才开始支持BLE API,所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统,另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。

PS:我的i9100刷了4.4系统后,竟然也能跟BLE蓝牙模块通信。


BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value。一般来说,Characteristic是手机与BLE终端交换数据的关键,Characteristic有较多的跟权限相关的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE蓝牙模块竟然没有标准的Characteristic的PERMISSION。Characteristic的PROPERTY可以通过位运算符组合来设置读写属性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此读取PROPERTY后要分解成所用的组合(本文代码已含此分解方法)。


本文代码改自Android 4.3 Sample的BluetoothLeGatt,把冗余代码去掉,获取的BLE设备信息都通过Log,还有一些必要的读写蓝牙方法,应该算是简化到大家一看就可以懂了。本文代码可以到下载。接下来贴出本文运行的结果,首先是连接BLE设备后,枚举出设备所有Service、Characteristic、Descriptor,并且手机会往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb写入“send data->”字符串,BLE终端收到数据通过串口传到PC串口助手(见PC串口助手的截图):

04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service type:PRIMARY
 04-21 18:28:25.465: E/DeviceScanActivity(12254): -->includedServices size:0
 04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service uuid:00001800-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a00-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char property:READ
 04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a01-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a02-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a03-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
 04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char uuid:00002a04-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ
 04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service type:PRIMARY
 04-21 18:28:25.475: E/DeviceScanActivity(12254): -->includedServices size:0
 04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service uuid:00001801-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:00002a05-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:INDICATE
 04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
 04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service type:PRIMARY
 04-21 18:28:25.480: E/DeviceScanActivity(12254): -->includedServices size:0
 04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service uuid:0000ffe0-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:0000ffe1-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
 04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:READ|WRITE_NO_RESPONSE|NOTIFY|
 04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
 04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002901-0000-1000-8000-00805f9b34fb
 04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:26.025: E/DeviceScanActivity(12254): onCharRead BLE DEVICE read 0000ffe1-0000-1000-8000-00805f9b34fb -> 00

这里红字是由BluetoothGattCallback的onCharacteristicRead()回调而打出Log


android 蓝牙 inputStream android 蓝牙读取数据_android_03


以下Log是PC上的串口工具通过BLE模块发送过来,由BluetoothGattCallback的 onCharacteristicChanged()打出Log

04-21 18:30:18.260: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:18.745: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:19.085: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:19.350: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:19.605: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:19.835: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:20.055: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:20.320: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:20.510: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:20.735: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
 04-21 18:30:21.000: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone

接下来贴出本文核心代码:


1. public class DeviceScanActivity extends ListActivity {  
2. private final static String TAG = DeviceScanActivity.class.getSimpleName();  
3. private final static String UUID_KEY_DATA = "0000ffe1-0000-1000-8000-00805f9b34fb";  
4.   
5. private LeDeviceListAdapter mLeDeviceListAdapter;  
6. /**搜索BLE终端*/  
7. private BluetoothAdapter mBluetoothAdapter;  
8. /**读写BLE终端*/  
9. private BluetoothLeClass mBLE;  
10. private boolean mScanning;  
11. private Handler mHandler;  
12.   
13. // Stops scanning after 10 seconds.  
14. private static final long SCAN_PERIOD = 10000;  
15.   
16. @Override  
17. public void onCreate(Bundle savedInstanceState) {  
18. super.onCreate(savedInstanceState);  
19.         getActionBar().setTitle(R.string.title_devices);  
20. new Handler();  
21.   
22. // Use this check to determine whether BLE is supported on the device.  Then you can  
23. // selectively disable BLE-related features.  
24. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {  
25. this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();  
26.             finish();  
27.         }  
28.   
29. // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to  
30. // BluetoothAdapter through BluetoothManager.  
31. final BluetoothManager bluetoothManager =  
32.                 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);  
33.         mBluetoothAdapter = bluetoothManager.getAdapter();  
34.           
35. // Checks if Bluetooth is supported on the device.  
36. if (mBluetoothAdapter == null) {  
37. this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();  
38.             finish();  
39. return;  
40.         }  
41. //开启蓝牙  
42.         mBluetoothAdapter.enable();  
43.           
44. new BluetoothLeClass(this);  
45. if (!mBLE.initialize()) {  
46. "Unable to initialize Bluetooth");  
47.             finish();  
48.         }  
49. //发现BLE终端的Service时回调  
50.         mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);  
51. //收到BLE终端数据交互的事件  
52.         mBLE.setOnDataAvailableListener(mOnDataAvailable);  
53.     }  
54.   
55.   
56. @Override  
57. protected void onResume() {  
58. super.onResume();  
59.   
60. // Initializes list view adapter.  
61. new LeDeviceListAdapter(this);  
62.         setListAdapter(mLeDeviceListAdapter);  
63. true);  
64.     }  
65.   
66. @Override  
67. protected void onPause() {  
68. super.onPause();  
69. false);  
70.         mLeDeviceListAdapter.clear();  
71.         mBLE.disconnect();  
72.     }  
73.   
74. @Override  
75. protected void onStop() {  
76. super.onStop();  
77.         mBLE.close();  
78.     }  
79.       
80. @Override  
81. protected void onListItemClick(ListView l, View v, int position, long id) {  
82. final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);  
83. if (device == null) return;  
84. if (mScanning) {  
85.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
86. false;  
87.         }  
88.           
89.         mBLE.connect(device.getAddress());  
90.     }  
91.   
92. private void scanLeDevice(final boolean enable) {  
93. if (enable) {  
94. // Stops scanning after a pre-defined scan period.  
95. new Runnable() {  
96. @Override  
97. public void run() {  
98. false;  
99.                     mBluetoothAdapter.stopLeScan(mLeScanCallback);  
100.                     invalidateOptionsMenu();  
101.                 }  
102.             }, SCAN_PERIOD);  
103.   
104. true;  
105.             mBluetoothAdapter.startLeScan(mLeScanCallback);  
106. else {  
107. false;  
108.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
109.         }  
110.         invalidateOptionsMenu();  
111.     }  
112.   
113. /**
114.      * 搜索到BLE终端服务的事件
115.      */  
116. private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener(){  
117.   
118. @Override  
119. public void onServiceDiscover(BluetoothGatt gatt) {  
120.             displayGattServices(mBLE.getSupportedGattServices());  
121.         }  
122.           
123.     };  
124.       
125. /**
126.      * 收到BLE终端数据交互的事件
127.      */  
128. private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener(){  
129.   
130. /**
131.          * BLE终端数据被读的事件
132.          */  
133. @Override  
134. public void onCharacteristicRead(BluetoothGatt gatt,  
135. int status) {  
136. if (status == BluetoothGatt.GATT_SUCCESS)   
137. "onCharRead "+gatt.getDevice().getName()  
138. " read "  
139.                         +characteristic.getUuid().toString()  
140. " -> "  
141.                         +Utils.bytesToHexString(characteristic.getValue()));  
142.         }  
143.           
144. /**
145.          * 收到BLE终端写入数据回调
146.          */  
147. @Override  
148. public void onCharacteristicWrite(BluetoothGatt gatt,  
149.                 BluetoothGattCharacteristic characteristic) {  
150. "onCharWrite "+gatt.getDevice().getName()  
151. " write "  
152.                     +characteristic.getUuid().toString()  
153. " -> "  
154. new String(characteristic.getValue()));  
155.         }  
156.     };  
157.   
158. // Device scan callback.  
159. private BluetoothAdapter.LeScanCallback mLeScanCallback =  
160. new BluetoothAdapter.LeScanCallback() {  
161.   
162. @Override  
163. public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {  
164. new Runnable() {  
165. @Override  
166. public void run() {  
167.                     mLeDeviceListAdapter.addDevice(device);  
168.                     mLeDeviceListAdapter.notifyDataSetChanged();  
169.                 }  
170.             });  
171.         }  
172.     };  
173.   
174. private void displayGattServices(List<BluetoothGattService> gattServices) {  
175. if (gattServices == null) return;  
176.   
177. for (BluetoothGattService gattService : gattServices) {  
178. //-----Service的字段信息-----//  
179. int type = gattService.getType();  
180. "-->service type:"+Utils.getServiceType(type));  
181. "-->includedServices size:"+gattService.getIncludedServices().size());  
182. "-->service uuid:"+gattService.getUuid());  
183.               
184. //-----Characteristics的字段信息-----//  
185.             List<BluetoothGattCharacteristic> gattCharacteristics =gattService.getCharacteristics();  
186. for (final BluetoothGattCharacteristic  gattCharacteristic: gattCharacteristics) {  
187. "---->char uuid:"+gattCharacteristic.getUuid());  
188.                   
189. int permission = gattCharacteristic.getPermissions();  
190. "---->char permission:"+Utils.getCharPermission(permission));  
191.                   
192. int property = gattCharacteristic.getProperties();  
193. "---->char property:"+Utils.getCharPropertie(property));  
194.   
195. byte[] data = gattCharacteristic.getValue();  
196. if (data != null && data.length > 0) {  
197. "---->char value:"+new String(data));  
198.                 }  
199.   
200. //UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic  
201. if(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){                    
202. //测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()  
203. new Runnable() {  
204. @Override  
205. public void run() {  
206.                             mBLE.readCharacteristic(gattCharacteristic);  
207.                         }  
208. 500);  
209.                       
210. //接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()  
211. true);  
212. //设置数据内容  
213. "send data->");  
214. //往蓝牙模块写入数据  
215.                     mBLE.writeCharacteristic(gattCharacteristic);  
216.                 }  
217.                   
218. //-----Descriptors的字段信息-----//  
219.                 List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();  
220. for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {  
221. "-------->desc uuid:" + gattDescriptor.getUuid());  
222. int descPermission = gattDescriptor.getPermissions();  
223. "-------->desc permission:"+ Utils.getDescPermission(descPermission));  
224.                       
225. byte[] desData = gattDescriptor.getValue();  
226. if (desData != null && desData.length > 0) {  
227. "-------->desc value:"+ new String(desData));  
228.                     }  
229.                  }  
230.             }  
231. //  
232.   
233.     }  
234. }  
235.