Android传统蓝牙与低功耗蓝牙

区别

低功耗蓝牙又叫ble蓝牙,本文会用ble代替低功耗蓝牙(偷懒)

通用配置

要申请的权限
注意:android6.0以上还需要申请运行时权限

1
2
3
4
5
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--6.0以上要加定位权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

初始代码

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
public static final int BLUETOOTH_CLIENT_REQUEST = 12;
public static final int BLUETOOTH_SERVER_REQUEST = 11;
//---------------------------获取BluetoothAdapte和打开蓝牙部分--------------------------------
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
/*
//API等级18以上:Android 4.3以上可以用这种
BluetoothManager bluetoothManager =(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
*/
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
//判断是否支持低功耗蓝牙 返回true为不支持
}
if (mBluetoothAdapter == null) {
//返回null表示不支持蓝牙
return;
}
if (mBluetoothAdapter.isEnabled()) {
//判断蓝牙是否开启
return;
}
mBluetoothAdapter.enable();//静默开启蓝牙
//弹框开启蓝牙
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, BLUETOOTH_CLIENT_REQUEST);
//弹框开启蓝牙回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == BLUETOOTH_CLIENT_REQUEST) {
if (resultCode == RESULT_OK) {
//打开蓝牙成功
} else if (resultCode == RESULT_CANCELED) {
//打开蓝牙失败
}
}
}

传统蓝牙

简介

传统蓝牙的操作很像平时用的Socket通讯。连接需要验证uuid和设备配对(可选),当服务端和客户端在同一 RFCOMM 通道上分别拥有已连接的 BluetoothSocket 时,二者将被视为彼此连接。 这种情况下,每台设备都能获得输入和输出流式传输,并且可以开始传输数据,传输数据主要就是读写BluetoothSocket的输入输出流。如果两台设备之前尚未配对,则在连接过程中,Android 框架会自动向用户显示配对请求通知或对话框。因此,在尝试连接设备时,您的应用无需担心设备是否已配对。 您的 RFCOMM 连接尝试将被阻塞,直至用户成功完成配对或配对失败。
——参考Android开发文档

作为客户端

扫描设备

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
//广播接收器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private final BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
//扫描出来的蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
//搜索结束
}
}
};
//注册蓝牙搜索回调广播
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);//每搜索到一个设备就会发送一个该广播
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//当全部搜索完后发送该广播
filter.setPriority(Integer.MAX_VALUE);//设置优先级
registerReceiver(bluetoothReceiver, filter);//注册广播
unregisterReceiver(bluetoothReceiver);//销毁时取消注册广播
mBluetoothAdapter.startDiscovery();//开始搜索 一般12秒后自动停止
mBluetoothAdapter.cancelDiscovery();//取消搜索

