- 手记 | MobPush 接入总结
- Gradle 手记|盘点我应用过的 build 根本配置(不断更新中。。。
- Git 手记 | 总结集体日常开发罕用到的一些命令(不断更新。。。
- Utils 手记 | Android Studio 插件整顿(不断更新中 …
- 手记|Kotlin 根底类型回顾
- 手记|Android 获取已配对蓝牙列表和已连贯蓝牙名称
序
最近正好我的项目有蓝牙需要,折腾了小一会儿,特意记录一下~
网上好多搜寻到的文章没法用,难堪死。。。或者就是 Java 版本,转 Kotlin 多少有点坑,不过更加加深了要好好学习一下 Kotlin 的想法~
附上脑图:
Demo GitHub 地址:
- https://github.com/HLQ-Strugg…
蓝牙简述
蓝牙的呈现,让挪动设施多了一种替换数据的形式,而 Android 利用能够通过 Bluetooth Api 执行如下操作:
- 扫描其余蓝牙设施
- 查问本地蓝牙适配器的配对蓝牙设施
- 建设 RFCOMM 通道
- 通过服务发现连贯到其余设施
- 与其余设施进行双向数据传输
- 治理多个连贯
而咱们明天,次要是进行第二点,查问本地蓝牙适配器的配对蓝牙设施。
传统的蓝牙实用于较为耗电的操作,其中包含 Android 设施之间的流式传输和通信等。而针对具备低功耗要求的蓝牙设施,Android 4.3(API 18)中引入面向低功耗蓝牙的 API 反对。
1、基础知识
为了让蓝牙设施能够在彼此之间传输数据,必须先通过配对过程造成通道。
其中一台设施须要将本身设置为可接管传入的连贯申请,另一台设施则通过服务发现过程并找到可检测的设施。
随后在检测到的设施承受配对申请后,设施之间实现绑定操作,并在此期间替换平安密钥。 二者会缓存这些密钥,以供日后应用。
实现配对和绑定过程后,两台设施会替换信息。
当会话实现时,发动配对申请的设施会将其链接到可检测设施的通道。
并且这俩台设施依然放弃绑定状态, 因而在将来的会话期间,只有两者在彼此的范畴内且均为移除绑定,便会主动连贯。
2、蓝牙权限
根底权限必须申明:
<uses-permission android:name="android.permission.BLUETOOTH" />
如果想对蓝牙进行相干操作,比方关上蓝牙等,须要配置如下权限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
而当利用须要扫描其余设施时,须要申明如下权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
这里须要留神的:
- 如果利用适配 Android 9(Api 28)或者更低版本,则能够申明 ACCESS_COARSE_LOCATION 权限,而非 ACCESS_FINE_LOCATION 权限。
如果须要申明以后利用仍然实用于不反对 BLE 的设施,则须要在权限中增加如下元素:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
蓝牙 Demo 搞起(获取已配对列表以及已连贯蓝牙名称)
1、必不可少的权限
<uses-permission android:name="android.permission.BLUETOOTH" />
2、工具类
package com.hlq.bluetoothpro.utils
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.media.AudioManager
import android.util.Log
import java.lang.reflect.InvocationTargetException
/**
* @author:HLQ_Struggle
* @date:2021/8/29
* @desc:*/
private var mBluetoothAdapter: BluetoothAdapter? = null
/**
* 实例化 BluetoothAdapter
*/
private fun getInstance(): BluetoothAdapter? {if (mBluetoothAdapter == null) {mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
}
return mBluetoothAdapter
}
/**
* 检测设施是否反对蓝牙
*/
fun checkBluetoothEnable(): Boolean {return getInstance() == null
}
/**
* 判断以后蓝牙是否关上
*/
fun checkBluetoothStateEnable(): Boolean {return getInstance()?.isEnabled == true
}
/**
* 获取蓝牙耳机连贯状态
*/
private fun isWiredHeadsetConnected(context: Context): Boolean {
try {val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
return audioManager.isWiredHeadsetOn
} catch (e: Exception) { }
return false
}
/**
* 判断蓝牙耳机是否已连贯
*/
fun hasBluetoothAudioDevice(): Boolean {val adapter = BluetoothAdapter.getDefaultAdapter()
var a2dp = false
var headset = false
try {
a2dp =
adapter.getProfileConnectionState(BluetoothProfile.A2DP) != BluetoothProfile.STATE_DISCONNECTED
headset =
adapter.getProfileConnectionState(BluetoothProfile.HEADSET) != BluetoothProfile.STATE_DISCONNECTED
} catch (e: Throwable) { }
return a2dp || headset
}
/**
* 获取到已配对胜利蓝牙设施
*/
fun fetchAlReadyConnection() {getInstance()?.let {
val devices = it.bondedDevices
for (device in devices) {
Log.e(
"HLQ", "---->" +
"name ${device.name}" +
"address ${device.address}" +
"bondState ${device.bondState}" +
"type ${device.type} ${device.uuids.size}"
)
}
}
}
fun getConnectedBtDevice(): String? {
// 获取蓝牙适配器
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
// 失去已匹配的蓝牙设施列表
val bondedDevices = bluetoothAdapter.bondedDevices
if (bondedDevices != null && bondedDevices.size > 0) {for (bondedDevice in bondedDevices) {
try {
// 应用反射调用被暗藏的办法
val isConnectedMethod =
BluetoothDevice::class.java.getDeclaredMethod("isConnected")
isConnectedMethod.isAccessible = true
val isConnected =
isConnectedMethod.invoke(bondedDevice) as Boolean
if (isConnected) {return bondedDevice.name}
} catch (e: NoSuchMethodException) {e.printStackTrace()
} catch (e: IllegalAccessException) {e.printStackTrace()
} catch (e: InvocationTargetException) {e.printStackTrace()
}
}
}
return null
}
3、创立监听蓝牙播送
package com.hlq.bluetoothpro.receiver
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.util.Log
import com.hlq.bluetoothpro.utils.checkBluetoothStateEnable
import com.hlq.bluetoothpro.utils.fetchAlReadyConnection
import com.hlq.bluetoothpro.utils.getConnectedBtDevice
import com.hlq.bluetoothpro.utils.hasBluetoothAudioDevice
/**
* @author:HLQ_Struggle
* @date:2021/8/28
* @desc:*/
class BluetoothReceiver : BroadcastReceiver() {
companion object {fun registerIntentFilter(): IntentFilter {val intentFilter = IntentFilter()
intentFilter.apply {addAction(BluetoothAdapter.ACTION_STATE_CHANGED); // 蓝牙状态扭转
addAction("android.bluetooth.BluetoothAdapter.STATE_OFF"); // 本地蓝牙适配器已敞开
addAction("android.bluetooth.BluetoothAdapter.STATE_ON"); // 本地蓝牙适配器已关上,能够应用
addAction(BluetoothDevice.ACTION_ACL_CONNECTED); // 已和近程设施建设 ACL 连贯
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); // 与近程设施 ACL 断开连接
priority = Int.MAX_VALUE
}
return intentFilter
}
}
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
action ?: return
val bluetoothLog = when (action) {
BluetoothAdapter.ACTION_STATE_CHANGED -> { // 监听蓝牙状态
when (val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0)) {
BluetoothAdapter.STATE_TURNING_ON -> {"STATE_TURNING_ON 蓝牙开启中"}
BluetoothAdapter.STATE_ON -> {"STATE_ON 蓝牙开启"}
BluetoothAdapter.STATE_CONNECTING -> {"STATE_CONNECTING 蓝牙连贯中"}
BluetoothAdapter.STATE_CONNECTED -> {"STATE_CONNECTED 蓝牙已连贯"}
BluetoothAdapter.STATE_DISCONNECTING -> {"STATE_DISCONNECTING 蓝牙断开中"}
BluetoothAdapter.STATE_DISCONNECTED -> {"STATE_DISCONNECTED 蓝牙已断开"}
BluetoothAdapter.STATE_TURNING_OFF -> {"STATE_TURNING_OFF 蓝牙敞开中"}
BluetoothAdapter.STATE_OFF -> {"STATE_OFF 蓝牙敞开"}
else -> "ACTION_STATE_CHANGED EXTRA_STATE $state"
}
}
BluetoothDevice.ACTION_ACL_CONNECTED -> { // 蓝牙已连贯
Log.e("HLQ", "----> ACTION_ACL_CONNECTED 蓝牙已连贯") // 蓝牙已关上 且 已连贯
Log.e("HLQ", "----> 蓝牙已关上且已连贯")
Log.e("HLQ", "----> 输入已配对胜利蓝牙列表")
Log.e("HLQ", "----> ${fetchAlReadyConnection()}")
"----> 以后连贯蓝牙名称:${getConnectedBtDevice()}"
}
BluetoothDevice.ACTION_ACL_DISCONNECTED -> { // 蓝牙已断开
"ACTION_ACL_DISCONNECTED 蓝牙已断开"
}
else -> "action $action"
}
Log.e("HLQ", "----> bluetoothLog $bluetoothLog")
}
}
4、蓝牙注册、移除以及获取
package com.hlq.bluetoothpro
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.hlq.bluetoothpro.receiver.BluetoothReceiver
import com.hlq.bluetoothpro.utils.*
class MainActivity : AppCompatActivity() {
/**
* 蓝牙监听 行车模式
*/
private var mBluetoothFilter: IntentFilter? = null
private var mBluetoothReceiver: BluetoothReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handleBluetooth()}
private fun handleBluetooth() {
// 验证以后设施是否反对蓝牙 反对便进行初始化
if (!checkBluetoothEnable()) {Log.e("HLQ", "----> 以后设施反对蓝牙")
initBluetooth()
if (checkBluetoothStateEnable() && hasBluetoothAudioDevice()) { // 蓝牙已关上 且 已连贯
Log.e("HLQ", "----> 蓝牙已关上且已连贯")
Log.e("HLQ", "----> 输入已配对胜利蓝牙列表")
Log.e("HLQ", "----> ${fetchAlReadyConnection()}")
Log.e("HLQ", "----> 以后连贯蓝牙名称:${getConnectedBtDevice()}")
}
}
}
/**
* 初始化行车模式 蓝牙监听
*/
private fun initBluetooth() {if (mBluetoothReceiver == null) {mBluetoothReceiver = BluetoothReceiver()
}
if (mBluetoothFilter == null) {mBluetoothFilter = BluetoothReceiver.registerIntentFilter()
}
if (mBluetoothReceiver != null && mBluetoothFilter != null) {registerReceiver(mBluetoothReceiver, mBluetoothFilter)
}
}
override fun onDestroy() {super.onDestroy()
// 清理蓝牙播送
if (mBluetoothReceiver != null) {unregisterReceiver(mBluetoothReceiver)
mBluetoothReceiver = null
}
}
}
来吧,日志展现
- 当蓝牙已关上且蓝牙已连贯
E/HLQ: ----> 以后设施反对蓝牙
E/HLQ: ----> 输入已配对胜利蓝牙列表
E/HLQ: ----> 蓝牙已关上且已连贯
E/HLQ: ----> name Earbuds X1 address E0:9D:FA:CA:4C:DF bondState 12 type 1 3
E/HLQ: ----> 以后连贯蓝牙名称:Earbuds X1
- 当蓝牙已关上且开始连贯蓝牙(之前配对胜利过,主动连贯)
E/HLQ: ----> 以后设施反对蓝牙
E/HLQ: ----> 蓝牙已关上且已连贯
E/HLQ: ----> 输入已配对胜利蓝牙列表
E/HLQ: ----> name Earbuds X1 address E0:9D:FA:CA:4C:DF bondState 12 type 1 3
E/HLQ: ----> 以后连贯蓝牙名称:Earbuds X1
- 再来个蓝牙开关展现
E/HLQ: ----> bluetoothLog STATE_TURNING_OFF 蓝牙敞开中
E/HLQ: ----> bluetoothLog STATE_OFF 蓝牙敞开
E/HLQ: ----> bluetoothLog STATE_TURNING_ON 蓝牙开启中
E/HLQ: ----> bluetoothLog STATE_ON 蓝牙开启
E/HLQ: ----> ACTION_ACL_CONNECTED 蓝牙已连贯
E/HLQ: ----> 蓝牙已关上且已连贯
E/HLQ: ----> 输入已配对胜利蓝牙列表
E/HLQ: ----> name Earbuds X1 address E0:9D:FA:CA:4C:DF bondState 12 type 1 3
E/HLQ: ----> kotlin.Unit
E/HLQ: ----> bluetoothLog ----> 以后连贯蓝牙名称:Earbuds X1
THK
- 蓝牙概览
- 蓝牙低功耗概览