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

Android 蓝牙开发-传输数据

在这里插入图片描述

概述

    传统蓝牙是通过建立REFCCOM sockect来进行通信的,类似于socket通信,一台设备需要开放服务器套接字并处于listen状态,而另一台设备使用服务器的MAC地址发起连接。连接建立后,服务器和客户端就都通过对BluetoothSocket进行读写操作来进行通信。

实现步骤

      要通过蓝牙来传输数据整体流程如下:

首次, 未配对状态

Created with Raphaël 2.3.0 开始 打开蓝牙 蓝牙已打开? 扫描 找到设备? 配对 配对成功? 连接 发送/读取数据 结束 yes no yes no yes no

已配对状态

Created with Raphaël 2.3.0 开始 打开蓝牙 蓝牙已打开? 获取配对设备 连接 发送/读取数据 结束 yes no

| 关键代码

蓝牙权限

    <uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

打开或关闭蓝牙

BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
ba.enable();
ba.disable();

扫描设备

BluetoothAdapter.getDefaultAdapter().startDiscovery();

监听设备扫描

//Device stae
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
//for discovery .
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

根据ACTION_FOUND实时获取扫描到的设备, 常规会获取设备的名称和MAC

BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String name = device.getName();
String mac = device.getAddress();

| 发起设备配对
| 配对动作大部分情况下, 连接的双方设备都会有对应的弹出窗口, 让用户选择是否配对设备.

public static boolean startPair(BluetoothDevice dev){Logger.d(TAG, "startPair(" + dev.getName() + ")");if(dev != null){try {Method createBond = BluetoothDevice.class.getDeclaredMethod("createBond");if(createBond != null){Object r = createBond.invoke(dev);return (Boolean)r;}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return false;
}

| 连接并发送数据

//获取已绑定的设备
Set<BluetoothDevice> devs = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
BluetoothDevice target = null;//通过名称查找目标设备
for(BluetoothDevice d : devs){if(StringTools.isNotEmpty(d.getName()) && d.getName().startsWith("TARGET-")){target = d;break;}
}if(target != null) {final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00XXXXXXXXXX");try {BluetoothSocket socket = target.createRfcommSocketToServiceRecord(MY_UUID);socket.connect();OutputStream outputStream = socket.getOutputStream();outputStream.write(msg.getBytes());Logger.d(TAG, "sendMsgByBluetooth " + msg);outputStream.flush();InputStream is = socket.getInputStream();byte[] cache = new byte[512];int r = is.read(cache);Logger.d(TAG, "receive response: " + new String(cache));sleepx(500);is.close();outputStream.close();} catch (IOException e) {e.printStackTrace();}
}

基于系统源码的服务端

PS: 源码端可以通过获取system权限, 完成设备配对流程

监听广播并执行配对

   public static final String BLUETOOTH_PARING_QUEST = "android.bluetooth.device.action.PAIRING_REQUEST";@Overridepublic void onReceive(Context context, Intent intent) {BluetoothDevice device = BluetoothTools.onPairRequest(intent);int mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);int mPasskey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR);BluetoothTools.pair(device, mType, mPasskeyFormatted);}

BluetoothTools.java (反射系统蓝牙部分接口)

