Manifest文件权限配置说明
使用蓝牙,扫描蓝牙和设置蓝牙设置需要用到
<uses-permission android:name=”android.permission.BLUETOOTH”/>
<uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”/>
Android 5.0以上需要额外配置位置权限
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/>
<uses-permission android:name=”andriod.permission.ACCESS_FINE_LOCATION”/>
注意ACCESS_COARSE_LOCATION权限在6.0上需要动态获取,否则无法搜索出设备
<uses-feature android:name="android.bluetooth.le" android:required="true"/>
这个权限是为了区分不支持BLE的android设备无法运行该APP,required=true,只能在支持BLE的android设备上安装运行该APP,required=false,所有设备均可以运行
这个权限贴出来只作了解,具体使用还是在代码中判断设备是否支持BLE作逻辑结束比较好
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Log.e("yzh","不支持BLE功能")
finish();
}
蓝牙的交互流程
1.开启手机蓝牙模块搜索蓝牙信号
2.根绝device的uuid,name或者address找到需要连接设备
3.进行通道连接,遍历所有的通道中的服务,再遍历每个服务中的特征值
4.找到需要用的特征值进行读写操作
初始化蓝牙管理对象
BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter=bluetoothManager.getAdapter();
判断蓝牙功能是否开启,未开始默认开始
if(bluetoothAdapter==null||!bluetoothAdapter.isEnabled()){
bluetoothAdapter.enable();
}
蓝牙搜索
bluetoothAdapter.getBluetoothLeScanner().startScan(callback);
private ScanCallback callback =new ScanCallback() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onScanResult(int callbackType, ScanResult result) {
if(!list.contains(result.getDevice())){
Log.e("yzh","onScanResult--"+result.getDevice().getUuids()+"--"+result.getDevice().getAddress()+"--"+result.getDevice().getName());
list.add(result.getDevice());
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
Log.e("yzh","onBatchscanresult");
}
@Override
public void onScanFailed(int errorCode) {
Log.e("yzh","onScanFailed"+errorCode);
}
};
startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback),上面搜索方法还可以带两个参数,筛选搜索结果
public List<ScanFilter> getScanFilters(String[] uuids){
List<ScanFilter> filters=new ArrayList<>();
if(uuids!=null&&uuids.length>0){
for (String s:uuids){
ScanFilter.Builder builder1=new ScanFilter.Builder();
builder1.setServiceUuid(ParcelUuid.fromString(s));
// builder1.setDeviceName("QN-Scale");
ScanFilter filter=builder1.build();
filters.add(filter);
}
}
return filters;
}
public ScanSettings getScanSettings(int times){
ScanSettings.Builder builder = new ScanSettings.Builder();
builder.setReportDelay(times);
builder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
// builder.setMatchMode(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT);
ScanSettings settings=builder.build();
return settings;
}
这里发现以前的搜索方法被废弃了,查阅是5.0以上新增api之后。网上介绍蓝牙ble的文章相对较少,很多以前的代码都会使用这2个方法,在这里贴出来说明一下
bluetooth.startLeScan;
bluetooth.stopLeScan;
连接蓝牙
//关闭蓝牙扫描 防止阻塞
bluetoothAdapter.getBluetoothLeScanner().stopScan(callback);
//通过蓝牙地址获取蓝牙设备
device=bluetoothAdapter.getRemoteDevice("F4:51:41:55:04:FC");
//设备建立通道连接
bluetoothGatt=device.connectGatt(BleConnectActivity.this,false,bleGattCallback);
//连接回调
private BluetoothGattCallback bleGattCallback =new BluetoothGattCallback() {
@Override
public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyUpdate(gatt, txPhy, rxPhy, status);
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.e("yzh", "onConnectionStateChange"+"--status="+status);
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.e("yzh", "连接成功");
//连接成功之后扫描服务
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if(status==0){
gatt.connect();
}else{
//尝试重连的代码
gatt.disconnect();
gatt.close();
device.connectGatt(BleConnectActivity.this,false,bleGattCallback);
}
Log.e("yzh", "断开");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
Log.e("yzh", "onServicesDiscovered");
String uuid = null;
if (status == BluetoothGatt.GATT_SUCCESS) {
//读取服务和每个服务下对应的特征值
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
uuid = gattService.getUuid().toString();
Log.e("yzh", "serviceUUid--" + uuid);
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
uuid = gattCharacteristic.getUuid().toString();
Log.e("yzh", "characteristic--" + uuid+"--"+gattCharacteristic.getProperties());
}
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.e("yzh", "onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
//读取特征值携带的信息 下面用了很多方式来解读返回的byte数组 实际要与硬件方沟通对接
String uuid = null;
uuid = characteristic.getUuid().toString();
Log.e("yzh","--uid--"+uuid);
try{
Log.e("yzh","--value--"+bytesToHexString(characteristic.getValue()));
Log.e("yzh","GBKvalue"+ new String(characteristic.getValue(),"GBK").toString());
Log.e("yzh","UTF-8value"+ new String(characteristic.getValue(),"UTF-8").toString());
Log.e("yzh","unicode-8value"+ new String(characteristic.getValue(),"unicode").toString());
Log.e("yzh","ISO8859-1-8value"+ new String(characteristic.getValue(),"ISO8859-1").toString());
Log.e("yzh","base64value"+ android.util.Base64.encodeToString(characteristic.getValue(), android.util.Base64.DEFAULT));
}catch (Exception e){
}
final byte[] data = characteristic.getValue();
for(int i=0;i<data.length;i++){
Log.e("yzh", "detailValue--"+data[i] + "--");
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
};
注意:这里有几点存在疑问或者说没有找到最优解
1.connectGatt()方法第二个参数的解读是在蓝牙断开,会进行自动重连,但是在验证过程中并没有重连的现象
2.onConnectionStateChange方法里写的重连方法,在验证时一直无法重连,返回状态值133,gatt.disconnect,gatt.close是网上找的一些建议,但并未生效,找到一个有效方式是先开启搜索再连接,网上也有人是这样做的,最好用不同的硬件和不同的手机系统去验证这个问题。
蓝牙数据读取
bluetoothGatt.readCharacteristic(characteristic);
//在回调方法里面接受特征值里面的数据
onCharacteristicRead
蓝牙数据写入
characteristic.setValue()//传入需要写入的数据
bluetoothGatt.writeCharacteristic(characteristic);//往设备写入数据
//开启 Android 端接收通知的开关
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
//CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb"
//characteristic的Descriptor属性写入开启通知的数据,保证硬件数据变化时,主动往手机发送数据
BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor);
监听写入成功
@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);
}