当前位置:   article > 正文

Android ble(低功耗蓝牙)开发基础代码及常见问题

android ble

目录

一、声明权限

二、蓝牙基础代码

1、蓝牙单例类BleManager.java:

2、权限处理类PermissionHelper.java

3、界面中使用ble单例类相关代码

三、常见问题(坑)更新中。。。

1、connectGatt(context, false, bluetoothGattCallback)方法

2、设置接收特定特征通知

3、读取特征值 gatt.readCharacteristic(characteristic)

4、连接同时拥有经典蓝牙和BLE的设备

5、设置MTU

6、断开连接bluetoothGatt.disconnect()

7、扫描回调OnScanResult()方法

8、息屏后保持扫描不停止


一、声明权限

清单文件 AndroidManifest.xml:

  1. <!-- 蓝牙权限 -->
  2. <uses-permission
  3. android:name="android.permission.BLUETOOTH"
  4. android:maxSdkVersion="30" />
  5. <uses-permission
  6. android:name="android.permission.BLUETOOTH_ADMIN"
  7. android:maxSdkVersion="30" />
  8. <!-- 位置权限 -->
  9. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  10. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  11. <!-- 安卓12蓝牙权限 -->
  12. <!-- 扫描权限 -->
  13. <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
  14. <!-- 蓝牙可被发现权限 -->
  15. <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
  16. <!-- 连接权限 -->
  17. <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
  18. <!-- 声明应用需要支持BLE -->
  19. <uses-feature
  20. android:name="android.hardware.bluetooth_le"
  21. android:required="true" />

 以上为蓝牙需要的权限(适配安卓12)

二、蓝牙基础代码

