Android:蓝牙设置配套设备配对

news2025/3/26 2:11:29

一、概述

在搭载 Android 8.0(API 级别 26)及更高版本的设备上,配套设备配对会代表您的应用对附近的设备执行蓝牙或 Wi-Fi 扫描,而不需要 ACCESS_FINE_LOCATION 权限。这有助于最大限度地保护用户隐私。使用此方法执行配套设备(如支持 BLE 的智能手表)的初始配置。此外,配套设备配对需要启用位置信息服务。

配对配套设备不会自行创建连接,也不会启用连续扫描。应用可以使用蓝牙或 Wi-Fi 连接 API 建立连接。

配对设备后,设备可以使用 REQUEST_COMPANION_RUN_IN_BACKGROUND 和 REQUEST_COMPANION_USE_DATA_IN_BACKGROUND 权限从后台启动应用。应用还可以使用 REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限从后台启动前台服务。

用户可以从列表中选择设备,并向应用授予访问该设备的权限。如果您卸载应用或调用 disassociate(),系统会撤消这些权限。如果用户不再需要配套应用的关联(例如在用户退出账号或移除已绑定的设备时),配套应用负责清除自己的关联。

二、实现配套设备配对

本部分介绍了如何使用 CompanionDeviceManager 通过蓝牙、BLE 和 Wi-Fi 将应用与配套设备配对。

指定配套设备
以下代码示例展示了如何向清单文件添加 <uses-feature> 标志。这会告知系统您的应用打算设置配套设备。

<uses-feature android:name="android.software.companion_device_setup"/>

按 DeviceFilter 列出设备
您可以显示与您提供的 DeviceFilter 匹配的所有在范围内的配套设备(如图 1 所示)。如果您想将扫描范围限制为一台设备,可以将 setSingleDevice() 设为 true(如图 2 所示)。

图1 配套设备配对

在这里插入图片描述

图 2. 单设备配对

在这里插入图片描述

以下是可在 AssociationRequest 中指定的 DeviceFilter 的子类:

  • BluetoothDeviceFilter
  • BluetoothLeDeviceFilter
  • WifiDeviceFilter

这三个子类都有用于简化过滤器配置的构建器。在以下示例中,设备使用 BluetoothDeviceFilter 扫描蓝牙设备。

val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
        // Match only Bluetooth devices whose name matches the pattern.
        .setNamePattern(Pattern.compile("My device"))
        // Match only Bluetooth devices whose service UUID matches this pattern.
        .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
        .build()

将 DeviceFilter 设置为 AssociationRequest,以便 CompanionDeviceManager 确定要搜索的设备类型。

val pairingRequest: AssociationRequest = AssociationRequest.Builder()
        // Find only devices that match this request filter.
        .addDeviceFilter(deviceFilter)
        // Stop scanning as soon as one device matching the filter is found.
        .setSingleDevice(true)
        .build()

应用初始化 AssociationRequest 后,请对 CompanionDeviceManager 运行 associate() 函数。associate() 函数接受 AssociationRequest 和 Callback。

当 CompanionDeviceManager 定位到设备且准备好启动用户意见征求对话框时,Callback 会在 onAssociationPending 中返回 IntentSender。用户确认设备后,系统会在 onAssociationCreated 中返回设备的 AssociationInfo。如果您的应用找不到任何设备,回调会返回 onFailure 和错误消息。

在搭载 Android 13(API 级别 33)及更高版本的设备上:

val deviceManager =
  requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE)

val executor: Executor =  Executor { it.run() }

deviceManager.associate(pairingRequest,
    executor,
    object : CompanionDeviceManager.Callback() {
    // Called when a device is found. Launch the IntentSender so the user
    // can select the device they want to pair with.
    override fun onAssociationPending(intentSender: IntentSender) {
        intentSender?.let {
             startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
        }
    }

    override fun onAssociationCreated(associationInfo: AssociationInfo) {
        // An association is created.
    }

    override fun onFailure(errorMessage: CharSequence?) {
        // To handle the failure.
     }
})

在搭载 Android 12L(API 级别 32)或更低版本的设备上(已废弃):

val deviceManager =
      requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE)

