近期项目使用到了蓝牙技术,菜鸟一枚,网上各种找资料,发现不是不全就是过时,要么就是抄袭转载,真实醉了,现在将这一块的东西整理出来,供大家参考。
基本概念
Android中的蓝牙分两种:经典蓝牙、低功耗蓝牙。
- 二者本质上没有太多区别,可以理解为后者是前者的升级优化版本。对于API上的实现区别还是很大的。
- 工作流程:发现设备->配对/绑定设备->建立连接->数据通信。 至于底层如何工作,本人不了解,也不是本文关注的重点。
- 官方文档:developer.android.com/guide/topic…
重要实例
- 经典蓝牙聊天实例:github.com/googlesampl…
- 低功耗蓝牙:github.com/googlesampl…
- 作为外设(API>=21):github.com/googlesampl…
- 基础概念讲解:blog.csdn.net/qinxiandiqi…
- 深入理论:www.race604.com/android-ble…
注意事项
-
低功耗蓝牙(BLE)Android 4.3(API 18)以上才支持
-
使用蓝牙需要权限
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
-
Android 5.0(API 21) 扫描蓝牙需要定位权限,否则扫描不到设备,实际使用时候发现 5.0不需要也可以扫描,Android 6.0(API 23)以上必须(不知道什么原因,测试机器:MI 2,知道原因的可告知)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 或 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
低功耗蓝牙要声明特征,或者代码判断
// 如果为true表示只能在支持低功耗蓝牙的设备上使用,如果不支持的设备也可以使用,采用代码判断 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> // 代码判断 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); }
-
经典蓝牙连接成功后获取一个socket连接得到输入输出流进行通信,低功耗通过特征(具体实现不知道是什么)
-
Android 5.0(API 21)之前不能当成外设(蓝牙耳机、音响等)来使用,只能作为中心即主机
低功耗蓝牙
现在蓝牙开发基本上都是低功耗蓝牙,比如心率设备、耳机设备、手环,所以我们先从重要的开始,讲讲低功耗蓝牙的使用,后面在完善经典蓝牙。
声明权限
创建项目在AndroidManifest.xml中声明权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lowett.android">
// 定位权限第二个包含第一个,所以这里就声明了一个,两个都声明也可以
<!-- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
// 是否必须支持低功耗蓝牙,此处不必须
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="false"/>
// 是有gps硬件,这个现在的智能手机没有不支持的吧
<uses-feature android:name="android.hardware.location.gps"/>
</manifest>
如果manifest中声明的蓝牙特性为false,那么在代码中监测是否支持BLE特性,
// 使用此检查确定BLE是否支持在设备上,然后你可以有选择性禁用BLE相关的功能
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
BluetoothAdapter
获取BluetoothManager得到蓝牙适配器BluetoothAdapter,注意这两个类都是系统级别,只有一个,代表了你手机上的蓝牙模块
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
如果获取到的Adapter为空说明不支持蓝牙,或者没有蓝牙模块
开启蓝牙
前面获取到了BluetoothAdapter,可以通过调用isEnabled()函数去检测是否开启了蓝牙,false表示没有开启,如果没有开启需要去启用,
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
代码执行完后,会有弹框提示用户是否启用,我们需要在onActivityResult()中判断返回
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == BluetoothLeManager.REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_OK) {
// something, 去扫描设备
startScan();
} else {
new AlertDialog.Builder(this)
.setMessage("请开启蓝牙,连接设备")
.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// something
}
})
.create()
.show();
}
}
}
扫描设备
低功耗蓝牙和经典蓝牙的扫描方式不同,如果熟悉经典蓝牙,那就要可能掉进坑了起不来了,哈哈。蓝牙扫描耗电比较严重,所以此处一定要记得在合适的实际停止扫描,比如定时停止、扫描到目标设备就停止(奇怪的是API为何不提供扫描时长的接口呢?)扫描时调用Adapter的startLeScan()方法,然而这个被标记为过时,API>=21被另一个取代。然后通过回掉得到扫描结果(经典蓝牙是广播)
public void startScan() {
// 初始化一个handler
initHandler();
if (!mScanning) {
if (scanRunnable == null) {
scanRunnable = new Runnable() {
@Override
public void run() {
stopScan();
}
};
}
// SCAN_PERIOD = 3 * 10 * 1000, 30s后停止扫面
mHandler.postDelayed(scanRunnable, SCAN_PERIOD);
// 新API
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// mBluetoothAdapter.getBluetoothLeScanner().startScan(this);
// }else {
// this 实现了BluetoothAdapter.LeScanCallback,即扫描结果回掉
mBluetoothAdapter.startLeScan(this);
// }
mScanning = true;
Log.i(TAG, "开始扫描,蓝牙设备");
}
}
回调函数
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
// 得到扫描结果
Log.i(TAG, "扫描到的设备, name=" + device.getName() + ",address=" + device.toString());
}
注意:device:代表外设即目标设备 rssi:设一个强度值,但是时负值,利用这个值通过公式可以算出离你的距离
scanRecord:广播数据,附加的数据,没用到
停止扫描
扫描完成务必停止,因为扫描不仅耗电,还影响连接速度,所以当要连接的时候,先停止扫描时必须的
public void stopScan() {
initHandler();
Log.i(TAG, "停止扫描,蓝牙设备");
if (mScanning) {
mScanning = false;
// 开始扫描的接口,要一样的不然停止不了
mBluetoothAdapter.stopLeScan(this);
}
if (scanRunnable != null) {
mHandler.removeCallbacks(scanRunnable);
scanRunnable = null;
}
}
连接设备
通常连接设备速度还是很快的,连接理论上来说也是无状态的,所以也需要一个定式任务来,保证超时停止。
public boolean connect(Context context, String address) {
if (mConnectionState == STATE_CONNECTED) {
return false;
}
if (mBluetoothAdapter == null || TextUtils.isEmpty(address)) {
return false;
}
initHandler();
if (connectRunnable == null) {
connectRunnable = new Runnable() {
@Override
public void run() {
mConnectionState = STATE_DISCONNECTING;
disconnect();
}
};
}
// 30s没反应停止连接
mHandler.postDelayed(connectRunnable, 30 * 1000);
stopScan();
// 获取到远程设备,
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
// 开始连接,第二个参数表示是否需要自动连接,true设备靠近自动连接,第三个表示连接回调
mBluetoothGatt = device.connectGatt(context, false, mGattCallback);
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
监听连接回调
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
// 连接状态变化
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) { // 连接上
mConnectionState = STATE_CONNECTED;
boolean success = mBluetoothGatt.discoverServices(); // 去发现服务
Log.i(TAG, "Attempting to start service discovery:" +
success);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // 连接断开
mConnectionState = STATE_DISCONNECTED;
}
}
// 发现服务
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i(TAG,"发现服务");
// 解析服务
discoverService();
}
}
// 特征读取变化
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
// 收到数据
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
mConnectionState = STATE_CONNECTED;
}
};
断开连接
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
mConnectionState = STATE_DISCONNECTED;
return;
}
// 连接成功的GATT
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
}
多设备连接
蓝牙适配器没有听过连接多个设备的接口,需要我们自己实现,即获取到目标设备的address后调用连接方法,自己维护多个BluetoothGatt即可(代码稍后放出)。
完整代码示例
正在做心率相关的蓝牙设备,此处代码发出来。
代码还在完善中,仅供参考,稳定代码将会发在Github中
package com.lowett.android.ble;
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.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.text.TextUtils;
import com.fit.android.utils.Logger;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
/**
* Email: fvaryu@qq.com
*/
public class BluetoothLeManager implements BluetoothAdapter.LeScanCallback {
public static final int REQUEST_ENABLE_BT = 1;
private static final int SCAN_PERIOD = 3 * 10 * 1000;
static final int STATE_DISCONNECTED = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_DISCONNECTING = 3;
public static final int STATE_CONNECTED = 4;
public static final int STATE_DISCOVER_SERVICES = 5;
@IntDef(value = {STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING, STATE_DISCOVER_SERVICES})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
}
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
private static BluetoothLeManager ourInstance = new BluetoothLeManager();
// private Context mContext;
private boolean is_inited = false;
private android.bluetooth.BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private int mConnectionState;
private BluetoothGatt mBluetoothGatt;
private boolean mScanning;
private Runnable scanRunnable;
private Handler mHandler;
private Runnable connectRunnable;
private OnDataReceivedListener mOnDataReceivedListener;
// 记得清掉监听 泄漏
private OnLeScanListener mOnLeScanListener;
private OnConnectionStateChangeListener mOnConnectionStateChangeListener;
private int retryCount;
public static BluetoothLeManager getInstance() {
return ourInstance;
}
private BluetoothLeManager() {
}
public void setOnDataReceivedListener(OnDataReceivedListener onDataReceivedListener) {
mOnDataReceivedListener = onDataReceivedListener;
}
public interface OnConnectionStateChangeListener {
void onConnectionStateChange(BluetoothGatt gatt, int status, int newState);
void onConnectTimeout();
}
public void setOnConnectionStateChangeListener(OnConnectionStateChangeListener onConnectionStateChangeListener) {
mOnConnectionStateChangeListener = onConnectionStateChangeListener;
}
public interface OnLeScanListener {
void onLeScan(BluetoothDevice device);
}
public interface OnDataReceivedListener {
void onDataReceived(int heart);
}
private void init() {
if (!is_inited) {
is_inited = true;
}
}
private boolean initialize(Context context) {
init();
if (!is_inited) {
throw new RuntimeException("请先调用init");
}
if (mBluetoothAdapter != null) {
return true;
}
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothLeManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
return mBluetoothAdapter != null;
}
public boolean isSupportBluetoothLe(Activity activity) {
return activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
}
public boolean isSupportBluetooth(Context context) {
return initialize(context);
}
public void enableBluetooth(Activity activity) {
if (!initialize(activity)) {
return;
}
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
public boolean isEnabled(Context context) {
return initialize(context) && mBluetoothAdapter.isEnabled();
}
private void initHandler() {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
}
}
public void startScan(OnLeScanListener onLeScanListener) {
initHandler();
if (!mScanning) {
if (scanRunnable == null) {
scanRunnable = new Runnable() {
@Override
public void run() {
stopScan();
}
};
}
mHandler.postDelayed(scanRunnable, SCAN_PERIOD);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// mBluetoothAdapter.getBluetoothLeScanner().startScan(this);
// }else {
mBluetoothAdapter.startLeScan(this);
// }
mScanning = true;
this.mOnLeScanListener = onLeScanListener;
Logger.i("开始扫描,蓝牙设备");
}
}
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
final BluetoothDevice tmp = device;
Logger.i("扫描到的设备, name=" + device.getName() + ",address=" + device.toString());
if (mOnLeScanListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mOnLeScanListener.onLeScan(tmp);
}
});
}
}
public void stopScan() {
initHandler();
mOnLeScanListener = null;
Logger.i("停止扫描,蓝牙设备");
if (mScanning) {
mScanning = false;
mBluetoothAdapter.stopLeScan(this);
}
if (scanRunnable != null) {
mHandler.removeCallbacks(scanRunnable);
scanRunnable = null;
}
}
private void removeConnectRunnable() {
if (connectRunnable != null) {
mHandler.removeCallbacks(connectRunnable);
connectRunnable = null;
}
}
private void retry() {
if (TextUtils.isEmpty(mBluetoothDeviceAddress)) {
return;
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (++retryCount < 11 && mConnectionState < STATE_CONNECTED) {
reconnect(retryCount);
mHandler.postDelayed(this, retryCount * 5 * 1000);
Logger.i("蓝牙重试次数=" + retryCount);
}
}
}, 2000);
}
private void reconnect(int count) {
if ((mConnectionState >= STATE_CONNECTING)) {
return;
}
if (connectRunnable == null) {
connectRunnable = new Runnable() {
@Override
public void run() {
mConnectionState = STATE_DISCONNECTING;
disconnect();
}
};
}
mHandler.postDelayed(connectRunnable, count * 3 * 1000);
if (mBluetoothDeviceAddress != null
&& mBluetoothGatt != null) {
mBluetoothGatt.connect();
mConnectionState = STATE_CONNECTING;
}
}
public boolean connect(Context context, String address) {
if (mConnectionState == STATE_CONNECTED) {
return false;
}
if (mBluetoothAdapter == null || TextUtils.isEmpty(address)) {
return false;
}
initHandler();
if (connectRunnable == null) {
connectRunnable = new Runnable() {
@Override
public void run() {
mConnectionState = STATE_DISCONNECTING;
disconnect();
if (mOnConnectionStateChangeListener != null) {
mOnConnectionStateChangeListener.onConnectTimeout();
}
}
};
}
mHandler.postDelayed(connectRunnable, 30 * 1000);
stopScan();
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(context, false, mGattCallback);
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Logger.i("BluetoothAdapter not initialized");
mConnectionState = STATE_DISCONNECTED;
return;
}
mBluetoothGatt.disconnect();
}
public void close() {
disconnect();
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
public void disconnectNoRetry() {
mBluetoothDeviceAddress = null;
close();
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
boolean success = mBluetoothGatt.discoverServices();
Logger.i("Attempting to start service discovery:" +
success);
removeConnectRunnable();
Logger.i("链接上");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Logger.i("断开链接");
retry();
}
if (mOnConnectionStateChangeListener != null) {
mOnConnectionStateChangeListener.onConnectionStateChange(gatt, status, newState);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Logger.i("发现服务");
discoverService();
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(characteristic);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
mConnectionState = STATE_CONNECTED;
broadcastUpdate(characteristic);
}
};
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
*
* @return A {@code List} of supported services.
*/
private List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
private void discoverService() {
if (mConnectionState == STATE_DISCOVER_SERVICES) {
return;
}
mConnectionState = STATE_DISCOVER_SERVICES;
List<BluetoothGattService> list = getSupportedGattServices();
/**
* BluetoothGattService = 00001800-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a00-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a01-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a04-0000-1000-8000-00805f9b34fb
BluetoothGattService = 00001801-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a05-0000-1000-8000-00805f9b34fb
心跳服务
BluetoothGattService = 0000180d-0000-1000-8000-00805f9b34fb
心跳特征
BluetoothGattCharacteristic = 00002a37-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a38-0000-1000-8000-00805f9b34fb
BluetoothGattService = 0000180f-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a19-0000-1000-8000-00805f9b34fb
// 设备名字
BluetoothGattService = 0000180a-0000-1000-8000-00805f9b34fb
BluetoothGattCharacteristic = 00002a28-0000-1000-8000-00805f9b34fb
*/
for (BluetoothGattService s : list) {
if (!SampleGattAttributes.HEART_RATE_SERVICES.equals(s.getUuid().toString())) {
continue;
}
final List<BluetoothGattCharacteristic> l = s.getCharacteristics();
for (final BluetoothGattCharacteristic bc : l) {
if (!SampleGattAttributes.HEART_RATE_MEASUREMENT.equals(bc.getUuid().toString())) {
continue;
}
Logger.i("连接蓝牙 服务成功");
setCharacteristicNotification(bc, true);
return;
}
}
}
private void broadcastUpdate(final BluetoothGattCharacteristic characteristic) {
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
}
int heartRate = characteristic.getIntValue(format, 1);
Logger.i(String.format(Locale.getDefault(), "Received heart rate: %d", heartRate));
if (mOnDataReceivedListener != null) {
mOnDataReceivedListener.onDataReceived(heartRate);
}
}
// else {
// For all other profiles, writes the data formatted in HEX.
// final byte[] data = characteristic.getValue();
// if (data != null && data.length > 0) {
// final StringBuilder stringBuilder = new StringBuilder(data.length);
// for (byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
// intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
// }
// }
/**
* 2、
*/
// sendBroadcast(intent);
}
public boolean isConnected() {
return mConnectionState == STATE_CONNECTED;
}
public String getConnectedAddress() {
if (!isConnected()) {
return null;
}
return mBluetoothDeviceAddress;
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Logger.i("BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
private void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Logger.i("BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public void clear() {
mOnLeScanListener = null;
mOnConnectionStateChangeListener = null;
}
public void release() {
// connectRunnable = null;
// mHandler = null;
// ourInstance = null;
}
}
总结
项目还在进行中,遇到的问题将会持续抛出,完善此文档。
坚持原创技术分享,您的支持将鼓励我继续创作! 赏微信打赏