1、蓝牙单例类BleManager.java:

  1. /**
  2. * author:created by mj
  3. * Date:2022/6/7 17:33
  4. * Description:蓝牙单例类
  5. */
  6. public class BleManager {
  7. //单例对象
  8. public static volatile BleManager bleManager;
  9. //调用到上下文对象
  10. private FragmentActivity context;
  11. //蓝牙适配器
  12. private BluetoothManager bluetoothManager;
  13. private BluetoothAdapter bluetoothAdapter;
  14. //设备扫描
  15. private BluetoothLeScanner bleScanner;
  16. //扫描回调 区分高低版本 H为安卓5.0及以上版本
  17. private ScanCallback scanCallbackH;
  18. private BluetoothAdapter.LeScanCallback scanCallbackL;
  19. //蓝牙gatt服务对象和回调
  20. private BluetoothGatt bluetoothGatt;
  21. private BluetoothGattCallback bluetoothGattCallback;
  22. //设备和app之间的读写特征值和描述符
  23. private BluetoothGattCharacteristic readCharacteristic;
  24. private BluetoothGattCharacteristic writeCharacteristic;
  25. private BluetoothGattDescriptor readDescriptor;
  26. //判断是否正在扫描和是否连接设备
  27. public boolean isScanning = false;
  28. public boolean isConnect = false;
  29. //子线程
  30. private Handler workHandler;
  31. private HandlerThread handlerThread;
  32. //主线程
  33. private Handler mainHandler;
  34. //存放扫描到的设备
  35. private List<String> devicesList;
  36. //存放配对的设备名字和mac地址
  37. private SharedPreferences sp;
  38. //服务和特征值ID(由ble设备工程师设置)
  39. private final String SERVICE_UUID = "0000xxxx-0000-1000-8000-xxxxxxxxxxxx";
  40. private final String CHARACTERISTIC_UUID1 = "0000xxxx-0000-1000-8000-xxxxxxxxxxxx";
  41. private final String CHARACTERISTIC_UUID2 = "0000xxxx-0000-1000-8000-xxxxxxxxxxxx";
  42. private final String READ_DESCRIPTOR_UUID = "00002902-0000-1000-8000-00805f9b34fb";
  43. //已配对的蓝牙设备
  44. private BluetoothDevice bleDevice;
  45. //设备名字和Mac地址
  46. private String DEVICE_NAME;
  47. private String DEVICE_ADDRESS;
  48. //ble状态码用来多线程处理
  49. private static final int START_SCAN = 1;
  50. private static final int STOP_SCAN = 2;
  51. private static final int CONNECT_GATT = 3;
  52. private static final int DISCONNECT_GATT = 4;
  53. private static final int CLOSE_GATT = 5;
  54. private static final int SEND_DATA = 6;
  55. //权限申请
  56. private BlePermissionHelper blePermissionHelper;
  57. //蓝牙连接状态改变监听接口
  58. private OnBleConnectCallback onBleConnectCallback;
  59. public interface OnBleConnectCallback {
  60. //扫描到设备
  61. void bleScan();
  62. //蓝牙设备连接和断开
  63. void bleConnect();
  64. void bleDisConnect();
  65. //获取设备电量
  66. void getBleEleQue(int ele);
  67. }
  68. //获取单例模式(懒汉式)
  69. public static BleManager getInstance() {
  70. //双重校验锁(提高效率)
  71. if (bleManager == null)
  72. synchronized (BleManager.class) {
  73. if (bleManager == null)
  74. bleManager = new BleManager();
  75. }
  76. return bleManager;
  77. }
  78. //初始化蓝牙ble相关
  79. @SuppressLint({"MissingPermission", "ObsoleteSdkInt"})
  80. public void initBle(FragmentActivity activity) {
  81. this.context = activity;
  82. devicesList = new ArrayList<>();
  83. //请求权限
  84. blePermissionHelper = new BlePermissionHelper(activity);
  85. if (!blePermissionHelper.isSupportBLE()) {
  86. Toast.makeText(activity, "当前设备不支持蓝牙!", Toast.LENGTH_LONG).show();
  87. return;
  88. }
  89. //通过蓝牙管理器获取适配器
  90. bluetoothManager = (BluetoothManager) activity.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
  91. bluetoothAdapter = bluetoothManager.getAdapter();
  92. //android 5.0以上API需要的ble扫描类
  93. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
  94. //初始化scanner
  95. bleScanner = bluetoothAdapter.getBluetoothLeScanner();
  96. //初始化已配对设备名和地址
  97. sp = activity.getApplicationContext().getSharedPreferences("sp_ble", Context.MODE_PRIVATE);
  98. DEVICE_NAME = sp.getString("bleName", null);
  99. DEVICE_ADDRESS = sp.getString("bleAddress", null);
  100. //初始化线程
  101. initHandler();
  102. //初始化高版本api扫描回调
  103. scanCallbackH = new ScanCallback() {
  104. @SuppressLint("MissingPermission")
  105. @Override
  106. public void onScanResult(int callbackType, ScanResult result) {
  107. super.onScanResult(callbackType, result);
  108. //连接蓝牙
  109. //进行扫描到的设备过滤
  110. if (result.getDevice().getName() == null)
  111. return;
  112. // Log.e("test","nowName "+DEVICE_NAME+" scanName "+bleDevice.getName() +" if="+bleDevice.getName().equals(DEVICE_NAME));
  113. //这里根据设备名进行连接(可以使用mac地址)
  114. if (result.getDevice().getName().equals(DEVICE_NAME)) {
  115. bleDevice = result.getDevice();
  116. mainHandler.sendEmptyMessage(CONNECT_GATT);
  117. }
  118. Log.e("test", "name:" + result.getDevice().getName() + " rssi:" + result.getRssi() + " address:" + result.getDevice().getAddress());
  119. if (devicesList.contains(result.getDevice().getName()))
  120. return;
  121. //将扫描到到设备添加到集合中用于显示
  122. devicesList.add(result.getDevice().getName());
  123. //回调连接接口的扫描方法
  124. onBleConnectCallback.bleScan();
  125. }
  126. };
  127. //初始化低版本api扫描回调
  128. scanCallbackL = new BluetoothAdapter.LeScanCallback() {
  129. @Override
  130. public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
  131. //内容同上onScanResult方法
  132. }
  133. };
  134. //初始化蓝牙gatt回调
  135. bluetoothGattCallback = new
  136. BluetoothGattCallback() {
  137. @SuppressLint("MissingPermission")
  138. @Override
  139. public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
  140. super.onConnectionStateChange(gatt, status, newState);
  141. Log.e("test", "onConnectionStateChange " + newState);
  142. //连接蓝牙成功后发现可读写的服务
  143. if (newState == BluetoothGatt.STATE_CONNECTED) {
  144. //连接成功后停止扫描
  145. workHandler.sendEmptyMessage(STOP_SCAN);
  146. DEVICE_NAME = gatt.getDevice().getName();
  147. // onBleConnectCallback.bleConnect();
  148. DEVICE_ADDRESS = gatt.getDevice().getAddress();
  149. Log.e("test", "connect name :" + DEVICE_NAME + " address---" + DEVICE_ADDRESS);
  150. isConnect = true;
  151. //将已连接的设备名存储到SharedPreferences中
  152. //先从sp中获取ble设备信息
  153. SharedPreferences.Editor editor = sp.edit();
  154. editor.putString("bleName", DEVICE_NAME);
  155. editor.apply();
  156. //延迟后回调否则扫描失败没有回调
  157. // handler.postDelayed(gatt::discoverServices, 100);
  158. bluetoothGatt.discoverServices();
  159. return;
  160. }
  161. if (newState == BluetoothGatt.STATE_DISCONNECTED) {
  162. onBleConnectCallback.bleDisConnect();
  163. isConnect = false;
  164. mainHandler.sendEmptyMessage(CLOSE_GATT);
  165. return;
  166. }
  167. //避免其他情况出现,断开连接
  168. mainHandler.sendEmptyMessage(DISCONNECT_GATT);
  169. }
  170. @SuppressLint("MissingPermission")
  171. @Override
  172. public void onServicesDiscovered(BluetoothGatt gatt, int status) {
  173. super.onServicesDiscovered(gatt, status);
  174. //发现服务成功后寻找特征值
  175. if (status == BluetoothGatt.GATT_SUCCESS) {
  176. UUID serviceUuid = UUID.fromString(SERVICE_UUID);
  177. //读设备到app的特征值uuid
  178. UUID characteristicUuid1 = UUID.fromString(CHARACTERISTIC_UUID1);
  179. //写app到设备的特征值uuid
  180. UUID characteristicUuid2 = UUID.fromString(CHARACTERISTIC_UUID2);
  181. bluetoothGatt.getServices();
  182. BluetoothGattService gattService = bluetoothGatt.getService(serviceUuid);
  183. if (gattService != null) {
  184. //根据uuid获取相应特征值
  185. readCharacteristic = gattService.getCharacteristic(characteristicUuid1);
  186. writeCharacteristic = gattService.getCharacteristic(characteristicUuid2);
  187. //获取根据uuid获取相应描述
  188. readDescriptor = readCharacteristic.getDescriptor(UUID.fromString(READ_DESCRIPTOR_UUID));
  189. //设置描述和特征值通知
  190. readDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
  191. bluetoothGatt.writeDescriptor(readDescriptor);
  192. bluetoothGatt.setCharacteristicNotification(readCharacteristic, true);
  193. //获取电量
  194. // handler.postDelayed(() -> writeBleHexStrValue("A102010055"), 200);
  195. }
  196. }
  197. }
  198. //读取数据回调,接收数据
  199. @Override
  200. public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic
  201. characteristic, int status) {
  202. super.onCharacteristicRead(gatt, characteristic, status);
  203. if (characteristic.getUuid().toString().equals(CHARACTERISTIC_UUID1)) {
  204. byte[] value = characteristic.getValue();
  205. Log.e("test", "Read" + Arrays.toString(value));
  206. }
  207. }
  208. //发送数据回调
  209. @Override
  210. public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
  211. characteristic, int status) {
  212. super.onCharacteristicWrite(gatt, characteristic, status);
  213. byte[] value = characteristic.getValue();
  214. Log.e("test", "Write" + Arrays.toString(value));
  215. }
  216. //蓝牙设备改变特征值后接收修改的信息
  217. @Override
  218. public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
  219. characteristic) {
  220. super.onCharacteristicChanged(gatt, characteristic);
  221. //判断是否为指定的特征值
  222. if (characteristic.getUuid().toString().equals(CHARACTERISTIC_UUID1)) {
  223. byte[] value = characteristic.getValue();
  224. //判断返回的数据是否非空且为电量
  225. if (value == null || value.length <= 0 || value[1] != 0x02)
  226. return;
  227. electricQuantity = value[3] & 0xFF;
  228. }
  229. byte[] value = characteristic.getValue();
  230. Log.e("test", "CharacteristicChanged " + Arrays.toString(value));
  231. onBleConnectCallback.getBleEleQue(electricQuantity);
  232. }
  233. //设置描述符后回调
  234. @Override
  235. public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
  236. super.onDescriptorWrite(gatt, descriptor, status);
  237. if (status == BluetoothGatt.GATT_SUCCESS) {
  238. Log.e("test", "onDescriptorWrite success");
  239. //设置特征通知成功,发送数据的特征也是成功,可以相互收发数据了
  240. //获取电量
  241. workHandler.postDelayed(() -> sendData2Ble("A102010055"), 100);
  242. }
  243. }
  244. }
  245. ;
  246. }
  247. //初始化线程
  248. private void initHandler() {
  249. //初始化主线程
  250. mainHandler = new Handler(context.getMainLooper()) {
  251. @SuppressLint("MissingPermission")
  252. @Override
  253. public void handleMessage(@NonNull Message msg) {
  254. super.handleMessage(msg);
  255. switch (msg.what) {
  256. case CONNECT_GATT:
  257. bluetoothGatt = bleDevice.connectGatt(context, false, bluetoothGattCallback);
  258. break;
  259. case DISCONNECT_GATT:
  260. if (bluetoothGatt != null)
  261. bluetoothGatt.disconnect();
  262. break;
  263. case CLOSE_GATT:
  264. if(bluetoothGatt!=null)
  265. bluetoothGatt.close();
  266. bluetoothGatt = null;
  267. break;
  268. }
  269. }
  270. };
  271. //初始化工作子线程
  272. handlerThread = new HandlerThread("BleWorkHandlerThread");
  273. handlerThread.start();
  274. workHandler = new Handler(handlerThread.getLooper()) {
  275. @SuppressLint("MissingPermission")
  276. @Override
  277. public void handleMessage(@NonNull Message msg) {
  278. super.handleMessage(msg);
  279. //根据消息类别进行相应处理
  280. switch (msg.what) {
  281. case START_SCAN:
  282. startBleScan();
  283. break;
  284. case STOP_SCAN:
  285. if (isScanning) {
  286. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
  287. if (bleScanner == null)
  288. bleScanner = bluetoothAdapter.getBluetoothLeScanner();
  289. bleScanner.stopScan(scanCallbackH);
  290. }
  291. else
  292. bluetoothAdapter.stopLeScan(scanCallbackL);
  293. isScanning = false;
  294. }
  295. //线程休眠确保ble停止搜索完成
  296. try {
  297. Thread.sleep(100);
  298. } catch (InterruptedException e) {
  299. e.printStackTrace();
  300. }
  301. break;
  302. case SEND_DATA:
  303. writeBleHexStrValue((String) msg.obj);
  304. break;
  305. }
  306. }
  307. };
  308. }
  309. //搜索蓝牙设备方法
  310. public void scanLeDevice() {
  311. if (blePermissionHelper.checkNOpenGps() && blePermissionHelper.checkNOpenBl()) {
  312. workHandler.sendEmptyMessage(START_SCAN);
  313. Log.e(TAG, "scan start");
  314. }
  315. }
  316. //停止扫描方法
  317. public void stopScanLeDevice() {
  318. workHandler.sendEmptyMessage(STOP_SCAN);
  319. }
  320. //向蓝牙设备写入数据方法
  321. @SuppressLint("MissingPermission")
  322. public void writeBleHexStrValue(String hexStr) {
  323. //判断是否连接和数据值是否为空
  324. if (!isConnect || hexStr == null || hexStr.equals(""))
  325. return;
  326. //判断写特征值和服务对象是否为空
  327. if (writeCharacteristic == null || bluetoothGatt == null)
  328. return;
  329. byte[] value = hexStrToBytes(hexStr);
  330. writeCharacteristic.setValue(value);
  331. bluetoothGatt.writeCharacteristic(writeCharacteristic);
  332. }
  333. //发送数据到BLE设备
  334. private void sendData2Ble(String data) {
  335. Message message = new Message();
  336. message.what = SEND_DATA;
  337. message.obj = data;
  338. workHandler.sendMessage(message);
  339. }
  340. //16进制字符串转字节数组
  341. public static byte[] hexStrToBytes(String hexStr) {
  342. String hex = "0123456789ABCDEF";
  343. if (hexStr == null || hexStr.equals(""))
  344. return null;
  345. //全部转化为大写字母
  346. hexStr = hexStr.toUpperCase();
  347. //字节数组长度
  348. int length = hexStr.length() / 2;
  349. //转化为字符数组
  350. byte[] value = new byte[length];
  351. char[] hexChar = hexStr.toCharArray();
  352. for (int i = 0; i < length; i++) {
  353. int p = i * 2;
  354. //右移4位得到字节高位再和下一个字符或得到位
  355. value[i] = (byte) (hex.indexOf(hexChar[p]) << 4 | hex.indexOf(hexChar[p + 1]));
  356. }
  357. return value;
  358. }
  359. //设置回调接口
  360. public void setOnBleConnectCallback(OnBleConnectCallback onBleConnectCallback) {
  361. this.onBleConnectCallback = onBleConnectCallback;
  362. }
  363. //开始扫描蓝牙
  364. @SuppressLint({"MissingPermission", "ObsoleteSdkInt"})
  365. public void startBleScan() {
  366. if (!isScanning) {
  367. isScanning = true;
  368. Log.e("test", "扫描");
  369. //开始扫描
  370. //如果安卓版本高于5.0使用高版本api
  371. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
  372. if (bleScanner == null)
  373. bleScanner = bluetoothAdapter.getBluetoothLeScanner();
  374. bleScanner.startScan(scanCallbackH);
  375. }
  376. else
  377. bluetoothAdapter.startLeScan(scanCallbackL);
  378. }
  379. }
  380. //判断蓝牙打开状态
  381. public boolean isEnabled() {
  382. return bluetoothAdapter.isEnabled();
  383. }
  384. //getter和setter 方法
  385. public BluetoothAdapter getBluetoothAdapter() {
  386. return bluetoothAdapter;
  387. }

