这里只要是Android设备与BLE设备的通讯都可以共用,只需要该的就是uuid的值,还有就是ble设备提供商要出文档协议,看看是如何发命令跟接收命令的。
BleUtil工具中,有些地方我感觉还是要提示下
1、characterUUID1 、characterUUID2 、descriptorUUID 这三个是对应的收发命令的,跟找到要操作的BluetoothGattDescriptor(特性)。
在做这个项目的时候ble设备提供商给的文档中uuid,是短的,我实际我打印出来的是长的。其实短的那种是ios来的,而android就不一样咯。可以参考:Android与IOS的UUID的区别
2、sendWorkModel、sendStrength 这两个方法是用来发送命令的,传值都是byte[]数组;而接收命令的话通过receiveData方法进行解析得到的byte[]。这三个方法都是需要根据不同设备协议进行修改,这里只是为了案例展示。总的来说就是收发命令都是byte[]
关键概念
Generic Attribute Profile (GATT)
通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。
Attribute Protocol (ATT)
GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。
每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。
Characteristic
Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。
Descriptor
对Characteristic的描述,例如范围、计量单位等。
Service
Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,
它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement”的Characteristic。
角色和职责
Android设备与BLE设备交互有两组角色:
中心设备和外围设备(Central vs. peripheral);
GATT server vs. GATT client.
Central vs. peripheral:
中心设备和外围设备的概念针对的是BLE连接本身。
Central角色负责scan advertisement。而peripheral角色负责make advertisement。
GATT server vs. GATT client:
这两种角色取决于BLE连接成功后,两个设备间通信的方式。
举例说明:
现有一个活动追踪的BLE设备和一个支持BLE的Android设备。
Android设备支持Central角色,而BLE设备支持peripheral角色。
创建一个BLE连接需要这两个角色都存在,都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。
当连接建立后,它们之间就需要传输GATT数据。
谁做server,谁做client,则取决于具体数据传输的情况。
例如,如果活动追踪的BLE设备需要向Android设备传输sensor数据,则活动追踪器自然成为了server端;
而如果活动追踪器需要从Android设备获取更新信息,则Android设备作为server端可能更合适。
权限及feature
和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,
如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:
1 | <uses-permission android:name="android.permission.BLUETOOTH"/> |
除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:
1 | <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> |
按时required为true时,则应用只能在支持BLE的Android设备上安装运行;
required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature
通讯设备的主要步骤
设置权限—>打开蓝牙—>扫描设备—>连接设备—>读写数据+通知设备的状态改变—>断开设备
BluetoothGatt的服务层次
BluetoothGatt—>BluetoothGattService(服务)—>BluetoothGattCharacteristic(特征)—>BluetoothGattDescriptor(特性)
下面的就是重点啦!工具类,工具类,工具类好听的话说三遍1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Created by shaolin on 6/17/16.
*/
(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class BleUtil {
private static final String TAG = "BleUtil";
private static final long SCAN_PERIOD = 10000;
public static String characterUUID1 = "0000fff2-0000-1000-8000-00805f9b34fb";//APP发送命令
public static String characterUUID2 = "0000fff1-0000-1000-8000-00805f9b34fb";//BLE用于回复命令
private static String descriptorUUID = "00002902-0000-1000-8000-00805f9b34fb";//BLE设备特性的UUID
public static byte[] workModel = {0x02, 0x01};
private Context mContext;
private static BleUtil mInstance;
//作为中央来使用和处理数据;
private BluetoothGatt mGatt;
private BluetoothManager manager;
private BTUtilListener mListener;
private BluetoothDevice mCurDevice;
private BluetoothAdapter mBtAdapter;
private List<BluetoothDevice> listDevice;
private List<BluetoothGattService> serviceList;//服务
private List<BluetoothGattCharacteristic> characterList;//特征
private BluetoothGattService service;
private BluetoothGattCharacteristic character1;
private BluetoothGattCharacteristic character2;
public static synchronized BleUtil getInstance() {
if (mInstance == null) {
mInstance = new BleUtil();
}
return mInstance;
}
public void setContext(Context context) {
mContext = context;
init();
}
public void init() {
listDevice = new ArrayList<>();
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
showToast("BLE不支持此设备!");
((Activity) mContext).finish();
}
manager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
//注:这里通过getSystemService获取BluetoothManager,
//再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。
if (manager != null) {
mBtAdapter = manager.getAdapter();
}
if (mBtAdapter == null || !mBtAdapter.isEnabled()) {
mBtAdapter.enable();
/*Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mContext.startActivity(enableBtIntent);*/
}
}
//扫描设备的回调
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
((Activity) mContext).runOnUiThread(new Runnable() {
public void run() {
if (!listDevice.contains(device)) {
//不重复添加
listDevice.add(device);
mListener.onLeScanDevices(listDevice);
Log.e(TAG, "device:" + device.toString());
}
}
});
}
};
//扫描设备
public void scanLeDevice(final boolean enable) {
if (enable) {
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
public void run() {
stopScan();
Log.e(TAG, "run: stop");
}
}, SCAN_PERIOD);
startScan();
Log.e(TAG, "start");
} else {
stopScan();
Log.e(TAG, "stop");
}
}
//开始扫描BLE设备
private void startScan() {
mBtAdapter.startLeScan(mLeScanCallback);
mListener.onLeScanStart();
}
//停止扫描BLE设备
private void stopScan() {
mBtAdapter.stopLeScan(mLeScanCallback);
mListener.onLeScanStop();
}
//返回中央的状态和周边提供的数据
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
Log.e(TAG, "onConnectionStateChange");
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.e(TAG, "STATE_CONNECTED");
mListener.onConnected(mCurDevice);
gatt.discoverServices(); //搜索连接设备所支持的service
break;
case BluetoothProfile.STATE_DISCONNECTED:
mListener.onDisConnected(mCurDevice);
disConnGatt();
Log.e(TAG, "STATE_DISCONNECTED");
break;
case BluetoothProfile.STATE_CONNECTING:
mListener.onConnecting(mCurDevice);
Log.e(TAG, "STATE_CONNECTING");
break;
case BluetoothProfile.STATE_DISCONNECTING:
mListener.onDisConnecting(mCurDevice);
Log.e(TAG, "STATE_DISCONNECTING");
break;
}
super.onConnectionStateChange(gatt, status, newState);
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "onServicesDiscovered");
if (status == BluetoothGatt.GATT_SUCCESS) {
serviceList = gatt.getServices();
for (int i = 0; i < serviceList.size(); i++) {
BluetoothGattService theService = serviceList.get(i);
Log.e(TAG, "ServiceName:" + theService.getUuid());
characterList = theService.getCharacteristics();
for (int j = 0; j < characterList.size(); j++) {
String uuid = characterList.get(j).getUuid().toString();
Log.e(TAG, "---CharacterName:" + uuid);
if (uuid.equals(characterUUID1)) {
character1 = characterList.get(j);
} else if (uuid.equals(characterUUID2)) {
character2 = characterList.get(j);
setNotification();
}
}
}
}
super.onServicesDiscovered(gatt, status);
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.e(TAG, "onCharacteristicRead");
super.onCharacteristicRead(gatt, characteristic, status);
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.e(TAG, "onCharacteristicWrite");
super.onCharacteristicWrite(gatt, characteristic, status);
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.e(TAG, "onCharacteristicChanged");
// 这里是可以监听到设备自身或者手机改变设备的一些数据修改h通知
receiveData(characteristic);
super.onCharacteristicChanged(gatt, characteristic);
}
};
//获取设备指定的特征中的特性,其中对其进行监听, setCharacteristicNotification与上面的回调onCharacteristicChanged进行一一搭配
private void setNotification() {
mGatt.setCharacteristicNotification(character2, true);
BluetoothGattDescriptor descriptor = character2.getDescriptor(UUID.fromString(descriptorUUID));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mGatt.writeDescriptor(descriptor);
}
//接收数据,对其进行处理
private void receiveData(BluetoothGattCharacteristic ch) {
byte[] bytes = ch.getValue();
int cmd = bytes[0];
int agree = bytes[1];
switch (cmd) {
case 1:
mListener.onStrength(agree);
Log.e(TAG, "手机通知BLE设备强度:" + agree);
break;
case 2:
mListener.onModel(agree);
Log.e(TAG, "工作模式:" + agree);
break;
case 3:
mListener.onStrength(agree);
Log.e(TAG, "设备自身通知改变强度:" + agree);
break;
}
}
//连接设备
public void connectLeDevice(int devicePos) {
mBtAdapter.stopLeScan(mLeScanCallback);
mCurDevice = listDevice.get(devicePos);
checkConnGatt();
}
//发送进入工作模式请求
public void sendWorkModel() {
if (character1 != null) {
character1.setValue(workModel);
mGatt.writeCharacteristic(character1);
}
}
//发送强度
public void sendStrength(int strength) {
byte[] strengthModel = {0x01, (byte) strength};
if (character1 != null) {
character1.setValue(strengthModel);
mGatt.writeCharacteristic(character1);
}
}
//检查设备是否连接了
private void checkConnGatt() {
if (mGatt == null) {
mGatt = mCurDevice.connectGatt(mContext, true, mGattCallback);
mListener.onConnecting(mCurDevice);
} else {
mGatt.connect();
mGatt.discoverServices();
}
}
// 断开设备连接
private void disConnGatt() {
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
mGatt = null;
listDevice = new ArrayList<>();
mListener.onLeScanDevices(listDevice);
}
}
private void showToast(String message) {
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
}
public void setBTUtilListener(BTUtilListener listener) {
mListener = listener;
}
public interface BTUtilListener {
void onLeScanStart(); // 扫描开始
void onLeScanStop(); // 扫描停止
void onLeScanDevices(List<BluetoothDevice> listDevice); //扫描得到的设备
void onConnected(BluetoothDevice mCurDevice); //设备的连接
void onDisConnected(BluetoothDevice mCurDevice); //设备断开连接
void onConnecting(BluetoothDevice mCurDevice); //设备连接中
void onDisConnecting(BluetoothDevice mCurDevice); //设备连接失败
void onStrength(int strength); //给设备设置强度
void onModel(int model); //设备模式
}
}