Android 蓝牙使用

这篇具有很好参考价值的文章主要介绍了Android 蓝牙使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文地址: Android 蓝牙使用 - Stars-One的杂货小窝

公司项目需求需要实现监听蓝牙耳机连接,且要获取蓝牙耳机电量功能,翻了不少官方文档,记录下技术调研代码

注:本文没有研究蓝牙配对功能

关于蓝牙权限适配

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%)

  • adolfintel/OpenPods: The Free and Open Source app for monitoring your AirPods on Android

app原理则是通过蓝牙扫描,获取到蓝牙设备对应的设备厂商数据,并区分型号,然后做对应的处理从而获取到电量(比如说左耳机,右耳机,耳机仓)

通过蓝牙的adapter获取scanner,调用扫描方法,之后在扫描的回调里处理返回结果, 从而得到对应的电量数据

蓝牙扫描还需要一个获取定位的权限(在Android12版本之下需要),不然无法扫描文章来源地址https://www.toymoban.com/news/detail-776914.html

参考

  • Android状态栏显示蓝牙耳机电量 - CodeAntenna
  • 苹果公司对蓝牙免提AT指令的扩充 - WestMountain - 博客园
  • Bluetooth (Android) 之自定义 AT 指令 – xmamiga
  • 如何获得蓝牙耳机的电池电量?
  • adolfintel/OpenPods: The Free and Open Source app for monitoring your AirPods on Android

到了这里,关于Android 蓝牙使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【沁恒蓝牙mesh】CH58x flash分区之利用随机数作为蓝牙mesh地址

    本文主要介绍了 沁恒蓝牙芯片 CH58x 的flash 分区与数据存储管理,利用随机数作为蓝牙mesh地址,蓝牙mesh采用自组网 📋 个人简介 💖 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。😎 📝 个人主页:欢迎访问我的 Ethernet_Comm 博客主页🔥 🎉 支持我:点赞👍+收藏⭐

    2024年02月13日
    浏览(49)
  • uniapp:蓝牙设备ios与安卓端deviceId不一致问题及ios端获取蓝牙mac地址方法

    在uniapp开发项目中,主要是指APP端,使用API接口: uni.getBluetoothDevices 或者 uni.onBluetoothDeviceFound 查找到的蓝牙设备数据里deviceId值不一样: 在安卓中deviceId即mac地址 在ios中deviceId即uuid 如何在ios端也能获取到mac地址? 通常情况下,蓝牙设备必定是有独一无二的mac地址,只是在

    2024年02月09日
    浏览(48)
  • Android模拟蓝牙蓝牙键盘——适配Android和Windows

    学校寒假有个程序设计比赛,我也一直想要去写一个安卓模拟的蓝牙键盘,这样无论到哪里,比如班班通和没有键盘的电脑设备,有手机就可以操作它,也比USB方便一些。忙活了一个寒假,也走了不少歪路,终于整成了,下面分享一些经验。 (学校的软件设计比赛已经交了终

    2024年04月28日
    浏览(38)
  • ios开发 swift5 苹果手机怎样获取蓝牙设备的mac地址

    如设备蓝牙名为: 蓝牙名_mac app这边展示蓝牙名的时候,就只展示 蓝牙名 , 去掉后面的 _mac 其他用到蓝牙名的地方,都用这样的方式处理 如下图,箭头部分就是广播出的mac地址 如果不是通过搜索获取到peripheral,而是通过retrievePeripherals方法获取到peripheral。这个时候就只能获

    2024年02月03日
    浏览(53)
  • Android 9.0 蓝牙功能之一:蓝牙设置

    本章节记录如何构建蓝牙设置。 注意蓝牙应用必须是 System App。 LocalBluetoothManager 是操作蓝牙的主要入口。 1.通过 LocalBluetoothManager,可以获取到LocalBluetoothAdapter;CachedBluetoothDeviceManager;BluetoothEventManager、LocalBluetoothProfileManager。 2.通过 BluetoothEventManager.registerCallback 注册回调,

    2023年04月24日
    浏览(47)
  • 蓝牙通信 Android开发实现手机间通过蓝牙传输文件

    MainActivity.java 根据以上代码的结构和功能,我会将它们分为以下几部分: 权限请求和检查 requestPermissions() 方法 checkLocationPermission() 方法 onRequestPermissionsResult() 方法 初始化和设置 onCreate() 方法 onStart() 方法 onActivityResult() 方法 蓝牙设备搜索和配对 discoverDevices() 方法 与列表交互

    2024年03月27日
    浏览(51)
  • Android 蓝牙权限(更新到 Android 12)

    https://developer.android.com/guide/topics/connectivity/bluetooth/permissions BLUETOOTH :访问蓝牙适配器的权限,用于执行蓝牙操作。 BLUETOOTH_ADMIN :管理蓝牙适配器的权限,包括启用/禁用蓝牙、扫描设备和进行配对等操作。 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION :访问设备位置的权限。在 And

    2024年02月16日
    浏览(44)
  • Android 蓝牙广播

    ( BluetoothAdapter.ACTION_STATE_CHANGED ):当蓝牙状态发生变化时发送,可以用于检测蓝牙的开启或关闭状态。 提供了以下 Extra 值来描述相关信息: BluetoothAdapter.EXTRA_STATE: 表示蓝牙的当前状态。你可以使用 intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) 来获取该值。其可

    2024年02月16日
    浏览(37)
  • Android 蓝牙状态的监听

    客户在使用我公司的Flutter插件时,要求有一个蓝牙与设备重连的功能,我用公司提供的Android SDK只能实现超出和进入蓝牙范围进行重连,但是无法在蓝牙打开进行重连,这不得不让我使用Android手写一个广播监听。 1. 添加权限 2. 创建一个类继承 BroadcastReceiver 3. 动态注册和注销

    2024年02月10日
    浏览(45)
  • Android蓝牙BLE开发

    最近正在研究Android的蓝牙BLE开发学习,以下是自己做的个人总结 首先得说明什么是低功耗蓝牙BLE,BLE的全称为Bluetooth low energy(或称Blooth LE,BLE),从英文全称便可以知晓其是一种低功耗的蓝牙技术,是蓝牙技术联盟设计和销售的一种个人局域网技术,旨在用于医疗保健、运

    2023年04月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包