上篇 :Android笔记系列--(1)传统蓝牙 socket通讯方式
整理了一下网上关于蓝牙的资料,几乎涵盖Android开发使用蓝牙的方方面面。以下有部分内容引用的是来自网上的博客,文末将添加这些引用的来源,如果填漏了可以告诉我。
本文练习源码:https://github.com/StarsAaron/BluetoothTestDemo
主要内容:
(1)BLE蓝牙的基础概念
(2)Android 各版本API的变化
(3)设备作为中心和外围模式的使用
(4)返回数据解析
蓝牙分为三种:
(1)Bluetooth Smart Ready(双模)标准蓝牙则无法与Bluetooth Smart相通
Central 发现并连接广播中的 Peripheral
在BLE中 ,Peripheral 通过广播的方式向Central提供数据是主要方式。Android API版本变化:
传统蓝牙搜索:// 设置广播信息过滤
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
// 注册广播接收器,接收并处理搜索结果,在onDestory中记得取消注册
registerReceiver(receiver, intentFilter);
// 寻找蓝牙设备,android会将查找到的设备以广播形式发出去
// startDiscovery 方法可以查找到传统蓝牙和Ble设备但是startDiscovery的回调无法返回
// Ble的广播,所以无法通过广播识别设备,且startDiscovery扫描Ble的效率比StartLeScan低很多。
mBluetoothAdapter.startDiscovery();
//4.3以下的通过广播方式来搜索
private BroadcastReceiver receiver = 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);
Log.i("BroadcastReceiver--", device.getName());
}
}
};
4.3 新增的Ble蓝牙搜索接口:
// 4.3(API 18) 蓝牙搜索使用下面
mBluetoothAdapter.startLeScan(mLeScanCallback);
/**
* 旧回调,参数scanRecord是数据的字节数组,不够直观,要手动解析数据
*/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceList.addDevice(device);
Toast.makeText(MainActivity.this, device.getName() + device.getAddress(), Toast.LENGTH_SHORT).show();
Log.i(TAG, device.getName() + device.getAddress());
//这里的参数 scanRecord 就是广播数据,这里同时包含 广播数据 和 扫描响应数据 (如果有的话),所以长度一般就是 62 字节。
parseData(scanRecord);
}
});
}
};
//5.0 之后使用android.bluetooth.le 包新接口
BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(scanCallback);
/**
* 新添加的android.bluetooth.le 包新接口回调
*/
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, final ScanResult result) {
super.onScanResult(callbackType, result);
BluetoothDevice device = result.getDevice();
mLeDeviceList.addDevice(device);
Log.d(TAG, "Device name: " + device.getName());
Log.d(TAG, "Device address: " + device.getAddress());
Log.d(TAG, "Device service UUIDs: " + device.getUuids());
ScanRecord record = result.getScanRecord();
Log.d(TAG, "Record advertise flags: 0x" + Integer.toHexString(record.getAdvertiseFlags()));
Log.d(TAG, "Record Tx power level: " + record.getTxPowerLevel());
Log.d(TAG, "Record device name: " + record.getDeviceName());
Log.d(TAG, "Record service UUIDs: " + record.getServiceUuids());
Log.d(TAG, "Record service data: " + record.getServiceData());
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
@Override
public void onBatchScanResults(List results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
例如,在LED BUTTON示例中,0x1523作为服务的UUID,0x1524作为LED特性的UUID,0x1525作为按键状态特性的UUID。
8、profile(数据配置文件)Android BLE API
1、BluetoothGatt中心设备模式操作流程
权限声明:
如果您要声明自己的应用只适用于支持BLE的设备,请在应用清单中包含以下内容:
Android 5.0之前是android.hardware.bluetooth_le
不过,如果您想让应用程式适用于不支援BLE的装置,您仍应在应用的清单中加入这个元素,但required="false"设为required="false" 。
然后在运行时,您可以通过使用PackageManager.hasSystemFeature()确定BLE可用性:if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
android 6.0 以上的设备,获取蓝牙信息还需要定位权限
1、蓝牙开启
在使用蓝牙BLE之前,需要确认Android设备是否支持BLE feature(required为false时),另外要需要确认蓝牙是否打开。如果发现不支持BLE,则不能使用BLE相关的功能;如果支持BLE,但是蓝牙没打开,则需要打开蓝牙。代码示例如下://是否支持蓝牙模块
@TargetApi(18)
public static boolean isSupportBle(Context context) {
if(context != null && context.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le")) {
BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth");
return manager.getAdapter() != null;
} else {
return false;
}
}
//是否开启蓝牙
@TargetApi(18)
public static boolean isBleEnable(Context context) {
if(!isSupportBle(context)) {
return false;
} else {
BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth");
return manager.getAdapter().isEnabled();
}
}
//开启蓝牙
public static void enableBle(Activity act, int requestCode) {
Intent mIntent = new Intent("android.bluetooth.adapter.action.REQUEST_ENABLE");
act.startActivityForResult(mIntent, requestCode);
}
//蓝牙开启过程
if(isSupportBle(mContext)){
//支持蓝牙模块
if(!isBleEnable(mContext)){
//没开启蓝牙则开启
enableBle(mSelfActivity, 1);
}
} else{
//不支持蓝牙模块处理
}
//蓝牙开启回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//判断requestCode是否为开启蓝牙时传进去的值,再做相应处理
if(requestCode == 1){
//蓝牙开启成功后的处理
}
super.onActivityResult(requestCode, resultCode, data);
}
2、设备搜索
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
//对扫描到的设备进行处理,可以依据BluetoothDevice中的信息、信号强度rssi以及广播包和响应包组成的scanRecord字节数组进行分析
parseData(scanRecord);
}
});
//解析数据
public static ParsedAd parseData(byte[] adv_data) {
ParsedAd parsedAd = new ParsedAd();
ByteBuffer buffer = ByteBuffer.wrap(adv_data).order(ByteOrder.LITTLE_ENDIAN);
while (buffer.remaining() > 2) {
byte length = buffer.get();
if (length == 0)
break;
byte type = buffer.get();
length -= 1;
switch (type) {
case 0x01: // Flags
parsedAd.flags = buffer.get();
length--;
break;
case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
case 0x14: // List of 16-bit Service Solicitation UUIDs
while (length >= 2) {
parsedAd.uuids.add(UUID.fromString(String.format(
"%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
length -= 2;
}
break;
case 0x04: // Partial list of 32 bit service UUIDs
case 0x05: // Complete list of 32 bit service UUIDs
while (length >= 4) {
parsedAd.uuids.add(UUID.fromString(String.format(
"%08x-0000-1000-8000-00805f9b34fb", buffer.getInt())));
length -= 4;
}
break;
case 0x06: // Partial list of 128-bit UUIDs
case 0x07: // Complete list of 128-bit UUIDs
case 0x15: // List of 128-bit Service Solicitation UUIDs
while (length >= 16) {
long lsb = buffer.getLong();
long msb = buffer.getLong();
parsedAd.uuids.add(new UUID(msb, lsb));
length -= 16;
}
break;
case 0x08: // Short local device name
case 0x09: // Complete local device name
byte sb[] = new byte[length];
buffer.get(sb, 0, length);
length = 0;
parsedAd.localName = new String(sb).trim();
break;
case (byte) 0xFF: // Manufacturer Specific Data
parsedAd.manufacturer = buffer.getShort();
length -= 2;
break;
default: // skip
break;
}
if (length > 0) {
buffer.position(buffer.position() + length);
}
}
return parsedAd;
}
3、设备通信
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
//broadcastUpdate(intentAction);//发送状态
Log.d("连接", "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.d("", "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());//
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i("", "Disconnected from GATT server.");
// broadcastUpdate(intentAction);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
Log.e("discovered1", "onServicesDiscovered received: " +status);
BlueServiceList=gatt.getServices();
for(BluetoothGattService BS:BlueServiceList){
Log.e("服务",BS.getUuid().toString());
if(n==0){
gattDevice=gatt;
BluetoothGattService gattS=gattDevice.getService(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));
if(gattS!=null){
characteristic=gattS.getCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
gattDevice.setCharacteristicNotification(characteristic, true);
n++;
}
}
}
}else{
//Log.e("discovered0", "onServicesDiscovered received: " +status);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
byte[] data = characteristic.getValue();
Log.e("onCharacteristicRead", "onCharacteristicRead received: " +
new String(data));
//gatt.readCharacteristic(characteristic);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] data = characteristic.getValue();
Log.e("onCharacteristicChanged", "onCharacteristicChangedreceived: " + new String(data));
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
}
};
BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback);
//以下为获得Gatt后的相关操作对应的响应方法
//notification to onCharacteristicChanged;
bluetoothGatt.setCharacteristicNotification(characteristic, true);
//readCharacteristic to onCharacteristicRead;
bluetoothGatt.readCharacteristic(characteristic);
//writeCharacteristic to onCharacteristicWrite;
bluetoothGatt.wirteCharacteristic(mCurrentcharacteristic);
//connect and disconnect to onConnectionStateChange;
bluetoothGatt.connect();
bluetoothGatt.disconnect();
//readDescriptor to onDescriptorRead;
bluetoothGatt.readDescriptor(descriptor);
//writeDescriptor to onDescriptorWrite;
bluetoothGatt.writeDescriptor(descriptor);
//readRemoteRssi to onReadRemoteRssi;
bluetoothGatt.readRemoteRssi();
//executeReliableWrite to onReliableWriteCompleted;
bluetoothGatt.executeReliableWrite();
//获得某个 Gatt 外设提供的服务
bluetoothGatt.discoverServices();
//获得一个外设的所有服务, 存在一个 arraylist<>中
bluetoothGatt.getServices()
//通过UUID获得某个服务
BluetoothGattService gattS =gattDevice.getService(UUID uuid);
//通过UUID获得某个外设某个服务的一个Characteristic
characteristic = gattS.getCharacteristic(UUID uuid);
//设置当characteristic改变时通知,用来从外设获得发来的值
gatt.setCharacteristicNotification(characteristic, true);
//设备发来数据时回调函数
onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic)
//发送数据到设备
characteristic.setValue("0123");
gatt.writeCharacteristic(characteristic);
四、数据解析
BLE中有两种角色Central和Peripheral,也就是中心设备和外围设备,中心设备可以主动连接外围设备,外围设备发送广播或者被中心设备连接,外围通过广播被中心设备发现,广播中带有外围设备自身的相关信息。#define BLE_GAP_AD_TYPE_FLAGS 0x01 //< Flags for discoverability.
#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 //< Partial list of 16 bit service UUIDs.
#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 //< Complete list of 16 bit service UUIDs.
#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 //< Partial list of 32 bit service UUIDs.
#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 //< Complete list of 32 bit service UUIDs.
#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 //< Partial list of 128 bit service UUIDs.
#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 //< Complete list of 128 bit service UUIDs.
#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 //< Short local device name.
#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 //< Complete local device name.
#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A //< Transmit power level.
#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D //< Class of device.
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E //< Simple Pairing Hash C.
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F //< Simple Pairing Randomizer R.
#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 //< Security Manager TK Value.
#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 //< Security Manager Out Of Band Flags.
#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 //< Slave Connection Interval Range.
#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 //< List of 16-bit Service Solicitation UUIDs.
#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 //< List of 128-bit Service Solicitation UUIDs.
#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 //< Service Data - 16-bit UUID.
#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 //< Public Target Address.
#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 //< Random Target Address.
#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 //< Appearance.
#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A //< Advertising Interval.
#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B //< LE Bluetooth Device Address.
#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C //< LE Role.
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D //< Simple Pairing Hash C-256.
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E //< Simple Pairing Randomizer R-256.
#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 //< Service Data - 32-bit UUID.
#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 //< Service Data - 128-bit UUID.
#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D //< 3D Information Data.
#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF //< Manufacturer Specific Data.
五、参考链接
1、蓝牙Bluetooth BR/EDR 和 Bluetooth Smart 必需要知道的十个不同点
2、BLE简介和Android BLE编程
3、BLE广播数据解析
(4)设置连接回调
private void initAdvertiser() {
BluetoothLeAdvertiser advertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
if(advertiser == null){
Toast.makeText(this,"不支持周边服务模式",Toast.LENGTH_SHORT).show();
return;
}
// 广播设置
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(false).build();
ParcelUuid pUuid = new ParcelUuid(UUID.fromString("00001000-0000-1000-8000-00805f9b34fb"));
// 广播数据
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName(true)
.addServiceUuid(pUuid)
.addServiceData(pUuid,
"Data".getBytes(Charset.forName("UTF-8"))).build();
// 发出广播数据
advertiser.startAdvertising(settings, data, mAdvertiseCallback);
}
/**
* 广播回调
*/
final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
if (settingsInEffect != null) {
Log.d(TAG, "onStartSuccess TxPowerLv=" + settingsInEffect.getTxPowerLevel() + " mode=" + settingsInEffect.getMode()
+ " timeout=" + settingsInEffect.getTimeout());
} else {
Log.e(TAG, "onStartSuccess, settingInEffect is null");
}
Log.e(TAG, "onStartSuccess settingsInEffect" + settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
if (errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE) {
Toast.makeText(MainActivity.this, "Operation failed due to an internal error", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");
} else if (errorCode == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
Toast.makeText(MainActivity.this, "Operation failed due to an internal error", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising because no advertising instance is available.");
} else if (errorCode == ADVERTISE_FAILED_ALREADY_STARTED) {
Toast.makeText(MainActivity.this, "Operation failed due to an internal error", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising as the advertising is already started");
} else if (errorCode == ADVERTISE_FAILED_INTERNAL_ERROR) {
Toast.makeText(MainActivity.this, "Operation failed due to an internal error", Toast.LENGTH_LONG).show();
Log.e(TAG, "Operation failed due to an internal error");
} else if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
Toast.makeText(MainActivity.this, "This feature is not supported on this platform", Toast.LENGTH_LONG).show();
Log.e(TAG, "This feature is not supported on this platform");
} else {
Toast.makeText(MainActivity.this, "onStartFailure errorCode", Toast.LENGTH_LONG).show();
Log.e(TAG, "onStartFailure errorCode" + errorCode);
}
}
};
初始化GATT的服务
private void initServices(Context context) {
bluetoothGattServer = mBluetoothManager.openGattServer(context, bluetoothGattServerCallback);
BluetoothGattService service = new BluetoothGattService(UUID_SERVER,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
//add a read characteristic.
BluetoothGattCharacteristic characteristicRead = new BluetoothGattCharacteristic(UUID_CHARREAD,
BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ);
//add a descriptor
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UUID_DESCRIPTOR,
BluetoothGattCharacteristic.PERMISSION_WRITE);
characteristicRead.addDescriptor(descriptor);
service.addCharacteristic(characteristicRead);
//add a write characteristic.
BluetoothGattCharacteristic characteristicWrite = new BluetoothGattCharacteristic(UUID_CHARWRITE,
BluetoothGattCharacteristic.PROPERTY_WRITE |
BluetoothGattCharacteristic.PROPERTY_READ |
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_WRITE);
service.addCharacteristic(characteristicWrite);
bluetoothGattServer.addService(service);
Log.e(TAG, "2. initServices ok");
}
在 openGattServer 方法中,我们需要传入回调
配置数据交互回调
回调时间有:连接状态变化,收发消息,通知消息private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() {
/**
* 1.连接状态发生变化时
*/
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
super.onServiceAdded(status, service);
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset
, BluetoothGattCharacteristic characteristic) {
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset
, characteristic.getValue());
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
}
/**
* 3. onCharacteristicWriteRequest,接收具体的字节
*/
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId
, BluetoothGattCharacteristic characteristic, boolean preparedWrite
, boolean responseNeeded, int offset, byte[] requestBytes) {
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS
, offset, requestBytes);
//4.处理响应内容
onResponseToClient(requestBytes, device, requestId, characteristic);
}
/**
* 2.描述被写入时,在这里执行 bluetoothGattServer.sendResponse(device, requestId
* , BluetoothGatt.GATT_SUCCESS... 收,触发 onCharacteristicWriteRequest
*/
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId
, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded
, int offset, byte[] value) {
// now tell the connected device that this was all successfull
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset
, value);
}
/**
* 5.特征被读取。当回复响应成功后,客户端会读取然后触发本方法
*/
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset
, BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS
, offset, null);
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
}
@Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
super.onMtuChanged(device, mtu);
}
@Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
super.onExecuteWrite(device, requestId, execute);
}
};
处理来自客户端发来的数据和发送回复数据:
private void onResponseToClient(byte[] reqeustBytes, BluetoothDevice device, int requestId
, BluetoothGattCharacteristic characteristic) {
String msg = OutputStringUtil.transferForPrint(reqeustBytes);
Log.d("onResponseToClient", "4.收到:" + msg);
String str = new String(reqeustBytes) + " hello>";
characteristicRead.setValue(str.getBytes());
bluetoothGattServer.notifyCharacteristicChanged(device, characteristicRead, false);
Log.d("onResponseToClient", "4.响应:" + str);
}
交互流程:
(1) 当客户端开始写入数据时: 触发回调方法 onDescriptorWriteRequest通过日志,我们看看事件触发的顺序
1.onConnectionStateChange:device name = null, address = 74:32:DE:49:3C:28
1.onConnectionStateChange:status = 0, newState =2
2.onDescriptorWriteRequest:device name = null, address = 74:32:DE:49:3C:28
2.onDescriptorWriteRequest:requestId = 1, preparedWrite = false, responseNeeded = true, offset = 0, value = [01,00,],
3.onCharacteristicWriteRequest:device name = null, address = 74:32:DE:49:3C:28
3.onCharacteristicWriteRequest:requestId = 2, preparedWrite=false, responseNeeded=false, offset=0, value=[41,54,45,30,0D,]
4.onResponseToClient:device name = null, address = 74:32:DE:49:3C:28
4.onResponseToClient:requestId = 2
4.收到:ATE0
4.响应:ATE0 hello>
5.onNotificationSent:device name = null, address = 74:32:DE:49:3C:28
5.onNotificationSent:status = 0