• 手记 | 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.utilsimport android.bluetooth.BluetoothAdapterimport android.bluetooth.BluetoothDeviceimport android.bluetooth.BluetoothProfileimport android.content.Contextimport android.media.AudioManagerimport android.util.Logimport 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.receiverimport android.bluetooth.BluetoothAdapterimport android.bluetooth.BluetoothDeviceimport android.content.BroadcastReceiverimport android.content.Contextimport android.content.Intentimport android.content.IntentFilterimport android.util.Logimport com.hlq.bluetoothpro.utils.checkBluetoothStateEnableimport com.hlq.bluetoothpro.utils.fetchAlReadyConnectionimport com.hlq.bluetoothpro.utils.getConnectedBtDeviceimport 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.bluetoothproimport android.content.IntentFilterimport androidx.appcompat.app.AppCompatActivityimport android.os.Bundleimport android.util.Logimport com.hlq.bluetoothpro.receiver.BluetoothReceiverimport 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 3E/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

  • 蓝牙概览
  • 蓝牙低功耗概览