Android藍(lán)牙(API介紹)

1.簡介

通過藍(lán)牙API拖叙,可以實現(xiàn)以下內(nèi)容:

掃描其他藍(lán)牙設(shè)備

查詢配對藍(lán)牙設(shè)備的本地藍(lán)牙適配器

創(chuàng)建RFCOMM通道

通過服務(wù)發(fā)現(xiàn)連接其他設(shè)備

與其他設(shè)備進(jìn)行數(shù)據(jù)交互

管理多連接

2.基本要素

藍(lán)牙相關(guān)的API都存在android.bluetooth包內(nèi),主要包括以下幾個類和接口:

BluetoothAdapter

代表本地藍(lán)牙適配器慕购。BluetoothAdapter是所有藍(lán)牙設(shè)備交互的入口繁莹≌芍龋可以實現(xiàn)查找設(shè)備狮辽、遍歷配對設(shè)備仅乓、通過已知的MAC地址實例化BluetoothDevice赖舟、創(chuàng)建BluetoothServerSocket與其他設(shè)備進(jìn)行通信。

BluetoothDevice

代表一個遠(yuǎn)程藍(lán)牙設(shè)備方灾〗ㄌ悖可用于,通過BluetoothSocket請求與遠(yuǎn)程設(shè)備的連接裕偿,或者查詢設(shè)備信息(名字洞慎、地址、級別與配對狀態(tài))嘿棘。

BluetoothSocket

代表藍(lán)牙socket接口(類似于TCP Socket)劲腿。這是允許應(yīng)用與其他藍(lán)牙設(shè)備進(jìn)行數(shù)據(jù)交換的連接點,采用InputStream和OutputStream鸟妙。

BluetoothServerSocket

代表監(jiān)聽外來請求的開放服務(wù)socket(類似于TCP ServerSocket)焦人。為連接兩個Android設(shè)備挥吵,其中一個設(shè)備用這個類必須開放服務(wù)socket。當(dāng)遠(yuǎn)程藍(lán)牙設(shè)備向此設(shè)備進(jìn)行連接請求時花椭,當(dāng)連接被接受時忽匈,BluetoothServerSocket會返回一個連接的BluetoothSocket

BluetoothClass

描述一個藍(lán)牙設(shè)備的基本特點和性能矿辽。它是一個只讀的屬性集合丹允,定義了設(shè)備主要和次要的級別和服務(wù)。然而袋倔,它并沒有完全描述設(shè)備所支持的所有的藍(lán)牙配置文件和服務(wù)雕蔽,但是,對于設(shè)備類型來說是非常有用的宾娜。

BluetoothProfile

代表藍(lán)牙協(xié)議的接口批狐。是設(shè)備間基于藍(lán)牙通信的無線接口說明。例如Hands-Free Profile (HFP)前塔。

BluetoothHeadset

提供用于手機(jī)的藍(lán)牙耳機(jī)支持嚣艇。包括Bluetooth Headset和Hands-Free (v1.5) 協(xié)議。

BluetoothA2dp

定義高質(zhì)量音頻可以從一個設(shè)備通過藍(lán)牙連接傳輸?shù)搅硪粋€設(shè)備嘱根。"A2DP" 代表Advanced Audio Distribution Profile.

BluetoothHealth

代表健康設(shè)備配置文件協(xié)議髓废,控制藍(lán)牙設(shè)備。HDP Health Device Profile.

BluetoothHealthCallback

一個抽象類该抒,用于實現(xiàn)BluetoothHealth回調(diào)慌洪。必須繼承這個類并實現(xiàn)回調(diào)方法來接受應(yīng)用注冊狀態(tài)和藍(lán)牙通道狀態(tài)改變。

BluetoothHealthAppConfiguration

代表一個藍(lán)牙健康的第三方應(yīng)用與遠(yuǎn)程藍(lán)牙健康設(shè)備注冊通信應(yīng)用配置凑保。

BluetoothProfile.ServiceListener

一個當(dāng)服務(wù)(運行特殊配置文件的內(nèi)部服務(wù))連接與斷開時用于通知BluetoothProfileIPC代理的接口冈爹。

3.權(quán)限

<manifest...>

<uses-permissionandroid:name="android.permission.BLUETOOTH"/>

<uses-permissionandroid:name="android.permission. BLUETOOTH_ADMIN"/>

</manifest>

4.配置藍(lán)牙

使用藍(lán)牙進(jìn)行通信前,必須驗證設(shè)備支持藍(lán)牙欧引,并且藍(lán)牙可用频伤。主要分為兩步:

獲取BluetoothAdapter

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

if (mBluetoothAdapter == null) {

// Device does not support Bluetooth

}

使藍(lán)牙可用

private static final int REQUEST_ENABLE_BT = 1024;

if (!mBluetoothAdapter.isEnabled()) {

Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}

protect void onActivityResult(int requestCode, int resultCode, Intent data){

if(requestCode == REQUEST_ENABLE_BT){

if(resultCode == RESULT_OK)? // YES 用戶允許

if(resultCode == RESULT_CANCELED)? // NO 用戶取消

}

}

監(jiān)聽藍(lán)牙狀態(tài)改變

String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"

String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED"

String ACTION_AUDIO_STATE_CHANGED =

"android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED"

常量在BluetoothAdapter中定義。

ACTION_STATE_CHANGED

當(dāng)本地藍(lán)牙適配器的狀態(tài)改變時芝此,采用此廣播發(fā)送憋肖。intent中包含兩個狀態(tài)EXTRA_STATEEXTRA_PREVIOUS_STATE,分別表示當(dāng)前狀態(tài)和上一個狀態(tài)婚苹。

可能包含 的值為:STATE_OFF,STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF岸更。

5.查找設(shè)備

BluetoothAdapter可以查詢遠(yuǎn)程藍(lán)牙設(shè)備,也可以獲取配對設(shè)備列表膊升。

獲取配對列表

SetpairedDevices = 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" + device.getAddress());

}

}

搜索設(shè)備

調(diào)用boolean startDiscovery ()開始搜索怎炊,正確開始搜索時返回true。然后采用廣播監(jiān)聽的形式獲取藍(lán)牙設(shè)備。

調(diào)用boolean cancelDiscovery ()停止搜索评肆,一般在有遠(yuǎn)程設(shè)備連接時調(diào)用债查。

// Create a BroadcastReceiver for ACTION_FOUND

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

// When discovery finds a device

if (BluetoothDevice.ACTION_FOUND.equals(action)) {

// Get the BluetoothDevice object from the Intent

BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

// Add the name and address to an array adapter to show in a ListView

mArrayAdapter.add(device.getName() + "\n" + device.getAddress());

}

}

};

// Register the BroadcastReceiver

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

使能被發(fā)現(xiàn)

private static final int REQUEST_BT_DISCOVERABLE = 102;

Intent discoverableIntent = new

Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);

startActivityForResult(discoverableIntent,REQUEST_BT_DISCOVERABLE);

最大可查找時間為1小時,如果設(shè)為0時表示一直能被發(fā)現(xiàn)瓜挽。

onActivityResult()中監(jiān)聽返回值盹廷,如果resultCode為間隔值,說明返回成功秸抚,如果返回碼為RESULT_CANCELED速和,返回失敗。

6.連接設(shè)備

要在兩個設(shè)備間創(chuàng)建連接剥汤,需要同時實現(xiàn)服務(wù)端和客戶端機(jī)制,因為一個設(shè)備必須打開服務(wù)socket排惨,另一個必須初始化連接(用服務(wù)端設(shè)備的MAC地址進(jìn)行初始化連接)吭敢。當(dāng)服務(wù)端和客戶端之間在同一個RFCOMM通道存在一個連接的BluetoothSocket時被認(rèn)為是相互連接的。只有這樣暮芭,每一個設(shè)備可以獲取輸入輸出流并數(shù)據(jù)交換鹿驼。

服務(wù)端和客戶端可以采用不同的方式獲取需要的BluetoothSocket。服務(wù)端接受外來連接辕宏,接收到BluetoothSocket畜晰。客戶端想服務(wù)端打開一個RFCOMM通道時瑞筐,接收到BluetoothSocket凄鼻。

作為服務(wù)端連接

1.調(diào)用listenUsingRfcommWithServiceRecord(String, UUID)獲取BluetoothServerSocket

String 表示服務(wù)的名字;UUID代表Universally Unique Identifier聚假。

2.調(diào)用accept()監(jiān)聽連接請求

如果成功块蚌,將返回一個連接的BluetoothSocket

3.要接受其他連接是,調(diào)用close()

4.樣例

private class AcceptThread extends Thread {

private final BluetoothServerSocket mmServerSocket;

public AcceptThread() {

// Use a temporary object that is later assigned to mmServerSocket,

// because mmServerSocket is final

BluetoothServerSocket tmp = null;

try {

// MY_UUID is the app's UUID string, also used by the client code

tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME,

MY_UUID);

} catch (IOException e) { }

mmServerSocket = tmp;

}