deviceManager.associate(pairingRequest,
    object : CompanionDeviceManager.Callback() {
        // Called when a device is found. Launch the IntentSender so the user
        // can select the device they want to pair with.
        override fun onDeviceFound(chooserLauncher: IntentSender) {
            startIntentSenderForResult(chooserLauncher,
                SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
        }

        override fun onFailure(error: CharSequence?) {
            // To handle the failure.
        }
    }, null)

用户选择的结果会发送回 activity 的 onActivityResult() 中的 fragment。然后,您就可以访问所选设备了。

当用户选择蓝牙设备时,应显示 BluetoothDevice。当用户选择蓝牙 LE 设备时,会遇到 android.bluetooth.le.ScanResult。当用户选择 Wi-Fi 设备时,应显示 android.net.wifi.ScanResult。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    when (requestCode) {
        SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
            Activity.RESULT_OK -> {
                // The user chose to pair the app with a Bluetooth device.
                val deviceToPair: BluetoothDevice? =
data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                deviceToPair?.let { device ->
                    device.createBond()
                    // Continue to interact with the paired device.
                }
            }
        }
        else -> super.onActivityResult(requestCode, resultCode, data)
    }
}

查看完整示例:

在搭载 Android 13(API 级别 33)及更高版本的设备上:

private const val SELECT_DEVICE_REQUEST_CODE = 0

class MainActivity : AppCompatActivity() {

