在 android 系統(tǒng)上通過藍(lán)牙獲取通訊錄

在 android 系統(tǒng)上通過藍(lán)牙獲取通訊錄

*本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布

前言:

最近在研究通過藍(lán)牙通訊協(xié)議中的 PhoneBookAccessProfile(簡(jiǎn)稱 PBAP) 來獲取其它智能手機(jī)中的通訊錄。我們的目標(biāo)是,在 android 端運(yùn)行程序,該程序通過某個(gè)藍(lán)牙協(xié)議通過無線的方式獲取另一個(gè)手機(jī)上的通訊錄。這里,“另一個(gè)手機(jī)”可以是 android 設(shè)備也可以是 ios 設(shè)備。這也是我們選擇采用藍(lán)牙協(xié)議的一個(gè)原因:在某種程度上跨平臺(tái)。

幾種常見的藍(lán)牙協(xié)議:

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 其實(shí)泛指我們使用的藍(lán)牙設(shè)備。根據(jù)表格中的描述,想利用藍(lán)牙協(xié)議來獲取其他設(shè)備中的通訊錄,用 PhoneBookAccessProfile(PBAP) 協(xié)議就可以了。先不考慮代碼邏輯,通訊錄的獲取流程如下:

  1. 兩個(gè)藍(lán)牙設(shè)備配對(duì)
  2. 一端發(fā)起獲取通訊錄的請(qǐng)求
  3. 另一端會(huì)以某種方式(最常見的是彈窗)來請(qǐng)求本人授權(quán)
  4. 發(fā)起請(qǐng)求端獲取通訊錄數(shù)據(jù)

事實(shí)上,藍(lán)牙連接中,兩個(gè)設(shè)備間是不對(duì)等、不對(duì)稱的。一定會(huì)出現(xiàn)一個(gè)設(shè)備扮演客戶端的角色,另一個(gè)設(shè)備扮演服務(wù)端的角色??蛻舳诵枰龅木褪侨グl(fā)出某種請(qǐng)求,然后接受并處理服務(wù)端的返回?cái)?shù)據(jù);服務(wù)端需要做的就是一直監(jiān)聽是否有請(qǐng)求發(fā)過來,然后對(duì)請(qǐng)求做出響應(yīng)。整個(gè)機(jī)制跟 web 開發(fā)的流程是極其相似的,是可以無縫類比的。

android 對(duì)于藍(lán)牙開發(fā)的支持

android 本身對(duì)于藍(lán)牙協(xié)議進(jìn)行了高度的封裝。不過有的代碼可以在 android 官方文檔中查看到相關(guān)解釋,有的確只能自己翻代碼去看。
The BluetoothAdapter is the entry-point for all Bluetooth interaction. 正如文檔中所言,首先我們需要調(diào)用

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

來獲得 BluetoothAdapter 實(shí)例,然后需要通過這個(gè)實(shí)例獲取 BluetoothDevice 實(shí)例。這里做類似的調(diào)用:

Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
BluetoothDevice device = (BluetoothDevice) pairedDevices.toArray()[0];

首先通過 getBondedDevices() 來獲得一個(gè)已配對(duì)的設(shè)備的集合 pairedDevices。然后可以調(diào)用paredDevices.toArray()將集合轉(zhuǎn)化成數(shù)組。數(shù)組里面的每一項(xiàng)都是一個(gè) BluetoothDevice 實(shí)例。針對(duì) android 開發(fā),一般情況下會(huì)顯示一個(gè)列表,列表里面的數(shù)據(jù)源自device.getAddress() 以及 device.getName(),分別代表藍(lán)牙設(shè)備的地址以及名字。然后讓用戶手動(dòng)選擇一個(gè)藍(lán)牙設(shè)備去連接。在 onClick() 事件中,可以調(diào)用 adapter.getRemoteDevie(String address) 來通過藍(lán)牙設(shè)備地址來訪問該設(shè)備。
獲取到 BluetoothDevice 實(shí)例后,可以調(diào)用

BluetoothPbapClient client = new BluetoothPbapClient(device, yourHandler);
client.connect();
client.pullPhoneBook(BluetoothPbapClient.PB_PATH);
client.disconnect();

來完成通訊錄的獲取。其中,new BluetoothPbapClient(device, yourHandler);的 yourHandler 參數(shù)需要傳一個(gè) Handler 實(shí)例。利用 Handler 處理信息在 android 開發(fā)中已經(jīng)非常常見了。在傳入 yourHandler 實(shí)例之后,你就可以在它的 handleMessage(Message msg)函數(shù)中處理 BluetoothPbapClient 實(shí)例在工作的過程中發(fā)出的消息。比如,接收到 EVENT_PULL_PHONE_BOOK_DONE 信息后,輸出一下通訊錄的內(nèi)容或者基于通訊錄做一些其他事情等。代碼如下:

    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: {
                }
            }
        }
    }

注意:關(guān)于 BluetoothPbapClient 相關(guān)的類,需要在 android 源代碼中找,找到后直接 copy 到我們的工程下就好。需要用到的有:android.bluetooth.client.pbap.*;com.android.vcard.*,javax.obex.*。而且,這里有個(gè)小坑,就是低版本的 sdk 里面,相關(guān)的源代碼寫的有問題,需要到高版本的里面找,才能正確編譯。本人用的是 android-23 里面的文件。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容