2、权限处理类PermissionHelper.java

  1. /**
  2. * author:created by mj
  3. * Date:2022/8/24 17:30
  4. * Description:用于权限的类
  5. */
  6. public class BlePermissionHelper {
  7. private static final String TAG = "BlePermissionHelper";
  8. private Activity mActivity;
  9. private Context mContext;
  10. private final String[] gpsPermissions = new String[]{ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
  11. private final String[] blPermissions = new String[]{BLUETOOTH_SCAN, BLUETOOTH_CONNECT};
  12. private final BluetoothAdapter bluetoothAdapter;
  13. private final LocationManager locationManager;
  14. //状态码
  15. private final int OPEN_BLUETOOTH = 1;
  16. public final int REQUEST_GPS_PERMISSIONS = 2;
  17. public final int REQUEST_BLUETOOTH_PERMISSIONS = 3;
  18. //权限提示对话框
  19. private AlertDialog mDialog;
  20. public BlePermissionHelper(Activity mActivity) {
  21. this.mActivity = mActivity;
  22. this.mContext = mActivity;
  23. this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  24. this.locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
  25. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  26. builder.setTitle("获取权限")
  27. .setMessage("设置允许权限后才可以使用")
  28. .setPositiveButton("设置", (dialog, id) -> {
  29. Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
  30. Uri uri = Uri.fromParts("package", getPackageName(), null);
  31. intent.setData(uri);
  32. startActivity(intent);
  33. finish();
  34. }).setNegativeButton("取消", null);
  35. //弹出对话框提示
  36. AlertDialog mDialog = builder.create();
  37. mDialog.setCanceledOnTouchOutside(true);
  38. }
  39. public BlePermissionHelper(Context context) {
  40. this.mContext = context;
  41. this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  42. this.locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
  43. }
  44. //动态申请位置权限
  45. public void requestGpsPermissions() {
  46. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
  47. if (!isLocationPermission()) {
  48. Log.e(TAG, "request gps permission");
  49. // 没有权限会弹出对话框申请
  50. ActivityCompat.requestPermissions(mActivity, gpsPermissions, REQUEST_GPS_PERMISSIONS);
  51. }
  52. }
  53. //动态申请蓝牙权限(安卓12以上)
  54. public void requestBlePermissions() {
  55. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
  56. if (!isBlPermission()) {
  57. Log.e(TAG, "request bl ");
  58. // 没有权限会弹出对话框申请
  59. ActivityCompat.requestPermissions(mActivity, blPermissions, REQUEST_BLUETOOTH_PERMISSIONS);
  60. }
  61. }
  62. }
  63. //检查权限和打开GPS
  64. public boolean checkNOpenGps() {
  65. if (!isLocationPermission()) {
  66. requestGpsPermissions();
  67. return false;
  68. }
  69. if (!isEnableGps()) {
  70. mActivity.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
  71. return false;
  72. }
  73. return true;
  74. }
  75. //检查权限和打开蓝牙
  76. @SuppressLint("MissingPermission")
  77. public boolean checkNOpenBl() {
  78. if (!isBlPermission()) {
  79. requestBlePermissions();
  80. return false;
  81. }
  82. if (!isEnableBluetooth()) {
  83. //执行一次打开蓝牙功能,给用户提示。
  84. Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  85. mActivity.startActivityForResult(intent, OPEN_BLUETOOTH);
  86. return false;
  87. }
  88. return true;
  89. }
  90. //判断是否支持ble
  91. public boolean isSupportBLE() {
  92. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
  93. return false;
  94. }
  95. return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
  96. }
  97. //判断是否打开蓝牙
  98. public boolean isEnableBluetooth() {
  99. if (!isSupportBLE())
  100. return false;
  101. return bluetoothAdapter.isEnabled();
  102. }
  103. //判断是否打开gps定位
  104. public boolean isEnableGps() {
  105. return locationManager.isProviderEnabled(GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
  106. }
  107. //判断是否授权gps
  108. public boolean isLocationPermission() {
  109. return checkSelfPermission(mContext, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
  110. || checkSelfPermission(mContext, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED;
  111. }
  112. //判断是否授权蓝牙(安卓12以上)
  113. public boolean isBlPermission() {
  114. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
  115. return checkSelfPermission(mContext, BLUETOOTH_CONNECT) == PERMISSION_GRANTED
  116. && checkSelfPermission(mContext, BLUETOOTH_SCAN) == PERMISSION_GRANTED;
  117. }
  118. return true;
  119. }
  120. //如果用户选择了不再询问权限则弹窗提醒
  121. public void showSetPermissionDialogIfDeny(int requestCode) {
  122. String[] permissions;
  123. if (requestCode == REQUEST_GPS_PERMISSIONS) {
  124. if (isLocationPermission()) {
  125. requestBlePermissions();
  126. return;
  127. }
  128. permissions = gpsPermissions;
  129. } else {
  130. permissions = blPermissions;
  131. }
  132. for (String permission : permissions) {
  133. //用户选择了禁止且不再询问
  134. if (!ActivityCompat.shouldShowRequestPermissionRationale(mActivity, permission) && ActivityCompat.checkSelfPermission(mActivity, permission) != PackageManager.PERMISSION_GRANTED) {
  135. Log.e(TAG, "show dialog" + permission);
  136. if (!mDialog.isShowing())
  137. //弹出对话框提示
  138. mDialog.show();
  139. break;
  140. }
  141. }
  142. }
  143. //请求单个权限方法
  144. public void requestPermission(String permission, int requestCode) {
  145. if (checkSelfPermission(mContext, permission) != PERMISSION_GRANTED)
  146. ActivityCompat.requestPermissions(mActivity, new String[]{permission}, requestCode);
  147. }
  148. }

3、界面中使用ble单例类相关代码

  1. public class PermissionActivity extends AppCompatActivity {
  2. private BlePermissionHelper blePermissionHelper;
  3. private BleManager ble;
  4. @Override
  5. protected void onCreate(@Nullable Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. ble = BleManager.getInstance();
  8. ble.initBle(MainActivity.this);
  9. blePermissionHelper = new BlePermissionHelper(this);
  10. //ble连接回调
  11. BleManager.OnBleConnectCallback bleConnectCallback = new BleManager.OnBleConnectCallback() {
  12. @Override
  13. public void bleScan() {
  14. }
  15. @Override
  16. public void bleConnect() {
  17. }
  18. @Override
  19. public void bleDisConnect() {
  20. }
  21. @Override
  22. public void getBleEleQue(int ele) {
  23. }
  24. };
  25. ble.setOnBleConnectCallback(bleConnectCallback);
  26. }
  27. //权限回调方法
  28. @Override
  29. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  30. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  31. for (String p : permissions)
  32. Log.e("TAG", "onRequestPermissionsResult: " + requestCode + " " + p);
  33. blePermissionHelper.showSetPermissionDialogIfDeny(requestCode);
  34. }
  35. }