    private val deviceManager: CompanionDeviceManager by lazy {
        getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager
    }
    val mBluetoothAdapter: BluetoothAdapter by lazy {
        val java = BluetoothManager::class.java
        getSystemService(java)!!.adapter }
    val executor: Executor =  Executor { it.run() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // To skip filters based on names and supported feature flags (UUIDs),
        // omit calls to setNamePattern() and addServiceUuid()
        // respectively, as shown in the following  Bluetooth example.
        val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
            .setNamePattern(Pattern.compile("My device"))
            .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
            .build()

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of them appears.
        val pairingRequest: AssociationRequest = AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build()

        // When the app tries to pair with a Bluetooth device, show the
        // corresponding dialog box to the user.
        deviceManager.associate(pairingRequest,
            executor,
            object : CompanionDeviceManager.Callback() {
                // Called when a device is found. Launch the IntentSender so the user
                // can select the device they want to pair with.
                override fun onAssociationPending(intentSender: IntentSender) {
                intentSender?.let {
                    startIntentSenderForResult(it, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
              }
            }

             override fun onAssociationCreated(associationInfo: AssociationInfo) {
                 // AssociationInfo object is created and get association id and the
                 // macAddress.
                 var associationId: int = associationInfo.id
                 var macAddress: MacAddress = associationInfo.deviceMacAddress
             }
             override fun onFailure(errorMessage: CharSequence?) {
                // Handle the failure.
            }
    )

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
                Activity.RESULT_OK -> {
                    // The user chose to pair the app with a Bluetooth device.
                    val deviceToPair: BluetoothDevice? =
                        data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                    deviceToPair?.let { device ->
                        device.createBond()
                        // Maintain continuous interaction with a paired device.
                    }
                }
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

在搭载 Android 12L(API 级别 32)或更低版本的设备上(已废弃):

private const val SELECT_DEVICE_REQUEST_CODE = 0

class MainActivity : AppCompatActivity() {

    private val deviceManager: CompanionDeviceManager by lazy {
        getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // To skip filters based on names and supported feature flags (UUIDs),
        // omit calls to setNamePattern() and addServiceUuid()
        // respectively, as shown in the following  Bluetooth example.
        val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
            .setNamePattern(Pattern.compile("My device"))
            .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null)
            .build()

        // The argument provided in setSingleDevice() determines whether a single
        // device name or a list of them appears.
        val pairingRequest: AssociationRequest = AssociationRequest.Builder()
            .addDeviceFilter(deviceFilter)
            .setSingleDevice(true)
            .build()

        // When the app tries to pair with a Bluetooth device, show the
        // corresponding dialog box to the user.
        deviceManager.associate(pairingRequest,
            object : CompanionDeviceManager.Callback() {

                override fun onDeviceFound(chooserLauncher: IntentSender) {
                    startIntentSenderForResult(chooserLauncher,
                        SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0)
                }

                override fun onFailure(error: CharSequence?) {
                    // Handle the failure.
                }
            }, null)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            SELECT_DEVICE_REQUEST_CODE -> when(resultCode) {
                Activity.RESULT_OK -> {
                    // The user chose to pair the app with a Bluetooth device.
                    val deviceToPair: BluetoothDevice? =
                        data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
                    deviceToPair?.let { device ->
                        device.createBond()
                        // Maintain continuous interaction with a paired device.
                    }
                }
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

三、配套设备配置文件

在 Android 12(API 级别 31)及更高版本中,用于管理手表等设备的配套应用可以使用配套设备配置文件,通过在配对时授予必要的权限来简化设置流程。如需了解详情,请参阅配套设备配置文件。

四、使配套应用保持唤醒状态

在 Android 12(API 级别 31)及更高版本中,您可以使用其他 API 来帮助配套应用在配套设备在范围内时保持运行。借助这些 API,您可以执行以下操作:

  • 当配套设备处于范围内时,唤醒您的应用。
    如需了解详情,请参阅 CompanionDeviceManager.startObservingDevicePresence()。
  • 保证只要配套设备保持在范围内,应用进程将继续运行。
    如需了解详情,请参阅 CompanionDeviceService.onDeviceAppeared()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 变量作用域、global 关键字与闭包作用域深度解析 第三部分

## 三、闭包作用域的存在原因及适用场景 ### 3.1 闭包作用域存在的原因 #### 3.1.1 数据封装与隐藏 闭包可以把数据封装在外部函数的作用域中&#xff0c;只有内部函数能够访问这些数据&#xff0c;这有助于实现数据的隐藏和保护。 python def counter(): count 0 def incre…

zookeeper使用

下载 官网 链接 1. 2. 然后解压&#xff1a; 启动 先复制一份这个文件&#xff0c; 双击启动 默认占用8080&#xff0c;和Tomcat冲突&#xff0c; 解决方法&#xff1a;链接 然后重启

使用BootStrap 3的原创的模态框组件,没法弹出!估计是原创的bug

最近在给客户开发一个CRM系统&#xff0c;其中用到了BOOTSTRAP的模态框。版本是3。由于是刚开始用该框架。所以在正式部署到项目中前&#xff0c;需要测试一下&#xff0c;找到框架中的如下部分。需要说明的是。我用的asp.net mvc框架开发。测试也是在asp.net mvc环境下。 复制…

【Azure 架构师学习笔记】- Azure Networking(1) -- Service Endpoint 和 Private Endpoint

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Networking】系列。 前言 最近公司的安全部门在审计云环境安全性时经常提到service endpoint&#xff08;SE&#xff09;和priavate endpoint&#xff08;PE&#xff09;的术语&#xff0c;为此做了一些研究储备。 云…

Excel第41套全国人口普查

2. 导入网页中的表格&#xff1a;数据-现有链接-考生文件夹&#xff1a;网页-找到表格-点击→变为√-导入删除外部链接关系&#xff1a;数据-点击链接-选中连接-删除-确定&#xff08;套用表格格式-也会是删除外部链接&#xff09;数值缩小10000倍&#xff08;除以10000即可&am…

VUE2导出el-table数据为excel并且按字段分多个sheet

首先在根目录下建一个文件夹export用来存储export.js import * as XLSX from xlsxfunction autoWidthFunc(ws, data) {// 设置每列的最大宽度const colWidth data.map(row > row.map(val > {var reg new RegExp([\\u4E00-\\u9FFF], g) // 检测字符串是否包含汉字if (v…

PDF文件转Markdown,基于开源项目marker

​ 首先我们来问下deepseek 为啥要选marker呢 基于深度学习&#xff0c;一看就逼格拉满。搞科研必备&#xff0c;效果应该不会太差。 看下官网 https://github.com/VikParuchuri/marker ​ 一看头像是个印度佬&#xff0c;自吹——又快又好。那就试试吧。 安装步骤 安装…

【蓝桥杯速成】| 9.回溯升级

题目一&#xff1a;组合综合 问题描述 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返…

【uni-app】引用公共组件

目录 一、建立公共组件 1.1新建vue文件 1.2编写公共文件代码 1.3使用 注意事项 一、建立公共组件 1.1新建vue文件 在公共组件文件目录下新建所需要的功能文件 1.2编写公共文件代码 按需求写对应功能的代码 1.3使用 在需要使用的文件下引用公共组件 注意事项 想要使用s…

API-Arrays

Arrays 操作数组的工具类 1.tostring import java.util.Arrays;public class demo1 {public static void main(String[] args) {Integer[] arr {2, 3, 1, 5, 6, 7, 8, 4, 9};System.out.println(Arrays.toString(arr));//[2, 3, 1, 5, 6, 7, 8, 4, 9]} } 2.binarySearch 二…

尝试在软考62天前开始成为软件设计师-信息系统安全

安全属性 保密性:最小授权原则(能干活的最小权限)、防暴露(隐藏)、信息加密、物理保密完整性(防篡改):安全协议、校验码、密码校验、数字签名、公证 可用性:综合保障( IP过滤、业务流控制、路由选择控制、审计跟踪)不可抵赖性:数字签名 对称加密 DES :替换移位 3重DESAESR…

dsPIC33CK64MC105 Curiosity Nano|为高性能数字电源与电机控制而生

「dsPIC33CK64MC105 Curiosity Nano」面向高性能数字电源与电机控制而生 dsPIC33CK64MC105 Curiosity Nano 该评估套件是一个经济高效的硬件平台&#xff0c;用于评估dsPIC33CK系列高性能数字信号控制器&#xff08;DSC&#xff09;。该板采用 100 MHz dsPIC33CK64MC105 DSC&am…

《面向车险理赔的事故信息提取》开题报告

个人主页&#xff1a;大数据蟒行探索者 目录 一、选题的依据及意义 二、国内外研究概况及发展趋势 &#xff08;1&#xff09;车牌识别技术 &#xff08;2&#xff09;证件信息提取技术 &#xff08;3&#xff09;交通事故认定书文本提取 三、研究内容及实验方案 1.研究…

【AI神经网络】深度神经网络(DNN)技术解析:从原理到实践

引言 深度神经网络&#xff08;Deep Neural Network, DNN&#xff09;作为人工智能领域的核心技术&#xff0c;近年来在计算机视觉、自然语言处理、医疗诊断等领域取得了突破性进展。与传统机器学习模型相比&#xff0c;DNN通过多层非线性变换自动提取数据特征&#xff0c;解决…

EasyRTC轻量级Webrtc音视频通话SDK,助力带屏IPC在嵌入式设备中的应用

一、市场背景 随着人们生活水平的提高&#xff0c;对于家居安全和远程监控的需求日益增长&#xff0c;带屏IPCam不仅满足了用户实时查看监控画面的需求&#xff0c;还提供了诸如双向语音通话、智能报警等丰富的功能&#xff0c;极大地提升了用户体验。 此外&#xff0c;技术的…

预测数值型数据:回归

1.1 用线性回归找到最佳拟合直线 线性回归&#xff1a;优点&#xff1a;结果易于理解&#xff0c;计算上不复杂 缺点&#xff1a;对非线性的数据拟合不好 适用数据类型&#xff1a;数值型和标称型数据 回归的目的就是预测数值型的目标值。 回归的一般方法&#xff1a; &#…

【操作系统安全】任务3:Linux 网络安全实战命令手册

目录 一、基础网络信息获取 1. 网络接口配置 2. 路由表管理 3. 服务端口监控 二、网络监控与分析 1. 实时流量监控 2. 数据包捕获 3. 网络协议分析 三、渗透测试工具集 1. 端口扫描 2. 漏洞利用 3. 密码破解 四、日志审计与分析 1. 系统日志处理 2. 入侵检测 3…

5.4 位运算专题:LeetCode 137. 只出现一次的数字 II

1. 题目链接 LeetCode 137. 只出现一次的数字 II 2. 题目描述 给定一个整数数组 nums&#xff0c;其中每个元素均出现 三次&#xff0c;除了一个元素只出现 一次。请找出这个只出现一次的元素。 要求&#xff1a; 时间复杂度为 O(n)&#xff0c;空间复杂度为 O(1)。 示例&a…

3. 轴指令(omron 机器自动化控制器)——>MC_SetPosition

机器自动化控制器——第三章 轴指令 11 MC_SetPosition变量▶输入变量▶输出变量▶输入输出变量 功能说明▶时序图▶重启动运动指令▶多重启运动指令▶异常 MC_SetPosition 将轴的指令当前位置和反馈当前位置变更为任意值。 指令名称FB/FUN图形表现ST表现MC_SetPosition当前位…

Python+Requests+Pytest+YAML+Allure接口自动化框架

GitHub源码地址&#xff08;详细注释&#xff09;&#xff1a;源码 调试项目python自主搭建&#xff1a;附项目源码 一、项目介绍 本项目是基于 PythonRequestsPytestYAMLAllure 搭建的 接口自动化测试框架&#xff0c;用于对 REST API 进行测试。 框架的主要特点包括&#…