BlueTooth
根据官方DOC翻译
(本人英语4级没过,看不懂请自行脑补)
Bluetooth API操作流程:
- 搜索其他蓝牙设备
- 查询本地匹配器已经匹配的蓝牙设备
- 建立RFCOMM通道
- 通过Service发现并连接其他设备
- 与其他蓝牙设备进行数据交互
- 管理多个连接
Permission:
- android.permission.BLUETOOTH:Allows applications to connect to paired bluetooth devices
- android.permission.BLUETOOTH_ADMIN:Allows applications to discover and pair bluetooth devices
Setting Up Bluetooth:
确保设备支持蓝牙模块,并已开启
- 获取BluetoothAdapter。整个系统只有一个BluetoothAdapter。如果返回null表示设备不支持蓝牙。
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 设备是否支持蓝牙
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.not_support, Toast.LENGTH_SHORT).show();
}
- 开启蓝牙:如果没用开启蓝牙,会弹出系统对话框,请求用户开启蓝牙功能。如果开启成功,则返回:Activity.RESULT_OK,否则返回:Activity.RESULT_CANCELED。
- 监听状态:你可以通过监听BluetoothAdapter. ACTION_STATE_CHANGED广播获得蓝牙状态变化信息。广播包含以下额外字段: EXTRA_STATE和EXTRA_PREVIOUS_STATE。常见值包括:STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF和STATE_OFF。
Finding Devices:
使用BluetoothAdapter,你可以找到远程蓝牙设备。通过查找设备,或查询配对(绑定)的设备列表。查找设备会搜索区域内的蓝牙设备,如果该设备设定为可被发现,则会返回一些信息,通过该信息则可连接设备。当首次建立连接,该设备信息会被保存并可通过API获得,使用MAC地址不需要重新搜索设备(假设设备在可连接范围内)。
- 配对(Pair): 意味着两个设备都知道彼此的存在,有一个共同的链路密钥,可用于进行认证,并且能够建立与彼此的加密连接的。
- 连接(Connect):该装置当前共享一个RFCOMM信道,并能够相互传送数据。Android Bluetooth API's要求设备配对前需要先建立RFCOMM连接(当你通过API建立加密连接配对会自动执行)。
Querying paired devices:
通过getBondedDevices()可返回一组蓝牙配对清单(BluetoothDevice)。
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { mDeviceInfoList = new ArrayList<HashMap<String, Object>>(); for (BluetoothDevice device : pairedDevices) { mDeviceInfoList.add(device.getName() + "\n" + device.getAddress()); } }
Discovering devices:
通过startDiscovery()可搜索设备,此方法会立即返回Boolean提示是否成功开始搜索。这是一个异步操作,搜索时间大约12秒然后会返回发现的蓝牙设备信息。对于每个搜索到的设备,系统会广播一个ACTION_FOUND Intent,装载的信息包括:EXTRA_DEVICE和EXTRA_CLASS(包含BluetoothDevice和BluetoothClass)。所以你需要注册BroadcastReceiver接收ACTION_FOUND Intent。
// 搜索到蓝牙设备时接收广播提示信息 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 搜索完成时接收广播提示信息 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter); private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 如果查找到设备 BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED .equals(action)) { // 查找完成 } } }; protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (mBluetoothAdapter != null) { // 停止搜索设备 mBluetoothAdapter.cancelDiscovery(); } // 注销广播监听 this.unregisterReceiver(mReceiver); }
需要注意的是,搜索蓝牙设备非常消耗资源,所以一旦找到对应设备,应该使用cancelDiscovery()停止搜索。如果你已有该设备的连接再执行搜索会节约带宽。
如果你想使本地设备能被其他设备检测到,调用startActivityForResult(Intent,INT)和ACTION_REQUEST_DISCOVERABLE action Intent.。这将发出一个请求,以使通过系统设置发现模式(无需停止应用程序)。默认可见时间为120秒,也可以能过EXTRA_DISCOVERABLE_DURATION Intent extra来修改可见时间(最大值为3600秒,0表示设备始终可见)。系统会弹出对话框提示用户设置可见,并调用onActivityResult()返回结果,如果用户选择确定,则返回时间,如果用户选择否或者出现错误,则返回RESULT_CANCELED。如果未开启蓝牙,使设备可见会自动开启。如果你希望监听到设备可见状态的改变,可以注册BroadcastReceiver ACTION_SCAN_MODE_CHANGED Intent,包含:EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE。
// 设置设备对外可见,持续30秒 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivityForResult(intent, REQUEST_DISCOVERABLE);
Connectting Devices:
服务器端创建Server Socket,客户端使用服务器端的MAC地址创建连接,当服务器端与与客户端连接时,双方的BluetoothSocket会在同一RFCOMM通道中。此时双方都各自拥有input和output stream,并能实现数据传输。服务器端和客户端分别以不同的方式获得BluetoothSocket。服务器端:当传入连接Accepted时,接收到BluetoothSocket;
客户端:当客户端打开RFCOMM通道时,接收到BluetoothSocket。
有一种实现方法是每台设备均准备作为服务器,均打开Server Socket并监听连接。然后其它设备则以客户端的形式创建连接。
注意:如果两个设备先前未配对,Android框架将发送配对请求通知对话框给用户,应用程序不需要关注的设备是否被配对。您的RFCOMM连接尝试将阻塞,直到用户成功配对,或者如果用户拒绝配对,或者如果配对失败或者超时就会失败。
Connecting as a server:
当你尝试连接两台设备,其中一台需要充当服务器端打开并持有BluetoothServerSocket。Server Socket目的是监听来自客户端的连接请求,当客户端的连接请求被通过,服务器端将提供BluetoothSocket。一旦取得BluetoothSocket,BluetoothServerSocket应该被移除,除非你打算接受更多连接。
设置Server Socket和接收连接请求的基本流程:
- 使用listenUsingRfcommWithServiceRecord(String, UUID)获得BluetoothServerSocket。String是服务器端的名称。UUID它是用来唯一标识应用程序的蓝牙服务。如果与蓝牙串口(Bluetooth serial board)连接可以尝试使用标准的SPP UUID:00001101-0000-1000-8000-00805F9B34FB。但是如果连接的是Android Peer,你需要生成自己的UUID。
- 通过accept()开始监听连接请求。这是一个阻塞调用,当任意连接被同意或者发生异常时则会退出。只有当客户端发送连接请求,并且请求数据中的UUID与Server Socket的UUID才能被同意。如果连接成功,则返回BluetoothSocket。
- 除非你打算接受其他的连接,否则连接成功后,调用close()。这将释放Server Socket及其所有资源,但不会关闭accept()返回的BluetoothSocket。RFCOMM只允许每个通道一个连接的客户端的时间,因此,在大多数情况下,在BluetoothServerSocket通过连接请求后立即调用close()。
- Accept()不能运行于主线程,应该创建子线程执行些方法,另外BluetoothServerSocket和BluetoothSocket所有方法都是线程安全的。
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; private String mSocketType; public AcceptThread(boolean secure) { BluetoothServerSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; // 创建一个新的server socket监听,secure表示是否使用加密方式 try { if (secure) { tmp = mAdapter.listenUsingRfcommWithServiceRecord( NAME_SECURE, MY_UUID_SECURE); } else { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord( NAME_INSECURE, MY_UUID_INSECURE); } } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // 保持监听,直到Socket返回,或者中止 while (true) { try { // 这是一个阻塞方法,只会返回成功,否则抛出异常 socket = mmServerSocket.accept(); } catch (IOException e) { break; } // 如果连接成功 if (socket != null) { // 新创建一个线程使用Socket manageConnectedSocket (socket); mmServerSocket.close(); break; } } } public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }
请注意,当accept()返回的BluetoothSocket,socket已经连接,所以客户端不需要调用connect()。manageConnectedSocket()用于启动线程传输数据。你可能还需要在线程里提供public方法用于关闭BluetoothSocket。
Connecting as a client:
客户端连接服务器端首先要从服务器端获得BluetoothDevice(参考Finding Devices),然后从BluetoothDevice中获得BluetoothSocket并创建连接。基本流程如下:
- 通过createRfcommSocketToServiceRecord(UUID)从BluetoothDevice中获得BluetoothSocket。UUID必须与服务器端的UUID一致。
- 通过connect()启动连接。connect()连接服务器时,服务器端会匹配UUID,如果匹配成功,服务器会同意连接请求并提供RFCOMM能道,此时connect()会返回。Connect()是阻塞方法,所以需要创建子线程执行,如果连接出现任何问题或者超时(12秒),将会抛出错误。需要注意的是,调用connect()时,确保已经停止搜索(cancelDiscovery()),否则性能会明显降低。也可以使用isDiscovering()检查是否正在搜索中。
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device, boolean secure) { mmDevice = device; BluetoothSocket tmp = null; mSocketType = secure ? "Secure" : "Insecure"; // 通过BluetoothDevel和UUID获得BluetoothSocket try { if (secure) { // 使用加密方式 tmp = device .createRfcommSocketToServiceRecord(MY_UUID_SECURE); } else { // 不使用加密方式,需要API Level 10支持 tmp = device .createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE); } } catch (IOException e) { } mmSocket = tmp; } public void run() { // 停止搜索,搜索设备会占用大量资源 mAdapter.cancelDiscovery(); // 创建Bluetooth连接 try { // connect阻塞方法,只会返回成功, 否则抛出异常 mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { } return; } // 完成后重置线程 synchronized (BluetoothChatService.this) { mConnectThread = null; } // 创建一个独立的线程使用Sokcet manageConnectedSocket(mmSocket); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
当使用完BluetoothSocket,调用close()关闭连接释放资源。
Managing a Connection:
当两(多)台设备连接成功后,两台设备都持有BluetoothSocket,这时可以进行数据交互了。使用BluetoothSocket传输数据流程:
- 通过Socket使用InputStream和OutputStream数据。
- 通过read(byte[])和write(byte[])读写数据流。需要注意的是,你要为读写流创建线程,因为read(byte[])和write(byte[])是阻塞方法,read(byte[])会一直阻塞直到所有数据被读出;write(byte[])通常不会阻塞,但如果远和设备没有迅速调用read(byte[])又或者缓冲区已经满,则会造成阻塞。所以你的线程run主要用于读取InputStream。另外提供public方法,以启动写入输出流。
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // 获取输入和输出流,使用临时对象,因为成员流是final的 try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // 当连接成功后,一直监听InputStream while (true) { try { // 从InputStream读取数据 bytes = mmInStream.read(buffer); // 发送获得的数据至UI Activity mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); } catch (IOException e) { break; } } } // 写入数据并发送 public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { } } // 关闭连接 public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
Working with Profiles:
从Android 3.0开始,Bluetooth API包括了对Bluetooth Profiles的支持。Bluetooth Profile是一种基于设备间的蓝牙通信无线协议规范。其中一个例子是Hands-Free profile(免提模式),手机连接无线耳机,两个设备都必须要支持Hands-Free profile。你可以通过实现BluetoothProfile接口编写自己的类来支持特定的Bluetooth profiles。
- Headset:Headset profile提供对手机使用蓝牙耳机的支持。Android提供BluetoothHeadset类,通过进程通讯(IPC)代理控制蓝牙耳机服务。这里包括蓝牙耳机和免提(v1.5)模式。BluetoothHeadset包括支持AT命令。
- A2DP:The Advanced Audio Distribution Profile (A2DP高级音频传输模式)定义了多高质量的音频可以通过蓝牙传输。Android提供BluetoothA2dp类,通过进程通讯(IPC)代理控制蓝牙A2DP服务。
- Health Device:Android 4.0 (API level 14) 支持Bluetooth Health Device Profile (HDP)。它使你能够创建应用,通过蓝牙与Health Device通讯。例如:heart-rate monitors(心脏速率监视器),blood meters(血压计),thermometers(体温计),scales(身体均衡器),等等。
基本步骤如下:
- 获得Adapter(参考Setting Up Bluetooth)
- 通过方法getProfileProxy()建立与模式关联的理对象的连接。在下面的例子中,配置文件代理对象是BluetoothHeadset的一个实例。
- 设置BluetoothProfile.ServiceListener用于监听服务器端连接或断开连接的事件,并通知BluetoothProfile IPC。
- 在方法onServiceConnected()中获得profile proxy的handle对象。
- 一旦获得profile prox对象,你可以用它来监测连接状态,并进行其它相关的操作。
例如,以下代码显示了如何连接到一个BluetoothHeadset代理对象,这样就可以控制Headset profile:
BluetoothHeadset mBluetoothHeadset; // Get the default adapter BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // Establish connection to the proxy. mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET); private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = (BluetoothHeadset) proxy; } } public void onServiceDisconnected(int profile) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = null; } } }; // ... call functions on mBluetoothHeadset // Close proxy connection after use. mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
Vendor-specific AT commands:
从Android 3.0开始应用程序可以通过注册来接收来自耳机的pre-defined vendor-specific AT commands系统广播(例如:Plantronics +XEVENT command),例如应用程序可以通过广播接收所连接设备的电量水平,并通知用户。创建广播接收器并通过ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent处理来自耳机的vendor-specific AT commands。
Health Device Profile:
相关推荐
A radical new departure from conventional Bluetooth technology, Bluetooth Low Energy (BLE) will enable a whole new generation of wireless applications in industries ranging from healthcare to ...
Toshiba Bluetooth Stack v8.00.03(T) 补丁,Toshiba Bluetooth Stack v8.00.04(T)也可以用。 日发现东芝的蓝牙驱动软件升级到 v8.00.03(T) 版本了,新版本除了修复了一些BUG,更是增加了对蓝牙3.0的支持,建议使用...
当使用手机的蓝牙和电脑连接时,在Windows7下的设备管理器可能会出现两个或三个bluetooth外围设备是驱动有问题的这主要是没有驱动而产生的,这和蓝牙的驱动无关。本款bluetooth外围设备驱动程序其实是驱动人生,因为...
The Bluetooth Qualification Program Reference Document (PRD) is the primary reference document for the Bluetooth Qualification Program and defines its requirements, functions, and policies. The PRD is...
Linux Bluetooth 编程介绍
Bluetooth? Framework is a VCL and ActiveX components library, which allows you to add Bluetooth?, IrDA?, Serial and ActiveSync? support into your applications. The Bluetooth? Framework is not an end...
Delphi and C++ Builder Bluetooth library for Android. Features Uses Android Bluetooth API Supports BLE and BT Classic clients Available for Delphi/C++ Builder 10.1 - 11 Source code included in ...
Bluetooth SIG Board of Directors (both of which are hereinafter referred to herein as a Bluetooth “Specification”). Your use of this Specification in any way is subject to your compliance with all ...
Bluetooth Core v5.4
这是本人在研究安卓蓝牙模块的时候,自己整理的bluetooth框架相关知识点,android顶起。
BLUETOOTH COMPLIANCE REQUIREMENTS 1 Introduction ........................................................................................ 78 2 Scope ......................................................
Bluetooth USB Adapter ES-388. 蓝牙适配器 驱动
Unity Bluetooth LE Plugin for Android - Unity BLE 低功耗蓝牙连接功能技术文档 (安卓端)。
Android Bluetooth Simulator What is it It's a tcp-based implementation of part of the android bluetooth API. As for now, you can communicate between different emulators using the RFComm protocol, you ...
C# windows bluetooth LE 代码,BluetoothLEExplorer.rar
Inside Bluetooth Low Energy (Mobile Communications) By 作者: Naresh Gupta ISBN-10 书号: 1630810894 ISBN-13 书号: 9781630810894 Edition 版本: 2nd ed. Release 出版日期: 2016-06-30 pages 页数 (458)
【Android 11】【Bluetooth模块】Bluetooth打开函数调用流程图
完整的bluetooth5.0协议,If this specification is a prototyping specification, it is solely for the purpose of developing and using prototypes to verify the prototyping specifications at Bluetooth SIG ...
蓝牙核心协议标准5.0版本 Bluetooth Core Specification v 5.0
实战Linux Bluetooth编程, 用了bluez,有图有真相