public void run() {

BluetoothSocket socket = null;

// Keep listening until exception occurs or a socket is returned

while (true) {

try {

socket = mmServerSocket.accept();

} catch (IOException e) {

break;

}

// If a connection was accepted

if (socket != null) {

// Do work to manage the connection (in a separate thread)

manageConnectedSocket(socket);

mmServerSocket.close();

break;

}

}

}

/** Will cancel the listening socket, and cause the thread to finish */

public void cancel() {

try {

mmServerSocket.close();

} catch (IOException e) { }

}

}

作為客戶端連接

1.調(diào)用BluetoothDevicecreateRfcommSocketToServiceRecord(UUID)方法膘格,獲取BluetoothSocket峭范。

2.調(diào)用connect()初始化連接

3.樣例

private class ConnectThread extends Thread {

private final BluetoothSocket mmSocket;

private final BluetoothDevice mmDevice;

public ConnectThread(BluetoothDevice device) {

// Use a temporary object that is later assigned to mmSocket,

// because mmSocket is final

BluetoothSocket tmp = null;

mmDevice = device;

// Get a BluetoothSocket to connect with the given BluetoothDevice

try {

// MY_UUID is the app's UUID string, also used by the server code

tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

} catch (IOException e) { }

mmSocket = tmp;

}

public void run() {

// Cancel discovery because it will slow down the connection

mBluetoothAdapter.cancelDiscovery();

try {

// Connect the device through the socket. This will block

// until it succeeds or throws an exception

mmSocket.connect();

} catch (IOException connectException) {

// Unable to connect; close the socket and get out

try {

mmSocket.close();

} catch (IOException closeException) { }

return;

}

// Do work to manage the connection (in a separate thread)

manageConnectedSocket(mmSocket);

}

/** Will cancel an in-progress connection, and close the socket */

public void cancel() {

try {

mmSocket.close();

} catch (IOException e) { }

}

}

7.管理連接

調(diào)用socket的getInputStream()getOutputStream()獲得輸入輸出流

通過read(byte[])write(byte[])向流讀寫數(shù)據(jù)

樣例

private class ConnectedThread extends Thread {

private final BluetoothSocket mmSocket;

private final InputStream mmInStream;

private final OutputStream mmOutStream;

public ConnectedThread(BluetoothSocket socket) {

mmSocket = socket;

InputStream tmpIn = null;

OutputStream tmpOut = null;

// Get the input and output streams, using temp objects because

// member streams are final

try {

tmpIn = socket.getInputStream();

tmpOut = socket.getOutputStream();

} catch (IOException e) { }

mmInStream = tmpIn;

mmOutStream = tmpOut;

}

public void run() {

byte[] buffer = new byte[1024];? // buffer store for the stream

int bytes; // bytes returned from read()

// Keep listening to the InputStream until an exception occurs

while (true) {

try {

// Read from the InputStream

bytes = mmInStream.read(buffer);

// Send the obtained bytes to the UI activity

mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)

.sendToTarget();

} catch (IOException e) {

break;

}

}

}

/* Call this from the main activity to send data to the remote device */

public void write(byte[] bytes) {

try {

mmOutStream.write(bytes);

} catch (IOException e) { }

}

/* Call this from the main activity to shutdown the connection */

public void cancel() {

try {

mmSocket.close();

} catch (IOException e) { }

}

}

8.采用Profiles工作

android藍(lán)牙API提供下列協(xié)議的實現(xiàn)。

Headset:

BluetoothHeadset類瘪贱,通過IPC控制藍(lán)牙耳機(jī)服務(wù)的代理類纱控;包括Bluetooth Headset 和 Hands-Free (v1.5) profiles;包括對AT指令的支持菜秦,見第9甜害。

A2DP:

BluetoothA2dp類,通過IPC控制藍(lán)牙A2DP服務(wù)的代理類喷户。

Health Device:

BluetoothHealth類唾那,藍(lán)牙外接健康設(shè)備。

獲取默認(rèn)的藍(lán)牙適配器。

getProfileProxy()

創(chuàng)建與協(xié)議對象的連接闹获。

設(shè)置BluetoothProfile.ServiceListener期犬。當(dāng)與服務(wù)連接或斷開時,監(jiān)聽器通知BluetoothProfileIPC代理避诽。

onServiceConnected()中獲取協(xié)議代理對象龟虎。