private static void setRemoteOutOfBandData(BluetoothDevice dev){try {Method setRemoteOutOfBandData = BluetoothDevice.class.getDeclaredMethod("setRemoteOutOfBandData");if(setRemoteOutOfBandData != null){setRemoteOutOfBandData.invoke(dev);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}private static void setPairingConfirmation(BluetoothDevice dev, boolean bool){try {Method setPairingConfirmation = BluetoothDevice.class.getDeclaredMethod("setPairingConfirmation", Boolean.TYPE);if(setPairingConfirmation != null){setPairingConfirmation.invoke(dev, bool);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}private static void setPasskey(BluetoothDevice dev, int passKey){try {Method setPasskey = BluetoothDevice.class.getDeclaredMethod("setPasskey", Integer.TYPE);if(setPasskey != null){setPasskey.invoke(dev, passKey);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}private static byte[] convertPinToBytes(String val){try {Method convertPinToBytes = BluetoothDevice.class.getDeclaredMethod("convertPinToBytes", String.class);if(convertPinToBytes != null){return (byte[])convertPinToBytes.invoke(null, val);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}private static void setPin(BluetoothDevice mDevice, byte[] bytes){try {Method setPin = BluetoothDevice.class.getDeclaredMethod("setPin", byte[].class);if(setPin != null){setPin.invoke(mDevice, (Object)bytes);}} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}public static void pair(BluetoothDevice dev, int type, String password){onPair(type, password, dev);}private static void onPair(int mType, String value, BluetoothDevice mDevice) {switch (mType) {case BluetoothDevice.PAIRING_VARIANT_PIN:byte[] pinBytes = convertPinToBytes(value);if (pinBytes == null) {return;}setPin(mDevice, pinBytes);break;case PAIRING_VARIANT_PASSKEY:int passkey = Integer.parseInt(value);setPasskey(mDevice, passkey);break;case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:case PAIRING_VARIANT_CONSENT:setPairingConfirmation(mDevice, true);break;case PAIRING_VARIANT_DISPLAY_PASSKEY:case PAIRING_VARIANT_DISPLAY_PIN:// Do nothing.break;case PAIRING_VARIANT_OOB_CONSENT:setRemoteOutOfBandData(mDevice);break;default:Logger.e(TAG, "Incorrect pairing type received");}}

同样, 在完成配对后, 可以通过BluetoothServerSocket 来接收来自客户端的连接实现通讯:

final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00XXXXXXXXXX");
BluetoothServerSocket serverSocket = BluetoothAdapter.listenUsingRfcommWithServiceRecord("MyApp", MY_UUID);
Logger.d(TAG, "listen: waiting for new connect...");
BluetoothSocket clientSocket = serverSocket.accept();
InputStream inputStream = mSocket.getInputStream();
byte[] cache = new byte[512];
inputStream.read(cache);
//省略读写和关闭代码...
  • 关于UUID

    UUID.fromString 方法用于将字符串转换为 UUID 对象。UUID(通用唯一标识符)是一个 128 位的值,通常表示为 32 个十六进制数字,分为五组,形式为 8-4-4-4-12 的字符串。

    字符串格式要求如下:

    1. 长度必须是 36 个字符。
    2. 字符串必须以连字符(-)分隔为五组,每组字符数分别为 8、4、4、4 和 12。
    3. 所有字符都必须是十六进制数字(0-9 和 a-f 或 A-F)。

    示例:

    import java.util.UUID;public class Main {public static void main(String[] args) {String uuidString = "123e4567-e89b-12d3-a456-426614174000";UUID uuid = UUID.fromString(uuidString);System.out.println("UUID: " + uuid);}
    }

    如果你尝试使用不符合格式的字符串,UUID.fromString 方法将抛出 IllegalArgumentException。例如:

    import java.util.UUID;public class Main {public static void main(String[] args) {String invalidUuidString = "123e4567-e89b-12d3-a456-4266141740"; // 缺少一个字符try {UUID uuid = UUID.fromString(invalidUuidString);System.out.println("UUID: " + uuid);} catch (IllegalArgumentException e) {System.out.println("Invalid UUID string: " + invalidUuidString);}}
    }

    在这个例子中,invalidUuidString 不符合 UUID 字符串格式要求,因此 UUID.fromString 方法将抛出 IllegalArgumentException
    PS:UUID对字符大小写不敏感

参考系统源码 packages/apps/Settings
配对窗口: AndroidManifest.xml

<activity android:name=".bluetooth.BluetoothPairingDialog"android:excludeFromRecents="true"android:windowSoftInputMode="stateVisible|adjustResize"android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"><intent-filter android:priority="1"><action android:name="android.bluetooth.device.action.PAIRING_REQUEST" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>

src/com/android/settings/bluetooth/BluetoothParingController.java
src/com/android/settings/bluetooth/BluetoothParingDialogFragment.java

参考

android蓝牙开发 蓝牙设备的查找和连接
Android蓝牙通信机制详解

http://www.lryc.cn/news/509992.html

相关文章:

  • webrtc获取IceCandidate流程
  • 每天40分玩转Django:Django静态文件
  • Linux 线程池
  • windows使用zip包安装MySQL
  • 深度学习实战之超分辨率算法(tensorflow)——ESPCN
  • Android unitTest 单元测试用例编写(初始)
  • C++简明教程(10)(初识类)
  • 光谱相机的工作原理
  • 【Linux进程】基于管道实现进程池
  • 软件测试之单元测试
  • vscode+编程AI配置、使用说明
  • 007-spring-bean的相关配置(重要)
  • 【唐叔学算法】第19天:交换排序-冒泡排序与快速排序的深度解析及Java实现
  • 合并 Python 中的字典
  • 使用Python实现自动化文档生成工具:提升文档编写效率的利器
  • uniapp使用live-pusher实现模拟人脸识别效果
  • 【JavaSE】【网络原理】初识网络
  • 鸿蒙之路的坑
  • Python生日祝福烟花
  • Ubuntu环境 nginx.conf详解(二)
  • shardingsphere分库分表项目实践4-sql解析sql改写
  • mysql数据库中,一棵3层的B+树,假如数据节点大小是1k,那这棵B+可以存多少条记录(2100万的由来)
  • Git 操作全解:从基础命令到高级操作的实用指南
  • 华院计算参与项目再次被《新闻联播》报道
  • 从一次线上故障聊聊接口自动化测试
  • Element-ui的使用教程 基于HBuilder X
  • Chapter 03 复合数据类型-1
  • 【Python知识】Python面向对象编程知识
  • CSharp: Oracle Stored Procedure query table
  • “协同过滤技术实战”:网上书城系统的设计与实现