在 android 系统上通过蓝牙获取通讯录
*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
前言:
最近在研究通过蓝牙通讯协议中的 PhoneBookAccessProfile(简称 PBAP) 来获取其它智能手机中的通讯录。我们的目标是,在 android 端运行程序,该程序通过某个蓝牙协议通过无线的方式获取另一个手机上的通讯录。这里,“另一个手机”可以是 android 设备也可以是 ios 设备。这也是我们选择采用蓝牙协议的一个原因:在某种程度上跨平台。
几种常见的蓝牙协议:
Protocol | Abbreviation | Benefit |
---|---|---|
Advanced Audio Distribution Protocol | A2DP | Audio streaming |
Audio/Video Remote Control Protocol | AVRCP | Control over music playback directly from the stereo |
Hands-free Profile | HFP | Hands-free calling through the stereo |
Object Push Profile | OPP | Uploading of contact info to the stereo |
Phone Book Access Profile | PBAP | Access to contact list from the stereo |
表格中的 stereo 其实泛指我们使用的蓝牙设备。根据表格中的描述,想利用蓝牙协议来获取其他设备中的通讯录,用 PhoneBookAccessProfile(PBAP) 协议就可以了。先不考虑代码逻辑,通讯录的获取流程如下:
- 两个蓝牙设备配对
- 一端发起获取通讯录的请求
- 另一端会以某种方式(最常见的是弹窗)来请求本人授权
- 发起请求端获取通讯录数据
事实上,蓝牙连接中,两个设备间是不对等、不对称的。一定会出现一个设备扮演客户端的角色,另一个设备扮演服务端的角色。客户端需要做的就是去发出某种请求,然后接受并处理服务端的返回数据;服务端需要做的就是一直监听是否有请求发过来,然后对请求做出响应。整个机制跟 web 开发的流程是极其相似的,是可以无缝类比的。
android 对于蓝牙开发的支持
android 本身对于蓝牙协议进行了高度的封装。不过有的代码可以在 android 官方文档中查看到相关解释,有的确只能自己翻代码去看。
The BluetoothAdapter is the entry-point for all Bluetooth interaction. 正如文档中所言,首先我们需要调用
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
来获得 BluetoothAdapter 实例,然后需要通过这个实例获取 BluetoothDevice 实例。这里做类似的调用:
Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
BluetoothDevice device = (BluetoothDevice) pairedDevices.toArray()[0];
首先通过 getBondedDevices()
来获得一个已配对的设备的集合 pairedDevices。然后可以调用paredDevices.toArray()
将集合转化成数组。数组里面的每一项都是一个 BluetoothDevice 实例。针对 android 开发,一般情况下会显示一个列表,列表里面的数据源自device.getAddress()
以及 device.getName()
,分别代表蓝牙设备的地址以及名字。然后让用户手动选择一个蓝牙设备去连接。在 onClick()
事件中,可以调用 adapter.getRemoteDevie(String address)
来通过蓝牙设备地址来访问该设备。
获取到 BluetoothDevice 实例后,可以调用
BluetoothPbapClient client = new BluetoothPbapClient(device, yourHandler);
client.connect();
client.pullPhoneBook(BluetoothPbapClient.PB_PATH);
client.disconnect();
来完成通讯录的获取。其中,new BluetoothPbapClient(device, yourHandler);
的 yourHandler 参数需要传一个 Handler 实例。利用 Handler 处理信息在 android 开发中已经非常常见了。在传入 yourHandler 实例之后,你就可以在它的 handleMessage(Message msg)
函数中处理 BluetoothPbapClient 实例在工作的过程中发出的消息。比如,接收到 EVENT_PULL_PHONE_BOOK_DONE 信息后,输出一下通讯录的内容或者基于通讯录做一些其他事情等。代码如下:
public static class BluetoothServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
LogUtil.d(msg);
switch (msg.what) {
case BluetoothPbapClient.EVENT_PULL_PHONE_BOOK_DONE: {
LogUtil.d("EVENT_PULL_PHONE_BOOK_DONE");
sPbapClient.disconnect();
}
break;
default: {
}
}
}
}
注意:关于 BluetoothPbapClient 相关的类,需要在 android 源代码中找,找到后直接 copy 到我们的工程下就好。需要用到的有:android.bluetooth.client.pbap.*;
,com.android.vcard.*
,javax.obex.*
。而且,这里有个小坑,就是低版本的 sdk 里面,相关的源代码写的有问题,需要到高版本的里面找,才能正确编译。本人用的是 android-23 里面的文件。