当前位置: 首页 > news >正文

蓝牙开发 基础知识

零、基础知识

0.1、Android 应用可通过 Bluetooth API 执行以下操作

  • 扫描其他蓝牙设备
  • 查询本地蓝牙适配器的配对蓝牙设备
  • 建立 RFCOMM 通道
  • 通过服务发现连接到其他设备
  • 与其他设备进行双向数据传输
  • 管理多个连接

0.2、蓝牙进行通信的四大必需任务

  1. 设置蓝牙
  2. 查找局部区域内的配对设备或可用设备
  3. 连接设备
  4. 在设备之间传输数据

0.3、动作

请求连接、接受连接和传输数据

蓝牙协议是适用于设备间蓝牙通信的无线接口规范。
如果手机要与无线耳机进行连接,则两台设备都必须支持免提蓝牙协议。

0.4、协议

  • HFP协议:Android 提供 BluetoothHeadset 类,该类是用于控制蓝牙耳机服务的代理。其中包括蓝牙耳机和免提 (v1.5) 的协议。BluetoothHeadset 类包含对 AT 命令的支持。
  • A2DP协议:定义如何通过蓝牙连接和流式传输,将高质量音频从一个设备传输至另一个设备。Android 提供 BluetoothA2dp 类,该类是用于控制蓝牙 A2DP 服务的代理。
  • 蓝牙健康设备 (HDP)协议:该协议允许您创建应用,从而与支持蓝牙功能的健康设备(例如心率监测仪、血糖仪、温度计、台秤等)进行通信。

0.5、名词

  1. RFCOMM 通道
  2. AT 命令
  3. 耳机协议
  4. BluetoothHeadset类
  5. BluetoothSocket类
  6. SDP lookup of uuid
  7. 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);}}
}
http://www.lryc.cn/news/369865.html

相关文章:

  • QNX 7.0.0开发总结
  • Golang使用讯飞星火AI接口
  • 矫正儿童发音好帮手
  • wordpress主题导航主题v4.16.2哈哈版
  • 内存分布图
  • 如何发布自己的NPM插件包?
  • 计算广告读书杂记-待整理
  • No module named _sqlite3解决方案
  • 防飞单,赢市场:售楼处客流统计管理新篇章
  • LeetCode:419. 甲板上的战舰(遍历 Java)
  • 【python】OpenCV—Blob Detection(11)
  • 【C++】 基础复习 | 数据类型,输入,输出流 scanf printf
  • linux pxe和无人值守
  • Questflow借助MongoDB Atlas以AI重新定义未来工作方式
  • 数值计算精度问题(浮点型和双整型累加精度测试)
  • 算法训练营day56
  • 基于STM32的智能水产养殖系统(二)
  • [工具探索]富士mini90拍立得使用指南
  • VMware导入小白分享的MacOS版本之后,无法开机的解决方案
  • 【CSAPP导读】导论
  • “新E代弯道王”MAZDA EZ-6亮相2024重庆国际车展
  • 【lesson11】客户端backUp类的实现
  • 数据结构--关键路径
  • SSTI注入漏洞
  • Day11 - Day15
  • 启航信息学奥林匹克:青少年NOI学习路线与策略指南
  • 易舟云财务软件:数字化时代的财务管家
  • catia零件装配中通过指南针移动零件
  • 如何使用免费的 Instant Data Scraper快速抓取网页数据
  • 【仿真建模-anylogic】事件之手动定时触发