Android 蓝牙使用
公司项目需求需要实现监听蓝牙耳机连接,且要获取蓝牙耳机电量功能,翻了不少官方文档,记录下技术调研代码
注:本文没有研究蓝牙配对功能
关于蓝牙权限适配
Android12以后,申请蓝牙权限需要申请一组,如新增的几个权限,需要一起申请
参考: 蓝牙权限 | Connectivity | Android Developers
val permissionList = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
//android12及以上版本,这2个权限申请只会弹出一个对话框
listOf(Permission.BLUETOOTH_CONNECT, Permission.BLUETOOTH_SCAN)
} else {
//android12以下版本申请,默认是同意的,不会有权限弹窗
listOf(Permission.BLUETOOTH_CONNECT)
}
打开蓝牙开关
注意,如果是Android12及以上版本,蓝牙开关打开操作需要有Bluetooth_Connect权限才能执行操作
效果就是直接打开蓝牙开关
val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
//需要权限android.permission.BLUETOOTH_CONNECT才能执行操作
bluetoothAdapter.enable()
不过Android还是有提供另外的一个方法供我们使用,就是下面的方法
此方法是API 5 就有的方法,和上面一样,Android12及以上版本,就是需要有Bluetooth_Connect权限才能执行成功,否则会抛出异常
兼容低版本和高版本,此方法兼容,调用此方法,系统会弹出一个是否允许打开蓝牙的对话提示框
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
//这里写你对应的Activity,我这里只是个例子
Activity.startActivityForResult(intent,7777)
至于接收回调,则是在对应的Activity中的onActivityResult()方法中处理返回结果:
- 返回结果RESULT_OK,蓝牙模块打开成功
- 返回结果RESULT_CANCELED,蓝牙模块打开失败
PS: 测试的时候,用的华为手机,系统为鸿蒙4,Android Studio显示为Android12,但是使用
bluetoothAdapter.enable()却是能够正常弹出申请蓝牙是否打开的对话框
获取已配对的蓝牙设备列表
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
val bluetoothDevices = bluetoothAdapter.bondedDevices
//获取已配对的蓝牙设备列表
bluetoothDevices.forEach { device->
val text = when(device.type){
BluetoothDevice.DEVICE_TYPE_UNKNOWN -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_CLASSIC -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_LE -> "低功耗蓝牙"
BluetoothDevice.DEVICE_TYPE_DUAL -> "传统/低功耗双模式蓝牙"
else->"未知类型"
}
LogUtils.d("蓝牙设备名称: ${device.name} 蓝牙设备地址: ${device.address} 设备类型: $text")
}
获取蓝牙耳机设备列表
fun getEarPhoneDevices(context: Context): List<BluetoothDevice> {
val bluetoothAdapter = context.getSystemService(BluetoothManager::class.java).adapter
val bluetoothDevices = bluetoothAdapter.bondedDevices
val types = listOf(
BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES,
BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET,
BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO,
BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE
)
return bluetoothDevices.filter { device ->
types.any { it == device.bluetoothClass.deviceClass }
}
}
PS: 测试过程中,发现漫步者耳机的类型识别不了为上述的四个类型...
获取当前已连接蓝牙耳机
一般只能连接一个蓝牙耳机
val bluetoothAdapter = getSystemService(BluetoothManager::class.java).adapter
//如果在连接了蓝牙耳机的情况,这里会进入到里面获取到数据
bluetoothAdapter.getProfileProxy(this@EarphoneActivity, object : ServiceListener {
override fun onServiceConnected(p0: Int, p1: BluetoothProfile?) {
p1?.apply {
//获取蓝牙耳机的设备列表
val devices = this.connectedDevices
devices.forEach { device ->
val text = when (device.type) {
BluetoothDevice.DEVICE_TYPE_UNKNOWN -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_CLASSIC -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_LE -> "低功耗蓝牙"
BluetoothDevice.DEVICE_TYPE_DUAL -> "传统/低功耗双模式蓝牙"
else -> "未知类型"
}
LogUtils.d("蓝牙设备名称: ${device.name} 蓝牙设备地址: ${device.address} 设备类型: $text")
}
}
LogUtils.d("设备连接")
}
override fun onServiceDisconnected(p0: Int) {
}
}, BluetoothProfile.HEADSET)
}
获取蓝牙耳机电量
此方法适应市面上大多数蓝牙耳机,但如果是AirPods,则无效果,下一章节会讲到获取AirPods电量方法
(虽然参考的文章说这个是AirPods的扩展AT命令,但实际对于正版AirPods无效果,反倒是我同事的华强北AirPods支持...)
通过注册广播,来获取到对应的AT命令,在参数可以取值
val bluetoothIntentFilter = IntentFilter().apply {
addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
+ addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY+"."+BluetoothAssignedNumbers.APPLE)
+ addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)
}
registerReceiver(BlueToothReceiver(), bluetoothIntentFilter)
广播详情说明可看此链接蓝牙耳机 | 安卓开发者
之后在Receiver可以获取对应的AT命令参数,如下代码:
//蓝牙耳机的广播监听
if (BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT == action) {
Log.d(TAG, "onReceive: 蓝牙设备AT命令")
//蓝牙设备
val blueDevice = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java)
} else {
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
}
blueDevice?.apply {
val device = this
val text = when (device.type) {
BluetoothDevice.DEVICE_TYPE_UNKNOWN -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_CLASSIC -> "传统蓝牙"
BluetoothDevice.DEVICE_TYPE_LE -> "低功耗蓝牙"
BluetoothDevice.DEVICE_TYPE_DUAL -> "传统/低功耗双模式蓝牙"
else -> "未知类型"
}
LogUtils.d("蓝牙设备名称: ${device.name} 蓝牙设备地址: ${device.address} 设备类型: $text")
}
intent.extras?.apply {
val cmd = getString(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD,"")
val cmdType = getInt(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE,0)
//根据命令行类型,会有不同的参数
val cmdTypeStr = when (cmdType) {
BluetoothHeadset.AT_CMD_TYPE_ACTION -> {"AT_CMD_TYPE_ACTION"}
BluetoothHeadset.AT_CMD_TYPE_BASIC -> {"AT_CMD_TYPE_BASIC"}
BluetoothHeadset.AT_CMD_TYPE_READ -> {"AT_CMD_TYPE_READ"}
BluetoothHeadset.AT_CMD_TYPE_SET -> {"AT_CMD_TYPE_SET"}
BluetoothHeadset.AT_CMD_TYPE_TEST -> {"AT_CMD_TYPE_TEST"}
else -> {""}
}
val args = get(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS) as Array<Any>
LogUtils.d("""
接收到的AT命令: AT $cmd $cmdTypeStr ${args.joinToString(",") { it.toString() }}
""".trimIndent())
if (cmd == "+IPHONEACCEV") {
//电量等级说明 0:10% 9:100%
val param = args.map { it.toString().toInt() }
val level = param.last()
//电量
val battery = (level + 1) * 10
}
}
}
AT+IPHONEACCEV命令
该命令是用来提示蓝牙配件的电池状态,可以提示两方面:一方面是电池的电量百分比,一当面是蓝牙配件的当前的充电状态。该命令的说明见下方:
格式:AT+IPHONEACCEV=Number of key/value pairs,key1,val1,key2,val2,…
附带的参数的含义分别是:①键值对的数目:接下来的参数文本的数量;②接下来就是键值对分别是:键值为1表示的是电量,该键所对应的值就是电量百分比,使用字串”0“到”9“表示;键值为2表示的是充电状态,0表示不在充电,1表示正在充电。
举例:AT+IPHONEACCEV=1,1,3 该AT指令就说明附带了一个键值对(第一个参数是1);键是1,那么表示的是电量,且电量是40%(因为使用的是0~9,这里3就对应的百分比是40%)。
有个疑问,AirPods在电量变化后,会主动发送AT命令吗?还是说是在连接后才会发一次,之后便不再发送了?
AT +XAPL AT_CMD_TYPE_SET AB-12-0100,18
AirPods耳机电量
起初一致没找到方案,最终在github上输入了AirPods关键字,发现了有几个对于对应的开源库,测试发现下面这个能够符合要求(不过测试的时候,电量有些误差,充电仓在iphone手机上显示为8%,而android这边则显示为5%)
app原理则是通过蓝牙扫描,获取到蓝牙设备对应的设备厂商数据,并区分型号,然后做对应的处理从而获取到电量(比如说左耳机,右耳机,耳机仓)
通过蓝牙的adapter获取scanner,调用扫描方法,之后在扫描的回调里处理返回结果, 从而得到对应的电量数据
蓝牙扫描还需要一个获取定位的权限(在Android12版本之下需要),不然无法扫描
参考
- Android状态栏显示蓝牙耳机电量 - CodeAntenna
- 苹果公司对蓝牙免提AT指令的扩充 - WestMountain - 博客园
- Bluetooth (Android) 之自定义 AT 指令 – xmamiga
- 如何获得蓝牙耳机的电池电量?
- adolfintel/OpenPods: The Free and Open Source app for monitoring your AirPods on Android
Android 蓝牙使用的更多相关文章
- android蓝牙打印机
您还未登录!|登录|注册|帮助 首页 业界 移动 云计算 研发 论坛 博客 下载 更多 reality_jie的专栏 编程的过程是一种微妙的享受 目录视图 摘要视图 订阅 CSDN2013 ...
- Android蓝牙实例(和单片机蓝牙模块通信)
最近做毕设,需要写一个简单的蓝牙APP进行交互,在网上也找了很多资料,终于给搞定了,这里分享一下^_^. 1.Android蓝牙编程 蓝牙3.0及以下版本编程需要使用UUID,UUID是通用唯一识别码 ...
- Android 蓝牙4.0 BLE
Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是蓝牙4.0的核心Profil ...
- android 蓝牙4.0 开发介绍
最近一直在研究一个蓝牙功能 由于本人是菜鸟 学起来比较忙 一直搞了好久才弄懂 , 网上对蓝牙4.0也就是几个个dome 抄来抄去,全是英文注解 , 对英语不好的朋友来说 真是硬伤 , 一些没必要的描 ...
- 【转】android蓝牙开发---与蓝牙模块进行通信--不错
原文网址:http://www.cnblogs.com/wenjiang/p/3200138.html 近半个月来一直在搞android蓝牙这方面,主要是项目需要与蓝牙模块进行通信.开头的进展很顺利, ...
- Android 蓝牙开发(整理大全)
Android蓝牙开发 鉴于国内Android蓝牙开发的例子很少,以及蓝牙开发也比较少用到,所以找的资料不是很全. (一): 由于Android蓝牙的通信都需要用到UUID,如果由手机发起搜索,当搜索 ...
- android -- 蓝牙 bluetooth (四)OPP文件传输
在前面android -- 蓝牙 bluetooth (一) 入门文章结尾中提到了会按四个方面来写这系列的文章,前面已写了蓝牙打开和蓝牙搜索,这次一起来看下蓝牙文件分享的流程,也就是蓝牙应用opp目录 ...
- android -- 蓝牙 bluetooth (三)搜索蓝牙
接上篇打开蓝牙继续,来一起看下蓝牙搜索的流程,触发蓝牙搜索的条件形式上有两种,一是在蓝牙设置界面开启蓝牙会直接开始搜索,另一个是先打开蓝牙开关在进入蓝牙设置界面也会触发搜索,也可能还有其它触发方式,但 ...
- android -- 蓝牙 bluetooth (一) 入门
前段时间在 网上看了一些关于android蓝牙的文章,发现大部分是基于老版本(4.1以前含4.1)的源码,虽然无碍了解蓝牙的基本原理和工作流程,但对着4.2.2的代码看起来总是有些遗憾.所以针对4.2 ...
- 深入了解Android蓝牙Bluetooth——《基础篇》
什么是蓝牙? 也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的.利用"蓝牙"技术,能够有效地简化掌上电脑.笔记本电 ...
随机推荐
- oracle问题:ORA-09817及解决办法
某天以管理员身份登录公司测试库报ORA-09817错误,查了网上的文章说是审计文件没有存储空间造成的.我的这问题也证实了这一点,现将解决步骤分享: 1.发现问题:报ORA-09817 oracle@l ...
- 其它——Apache-ab压力测试工具使用
文章目录 一 介绍 二 安装 2.1 windows安装 2.2 Linux安装 三 使用 四 参数介绍 一 介绍 Apache Benchmark(简称ab) 是Apache安装包中自带的压力测试工 ...
- Java也能做OCR!SpringBoot 整合 Tess4J 实现图片文字识别
前言 今天给大家分享一个SpringBoot整合Tess4j库实现图片文字识别的小案例,希望xdm喜欢. 文末有案例代码的Git地址,可以自己下载了去玩玩儿或继续扩展也行. 话不多说,开整吧. 什么是 ...
- 关于Android Stuido2.3和Eclipse4.4
近3年没有做Android开发了,当时用是ECLISPE电脑配置2g,用的还可以. 现在又重新开始做安卓程序,发现大家都用AS了,作为技术人员,也就开始用了. (几年前AS已经发布,不过是0.x版本, ...
- zabbix监控Tomcat/JVM 实例性能
1.背景 zabbix-4.0 环境已部署好 JDK .Tomcat环境已部署好 2.配置Tomcat JMX 编辑catalina.sh加入以下配置 # vim /usr/local/tomcat/ ...
- 未能添加SSL证书,错误1312
1.win+r打开运行,输入mmc 2.在控制台1[控制台根节点]->文件->添加/删除....->选择证书->添加-选择计算机账户->完成->确认 3.找到证书文 ...
- 如何在Excel中实现三联类模板?
本文由葡萄城技术团队原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 在一些报表打印应用场景中,会有类似于如下图所示的排版格式: 一般情况下 ...
- 解密Prompt系列18. LLM Agent之只有智能体的世界
重新回来聊Agent,前四章的LLM Agent,不论是和数据库和模型还是和搜索引擎交互,更多还是大模型和人之间的交互.这一章我们来唠唠只有大模型智能体的世界!分别介绍斯坦福小镇和Chatdev两篇论 ...
- SNN_TIPS
脉冲神经网络的研究思路: ANN2SNN 代表: 梯度下降法 代表: STDP 代表: 神经网络代差划分 以神经元实现功能为准: 优势 SNN是一个动态系统,在动态识别中发挥出色,比如语音识别和动态图 ...
- 如何正确执行 DORA 指标
DevOps 研究与 DORA 评估指标可帮助我们深入了解软件开发和交付流程的性能和效率.这些指标包括部署频率.变更交付时间.变更失败率和平均恢复时间等方面.DORA 指标对于管理开发团队(从团队领导 ...