三、常见问题(坑)更新中。。。

1、connectGatt(context, false, bluetoothGattCallback)方法

第二个参数自动连接一般设为false,设置为true有时候会导致连接成功但无法读写数据的情况(据说如果自动连接期间再建立一个连接会出现死循环)。自动连接的效率也很低,不如自己写回连逻辑。

2、设置接收特定特征通知

 特征改变时需要获取数据只有

bluetoothGatt.setCharacteristicNotification(readCharacteristic, true);

不行,还要在上述语句前面加上下面两行代码设置相应的特征里的描述符的通知。

  1. //获取根据uuid获取相应描述
  2. readDescriptor = readCharacteristic.getDescriptor(UUID.fromString(READ_DESCRIPTOR_UUID));
  3. //设置描述通知
  4. readDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
  5. bluetoothGatt.writeDescriptor(readDescriptor);

注意setValue方法是BluetoothGattDescriptor对象调用的而不是BluetoothGattCharacteristic对象,这里写反编译器不会报错,但是无法接收到notify消息。

3、读取特征值 gatt.readCharacteristic(characteristic)

复杂一点的情况下一般都需要加一个延迟再读,否则经常读不到返回false。(也可能与设备有关) 

4、连接同时拥有经典蓝牙和BLE的设备

可能会出现无法连接的情况 Log显示onClientConnectionState() - status=133 clientIf=10

这时候需要修改连接代码对安卓6.0以上增加一个参数。

  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  2. mBluetoothGatt = mBluetoothDevice.connectGatt(mContext, false, mGattCallback,BluetoothDevice.TRANSPORT_LE);
  3. } else {
  4. mBluetoothGatt = mBluetoothDevice.connectGatt(mContext, false, mGattCallback);
  5. }

5、设置MTU

设置MTU要等onMtuChanged回调后再进行读写操作,不然的话会导致后续的读写特征返回false,无法发送数据到设备。

6、断开连接bluetoothGatt.disconnect()

不要和bluetoothGatt.close()一起调用,容易出现无法触发断连状态回调(onConnectionStateChange),gatt对象的保存也要注意,最好一一对应,否则容易出现连接和断连不完全等问题。

7、扫描回调OnScanResult()方法

回调中不要处理太多的逻辑,尽早结束回调,不然蓝牙资源利用频繁容易卡死主线程。

8、息屏后保持扫描不停止

需要设置过滤filters,可以设一个空列表

  1. List<ScanFilter> filters = new ArrayList<>();
  2. filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build());
  3. bleScanner.startScan(scanFilters, scanSettings, scanCallback);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/573771
推荐阅读
相关标签
  

闽ICP备14008679号