蓝牙开发 基础知识
零、基础知识
0.1、Android 应用可通过 Bluetooth API 执行以下操作
- 扫描其他蓝牙设备
- 查询本地蓝牙适配器的配对蓝牙设备
- 建立 RFCOMM 通道
- 通过服务发现连接到其他设备
- 与其他设备进行双向数据传输
- 管理多个连接
0.2、蓝牙进行通信的四大必需任务
- 设置蓝牙
- 查找局部区域内的配对设备或可用设备
- 连接设备
- 在设备之间传输数据
0.3、动作
请求连接、接受连接和传输数据
蓝牙协议是适用于设备间蓝牙通信的无线接口规范。
如果手机要与无线耳机进行连接,则两台设备都必须支持免提蓝牙协议。
0.4、协议
- HFP协议:Android 提供 BluetoothHeadset 类,该类是用于控制蓝牙耳机服务的代理。其中包括蓝牙耳机和免提 (v1.5) 的协议。BluetoothHeadset 类包含对 AT 命令的支持。
- A2DP协议:定义如何通过蓝牙连接和流式传输,将高质量音频从一个设备传输至另一个设备。Android 提供 BluetoothA2dp 类,该类是用于控制蓝牙 A2DP 服务的代理。
- 蓝牙健康设备 (HDP)协议:该协议允许您创建应用,从而与支持蓝牙功能的健康设备(例如心率监测仪、血糖仪、温度计、台秤等)进行通信。
0.5、名词
- RFCOMM 通道
- AT 命令
- 耳机协议
- BluetoothHeadset类
- BluetoothSocket类
- SDP lookup of uuid
- SDP record
供应商特定的 AT 命令
从 Android 3.0(API 级别 11)开始,应用可注册接收耳机发送的预定义供应商特定 AT 命令(例如 Plantronics +XEVENT 命令)的系统广播。例如,应用可接收指示所连接设备电池电量的广播,并根据需要通知用户或采取其他操作。为 ACTION_VENDOR_SPECIFIC_HEADSET_EVENT Intent 创建广播接收器,以处理耳机的供应商特定 AT 命令。
一、使用蓝牙
1.1 设置蓝牙
启用蓝牙:
获取 BluetoothAdapter。
所有蓝牙 Activity 都需要 BluetoothAdapter。如要获取 BluetoothAdapter,请调用静态的 getDefaultAdapter() 方法。此方法会返回一个 BluetoothAdapter 对象,表示设备自身的蓝牙适配器(蓝牙无线装置)。整个系统只有一个蓝牙适配器,并且您的应用可使用此对象与之进行交互。如果 getDefaultAdapter() 返回 null,则表示设备不支持蓝牙。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {// Device doesn't support Bluetooth
} else {if (!bluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}
}
如果成功启用蓝牙,您的 Activity 会在 onActivityResult() 回调中收到 RESULT_OK 结果代码。如果由于某个错误(或用户响应“No”)未成功启用蓝牙,则结果代码为 RESULT_CANCELED。
1.2 查找设备
1.2.1 设备发现
如要开始发现设备,只需调用 startDiscovery()。该进程为异步操作,并且会返回一个布尔值,指示发现进程是否已成功启动。发现进程通常包含约 12 秒钟的查询扫描,随后会对发现的每台设备进行页面扫描,以检索其蓝牙名称。
@Override
protected void onCreate(Bundle savedInstanceState) {...// Register for broadcasts when a device is discovered.IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);registerReceiver(receiver, filter);
}// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();if (BluetoothDevice.ACTION_FOUND.equals(action)) {// Discovery has found a device. Get the BluetoothDevice// object and its info from the Intent.BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);String deviceName = device.getName();String deviceHardwareAddress = device.getAddress(); // MAC address}}
};@Override
protected void onDestroy() {super.onDestroy();...// Don't forget to unregister the ACTION_FOUND receiver.unregisterReceiver(receiver);
}
1.2.2 查询配对设备的列表
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();if (pairedDevices.size() > 0) {// There are paired devices. Get the name and address of each paired device.for (BluetoothDevice device : pairedDevices) {String deviceName = device.getName();String deviceHardwareAddress = device.getAddress(); // MAC address}
}
1.2.3 启用可检测性
Intent discoverableIntent =new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); // 可检测性开启300秒
startActivity(discoverableIntent);
注意:如果尚未在设备上启用蓝牙,则启用设备可检测性会自动启用蓝牙。
1.2.4 已配对与已连接的区别
已配对是指两台设备知晓彼此的存在,具有可用于身份验证的共享链路密钥,并且能够与彼此建立加密连接。
已连接是指设备当前共享一个 RFCOMM 通道,并且能够向彼此传输数据。当前的 Android Bluetooth API 要求规定,只有先对设备进行配对,然后才能建立 RFCOMM 连接。在使用 Bluetooth API 发起加密连接时,系统会自动执行配对。
二、连接设备
2.1. 连接技术
2.1.1 作为服务器连接
private class AcceptThread extends Thread {private final BluetoothServerSocket mmServerSocket;public AcceptThread() {// Use a temporary object that is later assigned to mmServerSocket// because mmServerSocket is final.BluetoothServerSocket tmp = null;try {// MY_UUID is the app's UUID string, also used by the client code.tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {Log.e(TAG, "Socket's listen() method failed", e);}mmServerSocket = tmp;}public void run() {BluetoothSocket socket = null;// Keep listening until exception occurs or a socket is returned.while (true) {try {socket = mmServerSocket.accept();} catch (IOException e) {Log.e(TAG, "Socket's accept() method failed", e);break;}if (socket != null) {// A connection was accepted. Perform work associated with// the connection in a separate thread.manageMyConnectedSocket(socket);mmServerSocket.close();break;}}}// Closes the connect socket and causes the thread to finish.public void cancel() {try {mmServerSocket.close();} catch (IOException e) {Log.e(TAG, "Could not close the connect socket", e);}}
}
2.1.2 作为客户端连接
private class ConnectThread extends Thread {private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {// Use a temporary object that is later assigned to mmSocket// because mmSocket is final.BluetoothSocket tmp = null;mmDevice = device;try {// Get a BluetoothSocket to connect with the given BluetoothDevice.// MY_UUID is the app's UUID string, also used in the server code.tmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {Log.e(TAG, "Socket's create() method failed", e);}mmSocket = tmp;}public void run() {// Cancel discovery because it otherwise slows down the connection.bluetoothAdapter.cancelDiscovery();try {// Connect to the remote device through the socket. This call blocks// until it succeeds or throws an exception.mmSocket.connect();} catch (IOException connectException) {// Unable to connect; close the socket and return.try {mmSocket.close();} catch (IOException closeException) {Log.e(TAG, "Could not close the client socket", closeException);}return;}// The connection attempt succeeded. Perform work associated with// the connection in a separate thread.manageMyConnectedSocket(mmSocket);}// Closes the client socket and causes the thread to finish.public void cancel() {try {mmSocket.close();} catch (IOException e) {Log.e(TAG, "Could not close the client socket", e);}}
}
相关文章:
蓝牙开发 基础知识
零、基础知识 0.1、Android 应用可通过 Bluetooth API 执行以下操作 扫描其他蓝牙设备查询本地蓝牙适配器的配对蓝牙设备建立 RFCOMM 通道通过服务发现连接到其他设备与其他设备进行双向数据传输管理多个连接 0.2、蓝牙进行通信的四大必需任务 设置蓝牙查找局部区域内的配对…...
QNX 7.0.0开发总结
1 QNX编译 1.1 基本概念 QNX可以直接使用Linux Makefile编译库和二进制,在Makefile文件中指定CCaarch64-unknown-nto-qnx7.0.0-g,或者CCx86_64-pc-nto-qnx7.0.0-g,保存退出后,运行source /qnx_sdk_path/qnxsdp-env.sh,…...
Golang使用讯飞星火AI接口
一、API申请 https://www.bilibili.com/video/BV1Yw411m7Rs/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 注册申请,需要在此页面获取appid、apisecret、apikey https://www.xfyun.cn/ https://console.xfyun.cn/ser…...
矫正儿童发音好帮手
《言语构音语音训练手册——下颌、唇部、舌部构音运动障碍》教辅书 儿童言语构音语音问题越来越受到家长的关注,大多数家长受到儿童说话晚、口齿不清、发音错误等问题的困扰,国外报道2岁儿童言语构音语音障碍达到17%,3岁达4%~7.5%࿰…...
wordpress主题导航主题v4.16.2哈哈版
1.下载授权接口源码onenav-auth-api-v2.zip ,在宝塔新建一个网站,域名为 auth.iotheme.cn,设置wordpress伪静态,申请ssl证书。将上面源码解压后上传到此网站根目录。 2. 在宝塔根目录etc下 hosts 中添加 127.0.0.1 auth.iotheme.…...
内存分布图
1.基本数据类型和常量存放在常量池中。 2.类的成员存放在堆中,如果成员是其他类对象也存放在堆中 3.数组和数组的内容放在堆中 4.类对象存放在栈中。 5.单独的对象存放在栈中。 6.引用数据类型存放在堆或栈中。 Java中对象到底存在堆中还是栈中_java对象在堆还…...
如何发布自己的NPM插件包?
安装 Node.js : 如果没有安装的,Nodejs下载安装:http://nodejs.cn/download/ 首先确保你已经安装了 Node.js 和 npm。你可以通过运行以下命令来检查是否已经安装: node -v npm -v初始化项目: 创建一个新的项目文件夹…...
计算广告读书杂记-待整理
不知不觉已经在字节干了两年多广告研发,也跳槽去了一家广告公司继续深耕,借着这个劲,重新读一遍《计算广告》这本书,并将一些重点概念进行记录。...
No module named _sqlite3解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
防飞单,赢市场:售楼处客流统计管理新篇章
在竞争激烈的房地产市场中,售楼处作为楼盘销售的重要窗口,其管理效率和服务质量直接关系到楼盘的销售业绩和品牌形象。然而,传统的客户人数统计方式往往存在诸多不足,如数据不准确、统计效率低下等,这些问题给售楼处的…...
LeetCode:419. 甲板上的战舰(遍历 Java)
目录 419. 甲板上的战舰 题目描述: 实现代码与解析: 遍历 原理思路: 419. 甲板上的战舰 题目描述: 给你一个大小为 m x n 的矩阵 board 表示甲板,其中,每个单元格可以是一艘战舰 X 或者是一个空位 . &…...
【python】OpenCV—Blob Detection(11)
学习来自OpenCV基础(10)使用OpenCV进行Blob检测 文章目录 1、cv2.SimpleBlobDetector_create 中文文档2、默认 parameters3、配置 parameters附录——cv2.drawKeypoints 1、cv2.SimpleBlobDetector_create 中文文档 cv2.SimpleBlobDetector_create 是 O…...
【C++】 基础复习 | 数据类型,输入,输出流 scanf printf
文章目录 1 基本数据类型1.1 基本数据类型1.2 构造类型1.3 指针类型(Pointers) 2 基础输入输出2.1 通过输入输出操作符>> <<2.2 通过scanf和printf输入和输出2.2.1 输出printf 函数2.2.2 输出scanf 函数2.2.3 注意事项 1 基本数据类型 了解…...
linux pxe和无人值守
一 PXE和无人值守 pxe c/s模式 允许客户端通过网络从远程服务器(服务端)下载引导镜像 加载安装文件 实现自动化安装操作系统 无人值守 就是安装选项不需要认为干预 可以自动化实现 pxe的优点 1 规模化 同时装配多台服务器 20多 30台 2 自动化 …...
Questflow借助MongoDB Atlas以AI重新定义未来工作方式
MongoDB客户案例导读 Questflow借助MongoDB Atlas赋能AI员工,助力中小型初创企业自动化工作流程,简化数据分析,提升客户体验,推动AI与员工的协作,重新定义未来工作方式。 协作式AI自动化平台 无需编码即可拥有自己的…...
数值计算精度问题(浮点型和双整型累加精度测试)
这篇博客介绍双整型和浮点数累加精度问题,运动控制轨迹规划公式有大量对时间轴的周期累加过程,如果我们采用浮点数进行累加,势必会影响计算精度。速度的不同 进一步影响位置积分运算。轨迹规划相关问题请参考下面系列文章,这里不再赘述: 1、博途PLC 1200/1500PLC S型速度曲…...
算法训练营day56
题目1:300. 最长递增子序列 - 力扣(LeetCode) class Solution { public:int lengthOfLIS(vector<int>& nums) {// dp数组含义是第i个数的严格递增子序列的长度// 内层的递推公式就是 取 0 到 i - 1之间最大的dp数组 然后 1vector…...
基于STM32的智能水产养殖系统(二)
TPS5433IDR TPS5433IDR 是一款由德州仪器 (Texas Instruments) 生产的高效降压转换器(Buck Converter)。它能够将较高的输入电压转换为较低的输出电压,适用于各种电源管理应用。 主要特性 输入电压范围: 5.5V 至 36V输出电压范围: 0.9V 至 …...
[工具探索]富士mini90拍立得使用指南
文章目录 1. 基本功能介绍1.1 相机外观1.2 电池与胶片 2. 设置相机2.1 装入电池2.2 装入胶片 3. 拍摄模式3.1 标准模式3.2 儿童模式3.3 远景模式3.4 双重曝光模式3.5 Bulb(B)模式3.6 **派对模式**3.7 微距模式3.8 **亮度模式**3.9 **定时拍摄模式**3.10 …...
VMware导入小白分享的MacOS版本之后,无法开机的解决方案
前言 这段时间陆续有小伙伴找到小白,说:导入小白分享的MacOS版本之后,出现无法开机的问题。 遇到这个问题,并不是说明分享版本有问题,因为大部分小伙伴导入之后都没有出现类似的问题,都是导入之后开机&…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
aurora与pcie的数据高速传输
设备:zynq7100; 开发环境:window; vivado版本:2021.1; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程,pc通过pcie传输给fpga,fpga再通过aur…...