客户端获取BluetoothSocket

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
private static final MUUID= UUID.fromString(78e7b909-717b-4f83-a504-7c1798ffa5cb");
//根据mac获取BluetoothDevice
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice("12:34:56:78:E2:42");
ConnectThread(mConnectThread = new ConnectThread(device);
mConnectThread.start();//开始获取BluetoothSocket
//关闭线程
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
/**
* 客户端获取 BluetoothSocke线程
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// 从BluetoothDevice获取 BluetoothSocket
try {
//不安全连接 不需要配对
tmp = device.createInsecureRfcommSocketToServiceRecord(MUUID);
//安全连接 需要配对
// tmp = device.createRfcommSocketToServiceRecord(MUUID);
} catch (IOException e) {
Log.e(TAG, "Socket create() failed"+ e.getMessage());
}
mmSocket = tmp;
}
public void run() {
// 取消发现设备
mBluetoothAdapter.cancelDiscovery();
// 创建蓝牙连接
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
//这里可以回调连接失败的情况
return;
}
startDataThread(mmSocket);//打开通讯线程
//这里可以回调连接成功的情况
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}

服务端

打开可被发现

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
//弹框打开可被发现
public static final int BLUETOOTH_SERVER_REQUEST = 11;
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//应用可以设置的最大持续时间为 3600 秒,值为 0 则表示设备始终可检测到。任何小于 0 或大于 3600 的值都会自动设为 120 秒
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);//设备始终可检测到
startActivityForResult(discoverableIntent, BLUETOOTH_SERVER_REQUEST);
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == BluetoothUtils.BLUETOOTH_SERVER_REQUEST) {
if (resultCode == RESULT_CANCELED) {
//打开被发现失败
} else {
//打开被发现成功
}
}
}
//静默开启 利用java的反射
try {
Method setDiscoverableTimeout = BluetoothAdapter.class.getDeclaredMethod("setDiscoverableTimeout", int.class);
setDiscoverableTimeout.setAccessible(true);
Method setScanMode =BluetoothAdapter.class.getDeclaredMethod("setScanMode", int.class,int.class);
setScanMode.setAccessible(true);
setDiscoverableTimeout.invoke(mBluetoothAdapter, 0);//设置可被扫描时间
setScanMode.invoke(mBluetoothAdapter,BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,0);//第一个参数是选择被发现模式 第二个参数是时间
} catch (Exception e) {
e.printStackTrace();
}

监听连接状态获取BluetoothSocket

通过调用accept()开始监听连接请求。
这一个阻塞调用。在一个连接被接受或一个异常出现时,它将会返回。只有当一个远程设备使用一个UUID发送了一个连接请求,并且该UUID和正在监听的服务器socket注册的UUID相匹配时,一个连接才会被接受。成功后,accept() 将会返回一个已连接的 BluetoothSocket。

调用close(),除非你想要接受更多的连接。这将释放服务器socket和它所有的资源,但是不会关闭 accept()返回的已连接的 BluetoothSocket。不同于TCP/IP,RFCOMM仅仅允许每一个通道上在某一时刻只有一个已连接的客户端,因此在大多数情况下在接受一个已连接的socket后,在BluetoothServerSocket上调用 close() 是非常必要的。

accept() 不应该再主活动UI线程上执行,因为它是一个阻塞调用,并且将会阻止任何与应用的交互行为。它通常在你的应用管理的一个新的线程中使用一个BluetoothServerSocket 或 BluetoothSocket 来完成所有工作。为了中止一个阻塞调用,例如accept(),从你的其他线程里在BluetoothServerSocket (或 BluetoothSocket) 上调用 close() ,然后阻塞调用就会立即返回。注意在 BluetoothServerSocket 或 BluetoothSocket 上所有的方法都是线程安全的。
——参考Android开发文档

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
/**
* 服务端获取 BluetoothSocke线程
*/
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
//不安全连接 不需要配对
tmp = device.createInsecureRfcommSocketToServiceRecord(MUUID);
//安全连接 需要配对
// tmp = device.createRfcommSocketToServiceRecord(MUUID);
} catch (IOException e) {
Log.e(TAG, "Socket listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// 保持监听 直到连接成功
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket accept() failed", e);
break;
}
if (socket != null) {
startDataThread(socket);//打开通讯线程
//这里可以回调连接成功的情况
break;
}
}
}
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}

数据传输部分

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
...
...
private void startDataThread(BluetoothSocket socket) {
if (mBluetoothDataThread != null) {
mBluetoothDataThread.cancel();
mBluetoothDataThread = null;
}
mBluetoothDataThread = new BluetoothDataThread(socket);
mBluetoothDataThread.start();
}
/**
* 蓝牙数据处理线程
*/
private class BluetoothDataThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public BluetoothDataThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
if (bytes != 0) {
//这里回调接收的数据
mBluetoothUtilsListener.onDataReceiver(buffer, bytes);
}
} catch (IOException e) {
//这里回调断开连接
break;
}
}
}
//发送数据
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
// 关闭连接
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}

BLE

简介

