前言
本身已经写过一篇关于蓝牙适配的文章了,不过因为是Kotlin,很多读者看不懂,对此我深感无奈,一开始也没有想过再写Java版本的,但是后面发现看不懂的越来越多了,我意识到不对劲了,因此我觉得再写一个Java版本的。
正文
在Android系统版本中,蓝牙的变化有,但是不多,这里简要说明一下。
一、Android版本中蓝牙简介
- Android1.5 中增加了蓝牙功能,立体声 Bluetooth 支持:A2DP [Advanced Audio DistributionProfile]、AVCRP [Audio/Video Remote Control Profile],自动配对。
- Android2.0 中支持Bluetooth2.1协议。
- Android3.0 中能让应用查询已经连接上 Bluetooth 设备的 Bluetooth Profile、音频状态等,然后通知用户。
- Android3.1 中系统可以通过 Bluetooth HID 方式同时接入一到多款输入设备。
- Android4.0 中新增支持连接 Bluetooth HDP [Health Device Profile)] 设备,通过第三方应用的支持,用户可以连接到医院、健身中心或者家庭等场合中的无线医疗设备和传感器。
- Android4.2 中引入了一种新的针对 Android 设备优化的 Bluetooth 协议栈 BlueDroid,从而取代 BlueZ 协议栈。Bluedroid 协议栈由 Google 和 Broadcom 公司共同开发,相对于 BlueZ 协议栈,BlueDroid 提升了兼容性和可靠性。
- Android4.3 中增加了对低功耗蓝牙的支持,内置支持 Bluetooth AVRCP 1.3,基于 Google 和 Broadcom 公司功能研发的针对于 Android 设备优化的新的蓝牙协议栈 BlueDroid。
- Android4.4 中新增两种新 Proifle 支持:HID [Human Interface Device]、MAP [Message Access Profile]
- Android5.0 中支持Bluetooth4.1协议。
- Android6.0 中扫描蓝牙需要动态获取定位才行。
- Android7.0 中支持Bluetooth4.2协议。
- Android8.0 中支持Bluetooth5.0协议,强化了蓝牙音频的表现。比如编码/传输格式可选SBC、AAC、aptX/aptX HD、LDAC等四种,音质依次提高。
- Android10.0 中支持Bluetooth5.1协议,在5.0的基础上,增加了侧向功能和厘米级定位服务,大幅度提高了定位精度。使室内定位更精准。
- Android11.0 中支持Bluetooth5.2协议,增强版ATT协议,LE功耗控制和信号同步,连接更快,更稳定,抗干扰性更好。
Android12.0 中支持Bluetooth5.3协议,增强了经典蓝牙BR/EDR(基础速率和增强速率)的安全性。蓝牙5.3的延迟更低、抗干扰性更强、提升了电池续航时间。系统引入了新的运行时权限BLUETOOTH_SCAN、BLUETOOTH_ADVERTISE 和 BLUETOOTH_CONNECT权限,用于更好地管理应用于附近蓝牙设备的连接。
二、新建项目
在Android12.0中新增加了三个运行时权限,我们依次来说明一下,这里我们依然创建一个项目来说明,新建一个Android12Bluetooth-Java项目,如下图所示:
点击Finish,完成项目的创建。
① 配置build.gradle
然后来配置一下项目的依赖库,在app的build.gradle中增加
buildFeatures { viewBinding true dataBinding true }
增加位置如下图所示:
注意是在android{}闭包下,然后Sync Now。
② 配置AndroidManifest.xml
下面配置AndroidMainfest.xml,权限如下所示:
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <!--Android12 的蓝牙权限 如果您的应用与已配对的蓝牙设备通信或者获取当前手机蓝牙是否打开--> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <!--Android12 的蓝牙权限 如果您的应用查找蓝牙设备(如蓝牙低功耗 (BLE) 外围设备)--> <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> <!--Android12 的蓝牙权限 如果您的应用使当前设备可被其他蓝牙设备检测到--> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/> <!--Android 6-11 定位权限--> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
增加位置如下图所示:
这里我们需要蓝牙的权限,还有定位的权限,在Android 12及以上版本使用蓝牙相关权限,Android 12以下版本使用定位相关权限。
三、打开蓝牙
下面我们构建一下activity_main.xml中的代码:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btn_open_bluetooth" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:layout_marginTop="20dp" android:layout_marginEnd="10dp" android:insetTop="0dp" android:insetBottom="0dp" android:text="打开蓝牙" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
这里就是写一个按钮,用来点击打开系统蓝牙的开关的。在Android12.0之前打开蓝牙的之前需要先判断蓝牙是否打开,我们可以这样来写,在MainActivity中增加如下代码:
private boolean isOpenBluetooth() { BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); BluetoothAdapter adapter = manager.getAdapter(); if (adapter == null) { return false; } return adapter.isEnabled(); }
同样我们还需要一个方法判断当前是否为Android12及以上版本。
private boolean isAndroid12() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S; }
同样还有一个检查此权限是否授予的方法和一个显示Toast的方法:
private boolean hasPermission(String permission) { return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; } private void showMsg(CharSequence msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }
① 打开蓝牙意图
在MainActivity中新增如下代码:
private ActivityResultLauncher<Intent> enableBluetooth; //打开蓝牙意图 private void registerIntent() { //打开蓝牙意图 enableBluetooth = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { if (isOpenBluetooth()){ BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); mBluetoothAdapter = manager.getAdapter(); scanner = mBluetoothAdapter.getBluetoothLeScanner(); showMsg("蓝牙已打开"); } else { showMsg("蓝牙未打开"); } } }); }
这里声明了一个变量,然后在方法中对变量进行赋值,此方法就替代了之前的startActivityForResult
,现在我们使用registerForActivityResult。在返回中可以得知当前是否打开了蓝牙,因为是在Java中使用,因此我们写了一个registerIntent()
方法,我们需要在onCreate之前调用这个方法,如图所示:
② 请求BLUETOOTH_CONNECT权限意图
registerForActivityResult不光能用于页面获取值,也能用于请求权限,先在MainActivity中声明变量,代码如下:
private ActivityResultLauncher<String> requestBluetoothConnect; //请求蓝牙连接权限意图
然后在registerIntent()
方法中,增加如下代码:
//请求BLUETOOTH_CONNECT权限意图 requestBluetoothConnect = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> { if (result) { enableBluetooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); } else { showMsg("Android12中未获取此权限,无法打开蓝牙。"); } });
请求权限返回无非就是同意不同意,如果同意了我们就调用。
enableBluetooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
去打开系统蓝牙,不同意就提示一下。下面再用ViewBinding来配置一下:
下面我们再写一个initView()方法,在这个函数中我们对按钮的点击事件进行操作,新增initView()方法,代码如下:
private void initView() { binding.btnOpenBluetooth.setOnClickListener(v -> { //蓝牙是否已打开 if (isOpenBluetooth()) { showMsg("蓝牙已打开"); return; } //是Android12 if (isAndroid12()) { //检查是否有BLUETOOTH_CONNECT权限 if (hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) { //打开蓝牙 enableBluetooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); } else { //请求权限 requestBluetoothConnect.launch(Manifest.permission.BLUETOOTH_CONNECT); } return; } //不是Android12 直接打开蓝牙 enableBluetooth.launch(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); }); }
这里的代码就比较好理解,首先判断蓝牙是否已经打开了,打开了就不往下执行,没打开,再判断当前是否为Android12,不是就直接打开系统蓝牙,是Android12,再去检查是否授予BLUETOOTH_CONNECT权限,授予了就打开系统蓝牙,没有授予就去请求此权限,不要忘记在onCreate()方法中调用它。
下面我们运行一下:
Android 12 蓝牙适配 Java版(下)https://developer.aliyun.com/article/1407523