一旦擁有了協(xié)議代理對象,就可以用它管理連接狀態(tài)沙庐,執(zhí)行與協(xié)議相關(guān)的其他操作鲤妥。

樣例

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指令

從3.0開始,應(yīng)用可以注冊接收由headsets設(shè)備發(fā)送的預(yù)定義的AT指令系統(tǒng)廣播拱雏。例如棉安,應(yīng)用可以接收表明連接設(shè)備電量低的廣播并且通知用戶,或其他需要的行為铸抑」钡ⅲ可以創(chuàng)建一個廣播接收器用ACTION_VENDOR_SPECIFIC_HEADSET_EVENT作為intent的ACTION,處理headset設(shè)備的AT指令鹊汛。

String ACTION = “android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT”

Health Device Profile

創(chuàng)建一個HDP應(yīng)用

1.獲取BluetoothHealth協(xié)議對象的引用蒲赂。與HFP和A2DP類似,必須調(diào)用getProfileProxy()刁憋、BluetoothProfile.ServiceListenerHEALTH協(xié)議類型

滥嘴,建立協(xié)議代理對象的連接。

2.創(chuàng)建BluetoothHealthCallback回調(diào)和注冊應(yīng)用配置(BluetoothHealthAppConfiguration) 至耻。

3.建立與健康設(shè)備的連接若皱。

4.當(dāng)連接成功,采用文件描述器想設(shè)備進(jìn)行讀寫有梆。

5.結(jié)束后是尖,關(guān)閉通道,取消注冊應(yīng)用泥耀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饺汹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子痰催,更是在濱河造成了極大的恐慌兜辞,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夸溶,死亡現(xiàn)場離奇詭異逸吵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缝裁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門扫皱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事韩脑∏饴瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵段多,是天一觀的道長首量。 經(jīng)常有香客問我,道長进苍,這世上最難降的妖魔是什么加缘? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮觉啊,結(jié)果婚禮上拣宏,老公的妹妹穿的比我還像新娘。我一直安慰自己杠人,他們只是感情好蚀浆,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搜吧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杨凑。 梳的紋絲不亂的頭發(fā)上滤奈,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音撩满,去河邊找鬼蜒程。 笑死,一個胖子當(dāng)著我的面吹牛伺帘,可吹牛的內(nèi)容都是我干的昭躺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼伪嫁,長吁一口氣:“原來是場噩夢啊……” “哼领炫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起张咳,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤帝洪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后脚猾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葱峡,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年龙助,在試婚紗的時候發(fā)現(xiàn)自己被綠了砰奕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖军援,靈堂內(nèi)的尸體忽然破棺而出仅淑,到底是詐尸還是另有隱情,我是刑警寧澤盖溺,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布漓糙,位于F島的核電站,受9級特大地震影響烘嘱,放射性物質(zhì)發(fā)生泄漏昆禽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一蝇庭、第九天 我趴在偏房一處隱蔽的房頂上張望醉鳖。 院中可真熱鬧,春花似錦哮内、人聲如沸盗棵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纹因。三九已至,卻和暖如春琳拨,著一層夾襖步出監(jiān)牢的瞬間瞭恰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工狱庇, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留惊畏,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓密任,卻偏偏與公主長得像颜启,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浪讳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 藍(lán)牙 注:本文翻譯自https://developer.android.com/guide/topics/conn...
    RxCode閱讀 8,626評論 11 99
  • 公司的項目最近需要用到藍(lán)牙開發(fā)的相關(guān)內(nèi)容缰盏,因此特地查閱了Google官方文檔的內(nèi)容并進(jìn)行二次整理,希望能對需要學(xué)習(xí)...
    Chuckiefan閱讀 32,418評論 44 123
  • 我早就發(fā)現(xiàn)課本教材遠(yuǎn)離經(jīng)典是個極大缺失,小學(xué)生心無雜念合呐,學(xué)習(xí)效果好暮的,應(yīng)多讀鉆石版的書籍,教材編寫外國寓言過于簡單淌实,...
    我為云朵閱讀 290評論 0 2
  • UITableView是iOS開發(fā)中常用到的控件,UITableView繼承自UIScrollView,很強大,多...
    墨跡momo閱讀 421評論 0 0
  • 女兒今年九月一號開始上幼兒園了冻辩,當(dāng)時她才二歲四個月猖腕。經(jīng)過兩個月的適應(yīng),她已經(jīng)接受了幼兒園恨闪,接送女兒上幼兒園的任務(wù)也...
    心遙遠(yuǎn)閱讀 148評論 0 0