作为ble客户端系统需要android 4.3,而作为服务端则需要android5.0以上。ble的mac不是固定的。

GATT(通用属性配置)定义了一系列程序用来发现服务、特征、服务之间的关系 ,以及用来读取和写入特征值。

参数 说明
规范(Profile) 规范是由一个或多个服务构成结合成实现某一个特定的功能
服务(Service) 服务是一种或多种特征的集合,服务可分为两种类型:主要服务和次要服务。主要服务主要用来公开这个设备的基本可用功能。次要服务仅用来被主要服务其它次要服务所引用,为设备提供额外功能,
特征(Characteristic) 特征是一种或多种属性的集合,特征定义包括特征声明(Properties)、特征值(Value)也可以包含一个或多个特征描述符(Descriptor)
特征声明(Properties) 特征说明用来表面特征的相关属性 UUID 属性等
特征值(Value) 该特征返回的数据
特征描述符(Descriptor) 用来描述特征值的权限,计量单位等

客户端

扫描设备

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
//支持android4.3以上
MyLeScanCallback mMyScanCallback=new MyLeScanCallback();
mBluetoothAdapter.startLeScan(mMyScanCallback);//开始扫描
mBluetoothAdapter.stopLeScan(mMyScanCallback);//停止扫描
class MyLeScanCallback implements BluetoothAdapter.LeScanCallback {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
//扫描结果
}
}
//支持android5.0以上(api21)
MyScanCallback mMyScanCallback=new MyScanCallback();
BluetoothLeScanner bluetoothLeScanner=mBluetoothAdapter.getBluetoothLeScanner();
//过滤扫描
/*
List<ScanFilter> bleScanFilters = new ArrayList<>();
bleScanFilters.add(new ScanFilter.Builder().setServiceUuid(new ParcelUuid (SERVICE_UUID)).build());
ScanSettings bleScanSettings =new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
bluetoothLeScanner.startScan(bleScanFilters,bleScanSettings,mMyScanCallback);
*/
bluetoothLeScanner.startScan(mMyScanCallback);
bluetoothLeScanner.stopScan(mMyScanCallback);
class MyScanCallback extends ScanCallback {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
result.getScanRecord().toString();//设备信息
BluetoothDevice bluetoothDevice=result.getDevice();//扫描出的设备
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
}

连接设备

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
private BluetoothDevice device ;
private BluetoothGattCharacteristic mCH;
private BluetoothGattService service;
...
BluetoothGattCallback MyBluetoothGattCallback =new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {//是否连接成功
Log.e("蓝牙-----", "Connected to GATT server.");
mBluetoothGatt.discoverServices();//发现远程设备提供的服务及其特征和描述符。
} else {
Log.e("蓝牙-----", "断开连接");
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) { //当设备是否找到服务时,会回调该函数
if (status == BluetoothGatt.GATT_SUCCESS) {
bluetoothLeScanner.stopScan(mMyScanCallback);
//此处可以循环获得uuid
for (BluetoothGattService service : gatt.getServices()) {
service.getUuid().toString()
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
characteristic.getUuid()
for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors())
descriptor.getUuid()
}
}
service = mBluetoothGatt.getService(UUID.fromString("00002903-0000-1000-8000-00805f9b34fb"));
mCH = service.getCharacteristic(UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"));
setCharacteristicNotification(mCH, true);
} else {
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("蓝牙-----", "读成功: "+ new String(characteristic.getValue()));
} else {
Log.d("蓝牙-----", "读失败: ");
}
}
//写操作的回调
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e("蓝牙-----", "写入成功" + new String(characteristic.getValue()));
} else {
Log.e("蓝牙-----", "写入失败");
}
}
;
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
//通知回调
Log.e("蓝牙-----", "nCharacteristicChanged " + new String(characteristic.getValue()));
}
};
...
device .connectGatt(MainActivity.this, false,mMyBluetoothGattCallback);
.....
......
//断开连接
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.disconnect();
}
//回收资源
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
//获取BluetoothGattCharacteristic
public BluetoothGattCharacteristic getCharacteristic(UUID service, UUID characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return null;
}
BluetoothGattService gattService = mBluetoothGatt.getService(service);
return gattService.getCharacteristic(characteristic);
}
//写入数据
public void write(BluetoothGattCharacteristic characteristic, byte[] value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
characteristic.setValue(value);
mBluetoothGatt.writeCharacteristic(characteristic);
}
//读取数据
public void read(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
//设置通知
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
//官方规定接收通知描述符的UUID
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (descriptor != null) {//不需要回复的通知 //需要回复确认的通知
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
mBluetoothGatt.writeDescriptor(descriptor);
}
}

