Android 低功耗蓝牙的那点事详解手机开发

近期项目使用到了蓝牙技术,菜鸟一枚,网上各种找资料,发现不是不全就是过时,要么就是抄袭转载,真实醉了,现在将这一块的东西整理出来,供大家参考。

基本概念

Android中的蓝牙分两种:经典蓝牙、低功耗蓝牙。

  1. 二者本质上没有太多区别,可以理解为后者是前者的升级优化版本。对于API上的实现区别还是很大的。
  2. 工作流程:发现设备->配对/绑定设备->建立连接->数据通信。
    至于底层如何工作,本人不了解,也不是本文关注的重点。
  3. 官方文档:https://developer.android.com/guide/topics/connectivity/bluetooth.html?hl=zh-cn

重要实例

  1. 经典蓝牙聊天实例:https://github.com/googlesamples/android-BluetoothChat
  2. 低功耗蓝牙:https://github.com/googlesamples/android-BluetoothLeGatt
  3. 作为外设(API>=21):https://github.com/googlesamples/android-BluetoothAdvertisements
  4. 基础概念讲解:http://blog.csdn.net/qinxiandiqi/article/details/40741269
  5. 深入理论:http://www.race604.com/android-ble-in-action/

注意事项

  1. 低功耗蓝牙(BLE)Android 4.3(API 18)以上才支持
  2. 使用蓝牙需要权限
    <uses-permission android:name="android.permission.BLUETOOTH" /> 
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  3. 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" />

    官方文档:https://developer.android.com/guide/topics/connectivity/bluetooth-le.html?hl=zh-cn

  4. 低功耗蓝牙要声明特征,或者代码判断
    // 如果为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(); 
    }
  5. 经典蓝牙连接成功后获取一个socket连接得到输入输出流进行通信,低功耗通过特征(具体实现不知道是什么)
  6. 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: [email protected] 
*/ 
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 [email protected] BluetoothGatt#discoverServices()} completes successfully. 
* 
* @return A [email protected] 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; 
} 
}

总结

项目还在进行中,遇到的问题将会持续抛出,完善此文档。



原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/3192.html

(0)
上一篇 2021年7月16日
下一篇 2021年7月16日

相关推荐

发表回复

登录后才能评论