Android BLE开发
来源:互联网 发布:手机淘宝修改评价 编辑:程序博客网 时间:2024/06/06 14:06
蓝牙ble(Bluetooth Low Energy):蓝牙低能耗技术蓝牙4.0
适用范围:Android4.3之后才支持BLE;iOS7.0开始支持BLE,Swift语言需要iOS8.0以上,硬件要求iPhone4s以上(包含4s)
蓝牙通信关系:主从关系,每一对设备进行蓝牙通讯时,必须一个为中心设备central,另一个为从设备peripheral.通信时必须central进行查找,发起配对,连接成功后双方可收发数据.一个central可以最多同时连接7个从设进行通讯,一个peripheral只能连接一个central.
Android开发手机做central:
1 获取权限
//判断手机是否有硬件BLE模块
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="false" />
//获取权限
<uses-permission android:name="android.permission.BLUETOOTH" />
//允许程序连接到已配对的蓝牙设备
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
//允许程序发现和配对蓝牙设备
Android6.0蓝牙权限需要添加模糊定位权限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
模糊定位是Dangerous Permission,涉及到用户隐私,使用时需要用户实时授权:
在代码中添加首次进入判断://动态运行时权限
private void checkBluetoothPermission() { if (Build.VERSION.SDK_INT >= 23) { //校验是否已具有模糊定位权限 if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION); } else { //具有权限 } } else { //系统不高于6.0直接执行 } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); doNext(requestCode, grantResults); }2 初始化蓝牙外设
获取到系统BluetoothManager:getSystemService(Context.BLUETOOTH_SERVICE)
获取到蓝牙适配器:manager.getAdapter
打开蓝牙:adapter.enable
/** * 初始化蓝牙外设 */ public boolean initialize() { //判断手机是否配置蓝牙4.0 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Log.e(TAG, "initialize:不能初始化蓝牙,因为您的手机不适配蓝牙4.0,没有蓝牙模块 " ); return false; } //获取到蓝牙管理者 if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.e(TAG, "initialize:初始化蓝牙管理器失败 "); return false; } } //获取到蓝牙适配器 if(mBluetoothAdapter == null) { mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.e(TAG, "initialize:初始化蓝牙适配器失败 " ); return false; } } //打开手机蓝牙 if(mBluetoothAdapter == null) { Log.e(TAG, "initialize:初始化蓝牙适配器失败 " ); return false; } else { //判断是否有蓝牙模块 boolean hasBle = mContext.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le"); if (!hasBle) { Log.e(TAG, "initialize:不能初始化蓝牙,因为您的手机不适配蓝牙4.0,没有蓝牙模块 "); return false; } //打开手机蓝牙 mBluetoothAdapter.enable(); return true; } }3 扫描外设,断开扫描
蓝牙扫描外设Android:Android5.0(SDK21)之前 startLeScan ,stopLeScan,回调函数LeScanCallback
Android5.0之后版本:先获取到BluetoothLeScanner: mBluetoothAdapter.getBluetoothLeScanner();
扫描:mBluetoothLeScanner.startScan(mScanCallback), 停止扫描:mBluetoothLeScanner.stopScan(mScanCallback)
扫描结果回调函数:ScanCallback
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private static class VersionA { //扫描外设的回调函数 private static BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) { Log.e(TAG, "onLeScan: 扫描一次" ); mBleCallBack.deviceScanned(bluetoothDevice, i, bytes); } }; public static void startLeScan() { if (mBluetoothAdapter == null) { Log.e(TAG, "startLeScan:开始扫描,适配器失败 "); return; } mBluetoothAdapter.startLeScan(mLeScanCallback); } public static void stopLeScan() { if (mBluetoothAdapter == null) { Log.e(TAG, "stopLeScan:停止扫描,适配器失败 "); return; } mBluetoothAdapter.stopLeScan(mLeScanCallback); } } /** * 5.0之后版本的外设扫描 */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) private static class VersionB { private static ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { //if (isDevice(result.getScanRecord().getBytes())) { // TODO: 16/6/24 扫描回调函数 Log.e(TAG, "onScanResult: 扫描一次" ); // Log.d(TAG, "onScanResult: 扫描回调函数,回调一次"+result.getDevice().getAddress()); mBleCallBack.deviceScanned(result.getDevice(), callbackType, result.getScanRecord().getBytes()); // } } }; public static void startScan() { if (mBluetoothLeScanner == null) { mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); } mBluetoothLeScanner.startScan(mScanCallback); } public static void stopScan() { if (mBluetoothLeScanner != null) { mBluetoothLeScanner.stopScan(mScanCallback); } } }3 连接设备:
手动连接设备,通过address连接
通过address获取到设备device:mBluetoothAdapter.getRemoteDevice(address);
创建连接,连接gatt通道:device.connectGatt(mContext, false, mGattCallback);
GATT:定义两个BLE设备通过Service和characteristic的东西进行通信,GATT连接是独占的,一个BLE外设同时只能被一个中心设备连接,一旦外设被连接就不再广播,这样它对其他设备不可见,设备断开时,它又开始广播.
GATT中
一个低功耗蓝牙(ble)可以包括多个Profile
一个Profile中有多个Service(通过uuid就可以找到对应的Service)
一个Service中有多个Characteristic(通过uuid就可以找到对应的Characteristic)
一个Characteristic中包括一个value和多个Descriptor(通过uuid就可以找到对应的Descriptor)
/** * 手动连接设备,通过address连接 */ public boolean connect(final String address) { currentDevice = null; if (mBluetoothAdapter == null || address == null) { Log.e(TAG, "connect: 蓝牙适配器初始化失败或者蓝牙外设地址为空"); return false; } final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.e(TAG, "外设没有找到,连接失败"); return false; } currentDevice = device; // 曾经连接上过,重新连接// if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)// && mBluetoothGatt != null) {// Log.e(TAG, "尝试连接一个曾经连接上的外设");// mBluetoothGatt.close();// if (mBluetoothGatt.connect()) {// //已经连接上了,但是基于蓝牙协议,并没有连接上,手动扫描service从而实现连接// mBluetoothGatt.discoverServices();// return true;// } else {// return false;// }// } if (mBluetoothGatt != null){ mBluetoothGatt.close(); mBluetoothGatt = null; } //连接设备 mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback); Log.e(TAG, "尝试创建一个新连接,连接外设Gatt新通道"); mBluetoothDeviceAddress = address; if (mBluetoothGatt != null){ Log.e(TAG, "Gatt通道建立成功"); }else { Log.e(TAG, "Gatt通道建立失败"); } return true; }
4 断开连接:gatt.disConnect
5发送数据到外设:
this.writeCharacteristic.setValue(data);
this.mBluetoothGatt.writeCharacteristic(this.writeCharacteristic);
6 一旦扫描到外设,就可以获取到service了,这样就可以对属性进行读写了
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { // TODO: 16/6/24 设备连接 mBleCallBack.deviceConnected(currentDevice.getAddress()); //搜索连接到的蓝牙外设的服务 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } mBluetoothGatt.discoverServices(); //监测到设备连接成功后,扫描service } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // TODO: 16/6/24 设备断开 if (mBluetoothGatt != null){ mBluetoothGatt.close(); // 释放资源 mBluetoothGatt = null; } mBleCallBack.deviceDisconnected(currentDevice.getAddress()); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { Log.d(TAG, "onServicesDiscovered: BluetoothGatt Status:"+status); if (status == BluetoothGatt.GATT_SUCCESS){ // TODO: 16/6/27 搜索服务中 if(bleServiceList != null && bleServiceList.size() > 0) { bleServiceList.clear(); } if(mBluetoothGatt != null) { bleServiceList = mBluetoothGatt.getServices(); } Log.d(TAG, "onServicesDiscovered: gatt success"); setCharacteristicNull(); BluetoothGattService bluetoothGattService = mBluetoothGatt.getService(SERVICE_UUID); if (bluetoothGattService != null){ List<BluetoothGattCharacteristic> characteristicList = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic characteristic : characteristicList) { Log.d(TAG, "onServicesDiscovered: Characteristic:"+characteristic.getUuid()+"propertity:"+characteristic.getProperties()); if (characteristic.getUuid().equals(UUID.fromString(""))) { if ((characteristic.getProperties() & 18) != 0) { Log.d(TAG, "onServicesDiscovered: readCharacteristic:"+characteristic.getProperties()); readCharacteristic = characteristic;//获取到读写characteristic setCharacterNotification(readCharacteristic,true); } else if ((characteristic.getProperties() & 12) != 0) { Log.d(TAG, "onServicesDiscovered: writeCharacteristic:"+characteristic.getProperties()); characteristic.setWriteType(1); writeCharacteristic = characteristic; } } } } } BluetoothGattService bluetoothGattServicen = mBluetoothGatt.getService(SERVICE_UUIDN); if (bluetoothGattServicen != null) { List<BluetoothGattCharacteristic> characteristicListn = bluetoothGattServicen.getCharacteristics(); for (BluetoothGattCharacteristic characteristic : characteristicListn) { if (characteristic.getUuid().equals(UUID.fromString("d44bc439-abfd-45a2-b575-925416129601"))) { readCharacteristic = characteristic; setCharacterNotification(readCharacteristic,true); Log.e(TAG, "读:" + characteristic.getProperties()); } if (characteristic.getUuid().equals(UUID.fromString("d44bc439-abfd-45a2-b575-925416129600"))) { writeCharacteristic = characteristic; //characteristic.setWriteType(1); Log.e(TAG, "写:" + characteristic.getProperties()); } } } } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if(status == 0) { // TODO: 16/6/27 读characteristic的值 } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { byte[] var3 = characteristic.getValue(); Log.d(TAG,"write character response:"+CharUtils.bytesToHexString(var3)); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { byte[] var3 = characteristic.getValue(); Log.d(TAG, "onCharacteristicChanged: data:"+CharUtils.bytesToHexString(var3)); // TODO: 16/6/27 接收数据 mBleCallBack.deviceReceiveData(currentDevice.getAddress(),var3); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if(status == 0) { // TODO: 16/6/27 写入descriptor 之后回调 } } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { // TODO: 16/6/27 读取Rssi的值 mBleCallBack.deviceRssiReport(currentDevice.getAddress(),rssi); } };7 开启notify接收数据
如果设备主动给手机发信息,则可以通过notification的方式,如果notificaiton方式对于某个Characteristic是enable的,那么当设备上的这个Characteristic改变时,手机上onCharacteristic回调就会被促发。
private void setCharacterNotification(BluetoothGattCharacteristic characteristic, boolean enabled){ Log.e(TAG,"set ChatacterNotification"); boolean isOk = mBluetoothGatt.setCharacteristicNotification(characteristic,enabled); Log.e(TAG,"set ChatacterNotification:"+isOk); if(!isOk) { Log.e(TAG, "设置通知失败"); }// BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));// if(descriptor != null) {// byte[] bytes = enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;// descriptor.setValue(bytes);// boolean isWrite = mBluetoothGatt.writeDescriptor(descriptor);// if (isWrite){// Log.d(TAG, "writeDescriptor:ok ");// }else{// Log.d(TAG, "writeDescriptor:on ");// }// } List<BluetoothGattDescriptor> descriptorList = characteristic.getDescriptors(); if(descriptorList != null && descriptorList.size() > 0) { Log.e(TAG, "descriptor != null"); for(BluetoothGattDescriptor descriptor : descriptorList) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); boolean isWrite = mBluetoothGatt.writeDescriptor(descriptor); if (isWrite){ Log.d(TAG, "writeDescriptor:ok "); }else { Log.d(TAG, "writeDescriptor:on "); } } } }
- Android BLE开发: BLE Peripheral开发流程
- Android BLE开发记录
- Android BLE 开发总结
- Android BLE开发笔记
- android ble 开发笔记
- Android Ble蓝牙开发
- Android BLE 开发
- Android BLE开发总结
- android BLE蓝牙开发
- Android BLE 开发
- android ble开发整理
- Android BLE开发
- Android BLE开发
- android 蓝牙BLE 开发
- Android:BLE蓝牙开发
- android ble蓝牙开发
- Android蓝牙BLE开发步骤
- BLE For Android软件开发
- java迷路记-微信支付之公众号支付小结
- Hive入门安装配置
- 软考--程序设计语言基础
- LeetCode (Minimum Window Substring)
- 输入一个十进制的正整数,从低位开始查找,找到第一个置位(1)比特的位置
- Android BLE开发
- RxJava1.x ------ 取消订阅,Subscription
- js数据结构排序之选择排序
- <视频教程-2>生成对抗网络GAN视频教程part6-完整版
- libuv之事件循环loop
- 类图、用例图、序列图、BCE模式
- 小白题解 Codeforces 785B Anton and Classes
- mysql 和 redis的区别
- 《鸟哥的Linux私房菜-基础学习篇(第四版)》pdf