服务端

广播数据

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
private static final UUID SERVICE_UUID
= UUID.fromString("00002903-0000-1000-8000-00805f9b34fb");
.....
AdvertiseCallback callback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
//蓝牙广播开启成功
}
@Override
public void onStartFailure(int errorCode) {
//蓝牙广播开启失败
}
};
...
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setConnectable(true)//是否能连接
//.setTimeout()设置广播超时
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) //广播模式: 低功耗,平衡,低延迟
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) //发射功率级别: 极低,低,中,高
//广播数据(必须,广播启动就会发送)
AdvertiseData advertiseData = new AdvertiseData.Builder()
.setIncludeDeviceName(true)//广播蓝牙名称
.addServiceUuid(new ParcelUuid(SERVICE_UUID))//服务uuid
.setIncludeTxPowerLevel(true)//广播发射功率级别
.addManufacturerData(1,new byte[]{0x01}) //自定义数据
.build();
BluetoothLeAdvertiser bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, callback);

开启服务

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
private static final UUID SERVICE_UUID
= UUID.fromString("00002903-0000-1000-8000-00805f9b34fb");
private static final UUID CHAR_UUID
= UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
private BluetoothManager bluetoothManager;
...
final BluetoothGattServerCallback mBluetoothGattServerCallback=new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {//是否连接成功
Log.e(TAG, "服务端连接成功");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//断开连接
}
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
super.onServiceAdded(status, service);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"添加服务成功"+service.getUuid().toString());
}
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
Log.e(TAG, "onCharacteristicReadRequest" );
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, "yes".getBytes());// 响应客户端读取
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
//客户端写入
Log.e(TAG, "onCharacteristicWriteRequest"+"---"+new String(value));
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, "写入成功1".getBytes());// 响应客户端读取
characteristic.setValue("通知");
mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
}
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
Log.e(TAG, "onDescriptorReadRequest" );
mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, "读取成功2".getBytes());// 响应客户端读取
}
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
String valueStr = Arrays.toString(value);
Log.e(TAG, "onCharacteristicWriteRequest"+"---"+new String(value));
if (Arrays.toString(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE).equals(valueStr)) {
final BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
characteristic.setValue("通知");
mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
}
}
};
...
BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);//主要服务
//添加可读 可写 可通知characteristic
BluetoothGattCharacteristic characteristicRead = new BluetoothGattCharacteristic(CHAR_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE| BluetoothGattCharacteristic.PROPERTY_READ|BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_WRITE|BluetoothGattCharacteristic.PERMISSION_READ);
characteristicRead.addDescriptor(new BluetoothGattDescriptor(CHAR_UUID, BluetoothGattCharacteristic.PERMISSION_READ|BluetoothGattCharacteristic.PERMISSION_WRITE));//权限描述可选
service.addCharacteristic(characteristicRead);
if (bluetoothManager != null){
mBluetoothGattServer = bluetoothManager.openGattServer(BLEService.this, mBluetoothGattServerCallback);
mBluetoothGattServer.addService(service);
}

总结

相对于传统蓝牙 ble google官方文档和例子都感觉没讲的很清楚。坑比较多在此记录下。
2019年新年快乐~