概述:
Android平台包括了对蓝牙网络协议栈的支持, 它让设备可以跟其它蓝牙设备实现无线数据交换. 应用框架通过Android Bluetooth API提供了访问蓝牙的功能. 这些API可以让APP无线连接到其它的蓝牙设备, 可以使用点对点和多点无线功能. 通过使用蓝牙API, 一个Android APP可以实现这些功能:
l 扫描其它的蓝牙设备
l 为配对的蓝牙设备查询本地蓝牙适配器
l 建立RFCOMM通道
l 通过”服务发现”连接到其它设备
l 与其它设备交换数据
l 管理多连接
本文描述了如何使用经典蓝牙. 经典蓝牙是电池密集型操作的正确选择, 比如流和Android设备之间通信. 为了实现蓝牙设备低耗电的需求, Android4.3引入了支持Bluetooth Low Energy的API. 该功能可以参考这里. 将在下一篇blog中介绍.
基础:
该文档描述了如何使用Android Bluetooth API来完成四种使用蓝牙通信的主要任务: 设置蓝牙, 在本地区域搜索配对或者可用的设备, 连接设备, 和设备间交换数据. 所有Bluetooth API都在android.bluetooth包中. 这里列举了包中我们需要用到的类和接口的总览:
1. BluetoothAdapter: 代表本地蓝牙适配器(蓝牙无线电(radio)).BluetoothAdapter是蓝牙交互的入口. 通过它我们可以发现其它的蓝牙设备, 查询配对设备的列表, 使用一个已知的MAC地址实例化一个BluetoothDevice, 还可以创建一个BluetoothServerSocket来监听其它设备发来的通信.
2. BluetoothDevice: 表示一个远程的蓝牙设备. 使用它可以请求一个与远程设备通过BluetoothSocket建立的链接, 或者用来查询设备的相关信息, 比如名字, 地址, 类, 和配对状态.
3. BluetoothSocket: 表示为蓝牙socket的接口(类似于TCPSocket). 它是一个连接点, 允许一个APP跟其它的蓝牙设备通过InputStream和OutputStream来交换数据.
4. BluetoothServerSocket: 代表一个开放的服务器socket,它持续的监听连接进来的需求(类似于一个TCP ServerSocket). 为了连接两个Android设备, 一个设备必须用该类开启一个服务器socket. 当一个远程蓝牙设备请求连接该设备的时候, BluetoothServerSocket将会在连接建立后返回一个连接了的BluetoothSocket.
5. BluetoothClass: 描述蓝牙设备的一般特征和能力. 这是一组只读的属性, 定义了设备的主要和次要设备类和它的服务. 然而它对所有蓝牙配置文件和服务的描述并不是很牢靠, 但作为设备类型的参考还是有用的.
6. BluetoothProfile: 一个代表蓝牙配置文件(Bluetoothprofile)的接口. 蓝牙配置文件是一个设备间基于蓝牙通信的无线接口规范. 有一个栗子是Hands-Free(免提)配置文件. 更多信息可以参考”通过配置文件工作”小节.
7. BluetoothHeadset: 为移动电话的耳机提供支持.包括蓝牙耳机和Hands-Free(v1.5)配置文件.
8. BluetoothA2dp: 定义高质量音频如何从一个设备流传输到另一个设备. “A2DP”代表Advanced Audio Distribution Profile.
9. BluetoothHealth: 代表一个控制蓝牙服务的健康设备配置文件代理.
10. BluetoothHealthCallback: 一个抽象类, 我们可以用它来实现BluetoothHealth的回调. 要使用它则必须要继承该类并实现回调方法来接收关于APP注册状态和蓝牙通道状态的更新.
11. BluetoothHealthAppConfiguration:代表一个蓝牙健康第三方应用注册到了一个远程蓝牙健康设备的应用配置.
12. BluetoothProfile.ServiceListener:一个接口, 用于BluetoothProfile IPC客户端与服务连接或者断开连接的时候发出提醒.
蓝牙权限:
为了在APP中使用蓝牙功能, 我们必须声明蓝牙权限:BLUETOOTH. 执行任何的蓝牙通信, 比如请求连接, 接收连接, 数据交换, 都需要该权限. 如果想要我们的APP要启动设备发现或者操作蓝牙设置, 就必须声明BLUETOOTH_ADMIN权限. 大多数APP需要这个权限仅仅是为了发现本地蓝牙设备. 其它被该权限授权的能力不该被使用, 除非APP是”电源管理器”类的, 会根据用户的需求修改蓝牙设置. 注意: 如果使用了BLUETOOTH_ADMIN权限, 那么比需也声明BLUETOOTH权限. 栗子:
<manifest ...>
<uses-permission android:name="android.permission.BLUETOOTH"/>
...
</manifest>
设置蓝牙:
在使用蓝牙连接和通信之前, 我们必须确认设备可以支持蓝牙, 如果支持的话, 还要确认是否目前是启用的. 如果不支持蓝牙, 那么应该合理的关闭任何蓝牙相关的功能. 如果支持蓝牙, 但是目前蓝牙处于关闭状态, 那么我么你可以在不离开APP的情况下请求用户启动蓝牙. 这个操作需要个步骤, 并且使用BluetoothAdapter类:
1. 得到BluetoothAdapter: 所有的蓝牙activity都需要BluetoothAdapter. 想要得到它需要调用getDefaultAdapter()方法. 该方法返回一个BluetoothAdapter, 代表设备本身的蓝牙适配器(蓝牙无线电). 整个系统有一个蓝牙适配器, 并且APP可以使用该对象跟它通信. 如果getDefaultAdapter()方法返回了null, 那么代表设备不支持蓝牙, 接下来也就没啥事可做了. 栗子:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
2. 启动蓝牙: 下一步我们就该启动蓝牙了. 调用isEnabled()方法来查看蓝牙当前是否在启动着. 如果返回false, 那么表示蓝牙关闭. 这时候如果想要启动蓝牙, 调用startActivityForResult()方法, 并传给它ACTION_REQUEST_ENABLEaction intent. 这将会通过系统设置发出一个请求启动蓝牙的操作. 栗子:
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
这时候将会弹出一个对话框让用户选择是否启动蓝牙. 如果用户选择了”是”, 系统将会开启蓝牙, 成功(或者失败)后会将焦点返回给APP. 栗子中的REQUEST_ENABLE_BT常量是一个大于0的数字, 它将在onActivityResult()中作为requestCode返回给我们作为参数. 如果成功启动了蓝牙, activity将会在onActivityResult()中收到一个RESULT_OK的结果. 如果失败了, 将会收到RESULT_CANCELED.
还有一个可选项我们可以做的, APP可以监听ACTION_STATE_CHANGED广播intent, 当蓝牙状态改变的时候, 系统将会广播它. 该广播包含额外的域EXTRA_STATE和EXTRA_PREVIOUS_STATE, 分别包含新老蓝牙状态. 这些额外的域可能包含以下值: STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, 和STATE_OFF. 如果关注蓝牙状态的话, 监听该广播会很有用.
启动”可以被发现”功能会自动开启蓝牙. 如果我们打算在执行蓝牙activity前持续的启动设备发现功能, 可以跳过上面的两步. 后文详述.
查找设备:
通过BluetoothAdapter, 我们可以通过设备发现和查询配对列表找到远程蓝牙设备.
设备发现是一个扫描程序, 可以搜索附近区域启动了蓝牙的设备并获取各个设备的信息. 但是只有当该远程设备启动了”被发现”功能的时候才有可能被发现. 如果一个设备是可发现的, 那么它将会通过共享信息来回应发现需求, 比如设备的名字, 类, 和MAC地址. 使用这些信息, 就可以选择启动与该设备的连接了.
一旦首次建立了跟远程设备的连接, 一个配对需求会自动展现给用户. 当设备配对了之后, 关于该基础信息就会被保存并可以使用蓝牙API读取到. 使用其中的MAC地址就可以启动一个与它的连接而不用再次处理发现了(假如设备是在范围内的).
配对和连接之间有一个不同. 配对意味着两个设备都知道对方的存在, 有一个共享的link-key在认证的时候可以用, 并可以建立彼此的加密连接. 而”连接上”则意味着设备当前共享一个RFCOMM通道并可以交换数据. 当前Android Bluetooth API要求设备进行RFCOMM连接建立之前需要先进行配对(当通过Bluetooth API启用一个加密连接的时候, 配对将会被自动执行).
下面的小节将会介绍如何找到已经配对的设备以及如何用设备发现功能发现新的设备.
注意: Android设备默认情况下是不可发现的. 用户可以通过系统设置让设备可以被发现一段时间, 或者APP可以请求用户开启发现功能.
查询配对设备:
在执行设备发现之前, 查询一下要连接的设备是否在已经配对的设备列表中是有必要的. 想要实现这个操作, 调用getBonderDevices()方法. 该方法会返回一组BluetoothDevice来描述配对设备. 栗如, 我们可以查询所有的配对设备, 然后用一个列表展示给用户, 用一个ArrayAdapter:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n&#