原文地址:http://developer.android.com/guide/topics/wireless/bluetooth.htmlhtml
翻譯:jykenanjava
更新:2012.06.19android
Android平臺支持藍牙網絡協議棧,實現藍牙設備之間數據的無線傳輸。本文檔描述了怎樣利用android平臺提供的藍牙API去實現藍壓設備之間的通訊。藍牙具備point-to-point 和 multipoint兩種鏈接功能。
使用藍牙API,能夠作到:
* 搜索藍牙設備
* 從本地的Bluetooth adapter中查詢已經配對的設備
* 創建RFCOMM通道
* 經過service discovery鏈接到其它設備
* 在設備之間傳輸數據
* 管理多個鏈接數據庫
本文檔介紹瞭如何使用Android的藍牙API來完成的四個必要的主要任務,使用藍牙進行設備通訊,主要包含四個部分:藍牙設置、搜索設備(配對的或可見的)、鏈接、傳輸數據。
全部的藍牙API在android.bluetooth包中。實現這些功能主要須要下面這幾個類和接口:安全
BluetoothAdapter
表明本地藍牙適配器(藍牙發射器),是全部藍牙交互的入口。經過它能夠搜索其它藍牙設備,查詢已經配對的設備列表,經過已知的MAC地址建立BluetoothDevice,建立BluetoothServerSocket監聽來自其它設備的通訊。服務器
BluetoothDevice
表明了一個遠端的藍牙設備, 使用它請求遠端藍牙設備鏈接或者獲取 遠端藍牙設備的名稱、地址、種類和綁定狀態。 (其信息是封裝在 bluetoothsocket 中) 。網絡
BluetoothSocket
表明了一個藍牙套接字的接口(相似於 tcp 中的套接字) ,他是應用程 序經過輸入、輸出流與其餘藍牙設備通訊的鏈接點。app
BluetoothServerSocket
表明打開服務鏈接來監聽可能到來的鏈接請求 (屬於 server 端) , 爲了鏈接兩個藍牙設備必須有一個設備做爲服務器打開一個服務套接字。 當遠端設備發起連 接鏈接請求的時候,而且已經鏈接到了的時候,Blueboothserversocket 類將會返回一個 bluetoothsocket。框架
BluetoothClass
描述了一個設備的特性(profile)或該設備上的藍牙大體能夠提供哪些服務(service),但不可信。好比,設備是一個電話、計算機或手持設備;設備能夠提供audio/telephony服務等。能夠用它來進行一些UI上的提示。
BluetoothProfileless
BluetoothHeadset
提供手機使用藍牙耳機的支持。這既包括藍牙耳機和免提(V1.5)模式。
BluetoothA2dp
定義高品質的音頻,能夠從一個設備傳輸到另外一個藍牙鏈接。 「A2DP的」表明高級音頻分配模式。
BluetoothHealth
表明了醫療設備配置代理控制的藍牙服務
BluetoothHealthCallback
一個抽象類,使用實現BluetoothHealth回調。你必須擴展這個類並實現回調方法接收更新應用程序的註冊狀態和藍牙通道狀態的變化。
BluetoothHealthAppConfiguration
表明一個應用程序的配置,藍牙醫療第三方應用註冊與遠程藍牙醫療設備交流。
BluetoothProfile.ServiceListener
當他們已經鏈接到或從服務斷開時通知BluetoothProfile IPX的客戶時一個接口(即運行一個特定的配置文件,內部服務)。
爲了在你的應用中使用藍牙功能,至少要在AndroidManifest.xml中聲明兩個權限:BLUETOOTH(任何藍牙相關API都要使用這個權限) 和 BLUETOOTH_ADMIN(設備搜索、藍牙設置等)。
爲了執行藍牙通訊,例如鏈接請求,接收鏈接和傳送數據都必須有BLUETOOTH權限。
必需要求BLUETOOTH_ADMIN的權限來啓動設備發現或操縱藍牙設置。大多數應用程序都須要這個權限能力,發現當地的藍牙設備。此權限授予其餘的能力不該該使用,除非應用程序是一個「電源管理」,將根據用戶要求修改的藍牙設置
註釋:要請求BLUETOOTH_ADMIN的話,必需要先有BLUETOOTH。
在你的應用manifest 文件中聲明藍牙權限。例如:
1
2
3
4
|
<manifest ... > <uses-permission android:name="android.permission.BLUETOOTH" /> ... </manifest>
|
經過查看<uses-permission>
資料來聲明應用權限獲取更多的信息。
在你的應用經過藍牙進行通訊以前,你須要確認設備是否支持藍牙,若是支持,確信它被打開。
若是不支持,則不能使用藍牙功能。若是支持藍牙,但不可以使用,你剛要在你的應用中請求使用藍牙。這個要兩步完成,使用BluetoothAdapter。
1.獲取BluetoothAdapter
全部的藍牙活動請求BluetoothAdapter,爲了獲取BluetoothAdapter,呼叫靜態方法getDefaultAdapter() 。這個會返回一個BluetoothAdapter,表明設備本身的藍牙適配器(藍牙無線電)。這個藍牙適配器應用於整個系統中,你的應用能夠經過這個對象進行交互。若是getDefaultAdapter()返回null,則這個設備不支持藍牙。例如:
1
2
3
4
|
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth }
|
2.打開藍牙
其次。你須要肯定藍牙可以使用。經過isEnabled()來檢查藍牙當前是否可用。若是這個方法返回false,則藍牙不可以使用。爲了請求藍牙使用,呼叫startActivityForResult()與的ACTION_REQUEST_ENABLE動做意圖。經過系統設置中啓用藍牙將發出一個請求(不中止藍牙應用)。例如:
1
2
3
4
|
if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
|
![http://developer.android.com/images/bt_enable_request.png]
對話框中顯示請求使用藍牙權限。若是響應"Yes",這個進程完成(或失敗)後你的應用將可以使用藍牙。
REQUEST_ENABLE_BT常量做爲一個整型傳到startActivityForResult()中(值必須大於0),該系統傳回給你,在你onActivityResult()做爲實現的requestCode參數。
若是調用藍牙成功,你的Activity就會在onActivityResult()中收到RESULT_OK結果,若是藍牙不能使用因爲錯誤(或用戶響應「NO」那麼結果返回RESULT_CANCELED。
除了經過onActivityResult(),還能夠經過監聽ACTION_STATE_CHANGED這個broadcast Intent來知道藍牙狀態是否改變。這個Intent包含EXTRA_STATE,EXTRA_PREVIOUS_STATE兩個字段,分別表明新舊狀態。可能的值是STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, 還有STATE_OFF。
小貼: Enabling discoverability 將自動啓用藍牙。若是您計劃執行藍牙活動以前,始終使設備可發現,你能夠跳過上面的步驟2。參閱enabling discoverability。
使用BluetoothAdapter能夠經過設備搜索或查詢配對設備找到遠程Bluetooth設備。
Device discovery(設備搜索)是一個掃描搜索本地已使能Bluetooth設備而且從搜索到的設備請求一些信息的過程(有時候會收到相似「discovering」,「inquiring」或「scanning」)。可是,搜索到的本地Bluetooth設備只有在打開被發現功能後纔會響應一個discovery請求,響應的信息包括設備名,類,惟一的MAC地址。發起搜尋的設備可使用這些信息來初始化跟被發現的設備的鏈接。
一旦與遠程設備的第一次鏈接被創建,一個pairing請求就會自動提交給用戶。若是設備已配對,配對設備的基本信息(名稱,類,MAC地址)就被保存下來了,可以使用Bluetooth API來讀取這些信息。使用已知的遠程設備的MAC地址,鏈接能夠在任什麼時候候初始化而沒必要先完成搜索(固然這是假設遠程設備是在可鏈接的空間範圍內)。
須要記住,配對和鏈接是兩個不一樣的概念:
配對意思是兩個設備相互意識到對方的存在,共享一個用來鑑別身份的鏈路鍵(link-key),可以與對方創建一個加密的鏈接。
鏈接意思是兩個設備如今共享一個RFCOMM信道,可以相互傳輸數據。
目前Android Bluetooth API's要求設備在創建RFCOMM信道前必須配對(配對是在使用Bluetooth API初始化一個加密鏈接時自動完成的)。
下面描述如何查詢已配對設備,搜索新設備。
注意:Android的電源設備默認是不能被發現的。用戶能夠經過系統設置讓它在有限的時間內能夠被發現,或者能夠在應用程序中要求用戶使能被發現功能。
在搜索設備前,查詢配對設備看須要的設備是否已是已經存在是很值得的,能夠調用getBondedDevices()來作到,該函數會返回一個描述配對設備BluetoothDevice的結果集。例如,可使用ArrayAdapter查詢全部配對設備而後顯示全部設備名給用戶:
1
2
3
4
5
6
7
8
9
|
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" + device.getAddress()); } };
|
BluetoothDevice對象中須要用來初始化一個鏈接惟一須要用到的信息就是MAC地址。
要開始搜索設備,只需簡單的調用startDiscovery() 。該函數時異步的,調用後當即返回,返回值表示搜索是否成功開始。搜索處理一般包括一個12秒鐘的查詢掃描,而後跟隨一個頁面顯示搜索到設備Bluetooth名稱。
應用中能夠註冊一個帶ACTION_FOUND Intent的BroadcastReceiver,搜索到每個設備時都接收到消息。對於每個設備,系統都會廣播ACTION_FOUND Intent,該Intent攜帶着而外的字段信息EXTRA_DEVICE和EXTRA_CLASS,分別包含一個BluetoothDevice和一個BluetoothClass。
下面的示例顯示如何註冊和處理設備被發現後發出的廣播:
代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// 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
|
警告:完成設備搜索對於Bluetooth適配器來講是一個重量級的處理,要消耗大量它的資源。一旦你已經找到一個設備來鏈接,請確保你在嘗試鏈接前使用了cancelDiscovery()來中止搜索。一樣,若是已經保持了一個鏈接的時候,同時執行搜索設備將會顯著的下降鏈接的帶寬,因此在鏈接的時候不該該執行搜索發現。
若是想讓本地設備被其餘設備發現,能夠帶ACTION_REQUEST_DISCOVERABLE action Intent調用startActivityForResult(Intent, int) 方法。該方法會提交一個請求經過系統剛設置使設備出於能夠被發現的模式(而不影響應用程序)。默認狀況下,設備在120秒後變爲能夠被發現的。能夠經過額外增長EXTRA_DISCOVERABLE_DURATION Intent自定義一個值,最大值是3600秒,0表示設備老是能夠被發現的(小於0或者大於3600則會被自動設置爲120秒)。下面示例設置時間爲300:
1
2
3
4
|
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent);
|
!
[http://developer.android.com/images/bt_enable_discoverable.png]
詢問用戶是否容許打開設備能夠被發現功能時會顯示一個對話框。若是用戶選擇「Yes」,設備會在指定時間事後變爲能夠被發現的。Activity的onActivityResult()回調函數被調用,結果碼等於設備變爲能夠被發現所需時長。若是用戶選擇「No」或者有錯誤發生,結果碼會是Activity.RESULT_CANCELLED。
提示:若是Bluetooth沒有啓用,啓用Bluetooth可被發現功能可以自動開啓Bluetooth。
在規定的時間內,設備會靜靜的保持能夠被發現模式。若是想在能夠被發現模式被更改時受到通知,能夠用ACTION_SCAN_MODE_CHANGED Intent註冊一個BroadcastReceiver,包含額外的字段信息EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE分別表示新舊掃描模式,其可能的值爲SCAN_MODE_CONNECTABLE_DISCOVERABLE(discoverable mode),SCAN_MODE_CONNECTABLE(not in discoverable mode but still able to receive connections),SCAN_MODE_NONE(not in discoverable mode and unable to receive connections)。
若是隻須要鏈接遠程設備就不須要打開設備的能夠被發現功能。只在應用做爲一個服務器socket的宿主用來接收進來的鏈接時才須要使能能夠被發現功能,由於遠程設備在初始化鏈接前必須先發現了你的設備。
爲了在兩臺設備上建立一個鏈接,你必須在軟件上實現服務器端和客戶端的機制,由於一個設備必須必須打開一個server socket,而另外一個必須初始化這個鏈接(使用服務器端設備的MAC地址進行初始化)。
當服務器端和客戶端在同一個RFCOMM信道上都有一個BluetoothSocket時,就能夠認爲它們之間創建了一個鏈接。在這個時刻,每一個設備能得到一個輸出流和一個輸入流,也可以開始數據傳輸。本節介紹如何在兩個設備之間初始化一個鏈接。
服務器端和客戶端得到BluetoothSocket的方法是不一樣的,服務器端是當一個進入的鏈接被接受時才產生一個BluetoothSocket,客戶端是在打開一個到服務器端的RFCOMM信道時得到BluetoothSocket的。
!
[http://developer.android.com/images/bt_pairing_request.png]
一種實現技術是,每個設備都自動做爲一個服務器,因此每一個設備都有一個server socket並監聽鏈接。而後每一個設備都能做爲客戶端創建一個到另外一臺設備的鏈接。另一種代替方法是,一個設備按需打開一個server socket,另一個設備僅初始化一個到這個設備的鏈接。
Note: 若是兩個設備在創建鏈接以前並無配對,那麼在創建鏈接的過程當中,Android框架將自動顯示一個配對請求的notification或者一個對話框,如Figure 3所示。因此,在嘗試鏈接設備時,你的應用程序無需確保設備之間已經進行了配對。你的RFCOMM鏈接將會在用戶確認配對以後繼續進行,或者用戶拒絕或者超時以後失敗。
若是要鏈接兩個設備,其中一個必須充當服務器,經過持有一個打開的BluetoothServerSocket對象。服務器socket的做用是偵聽進來的鏈接,若是一個鏈接被接受,提供一個鏈接好的BluetoothSocket對象。從BluetoothServerSocket獲取到BluetoothSocket對象以後,BluetoothServerSocket就能夠(也應該)丟棄了,除非你還要用它來接收更多的鏈接。
下面是創建服務器socket和接收一個鏈接的基本步驟:
1.經過調用listenUsingRfcommWithServiceRecord(String, UUID)獲得一個BluetoothServerSocket對象。
該字符串爲服務的識別名稱,系統將自動寫入到一個新的服務發現協議(SDP)數據庫接入口到設備上的(名字是任意的,能夠簡單地是應用程序的名稱)項。 UUID也包括在SDP接入口中,將是客戶端設備鏈接協議的基礎。也就是說,當客戶端試圖鏈接本設備,它將攜帶一個UUID用來惟一標識它要鏈接的服務,UUID必須匹配,鏈接纔會被接受。
2.經過調用accept()來偵聽鏈接請求。
這是一個阻塞的調用,知道有鏈接進來或者產生異常纔會返回。只有遠程設備發送一個鏈接請求,而且攜帶的UUID與偵聽它socket註冊的UUID匹配,鏈接請求才會被接受。若是成功,accept()將返回一個鏈接好的BluetoothSocket對象。
3.除非須要再接收另外的鏈接,不然的話調用close() 。
close()釋放server socket和它的資源,但不會關閉鏈接accept()返回的鏈接好的BluetoothSocket對象。與TCP/IP不一樣,RFCOMM同一時刻一個信道只容許一個客戶端鏈接,所以大多數狀況下意味着在BluetoothServerSocket接受一個鏈接請求後應該當即調用close()。
accept()調用不該該在主Activity UI線程中進行,由於這是個阻塞的調用,會妨礙其餘的交互。常常是在在一個新線程中作BluetoothServerSocket或BluetoothSocket的全部工做來避免UI線程阻塞。注意全部BluetoothServerSocket或BluetoothSocket的方法都是線程安全的。
下面是一個簡單的接受鏈接的服務器組件代碼示例:
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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) { } } }
|
本例中,僅僅只接受一個進來的鏈接,一旦鏈接被接受獲取到BluetoothSocket,就發送獲取到的BluetoothSocket給一個單獨的線程,而後關閉BluetoothServerSocket並跳出循環。
注意:accept()返回BluetoothSocket後,socket已經鏈接了,因此在客戶端不該該呼叫connnect()。
manageConnectedSocket()是一個虛方法,用來初始化線程好傳輸數據。
一般應該在處理完偵聽到的鏈接後當即關閉BluetoothServerSocket。在本例中,close()在獲得BluetoothSocket後立刻被調用。還須要在線程中提供一個公共的方法來關閉私有的BluetoothSocket,中止服務端socket的偵聽。
爲了實現與遠程設備的鏈接,你必須首先得到一個表明遠程設備BluetoothDevice對象。而後使用BluetoothDevice對象來獲取一個BluetoothSocket來實現來接。
下面是基本的步驟:
1.用BluetoothDevice調用createRfcommSocketToServiceRecord(UUID)獲取一個BluetoothSocket對象。
這個初始化的BluetoothSocket會鏈接到BluetoothDevice。UUID必須匹配服務器設備在打開BluetoothServerSocket 時用到的UUID(用java.util.UUID) listenUsingRfcommWithServiceRecord(String, UUID)。能夠簡單的生成一個UUID串而後在服務器和客戶端都使用該UUID。
2.調用connect()完成鏈接
當調用這個方法的時候,系統會在遠程設備上完成一個SDP查找來匹配UUID。若是查找成功而且遠程設備接受鏈接,就共享RFCOMM信道,connect()會返回。這也是一個阻塞的調用,無論鏈接失敗仍是超時(12秒)都會拋出異常。
注意:要確保在調用connect()時沒有同時作設備查找,若是在查找設備,該鏈接嘗試會顯著的變慢,慢得相似失敗了。
實例:
下面是一個完成Bluetooth鏈接的樣例線程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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) { } } }
|
注意 : 到cancelDiscovery()在鏈接操做前被調用。在鏈接以前,無論搜索有沒有進行,該調用都是安全的,不須要確認(固然若是有要確認的需求,能夠調用isDiscovering() )。
manageConnectedSocket()是一個虛方法,用來初始化線程好傳輸數據。
在對BluetoothSocket的處理完成後,記得調用close()來關閉鏈接的socket和清理全部的內部資源。
若是已經鏈接了兩個設備,他們都已經擁有各自的鏈接好的BluetoothSocket對象。那就是一個有趣的開始,由於你能夠在設備間共享數據了。使用BluetoothSocket,傳輸任何數據一般來講都很容易了:
1.經過socket獲取輸入輸出流來處理傳輸(分別使用getInputStream()和getOutputStream() )。
2.用read(byte[])和write(byte[])來實現讀寫。
僅此而已。
固然,仍是有不少細節須要考慮的。首要的,須要用一個專門的線程來實現流的讀寫。只是很重要的,由於read(byte[])和write(byte[])都是阻塞的調用。read(byte[])會阻塞直到流中有數據可讀。write(byte[])一般不會阻塞,可是若是遠程設備調用read(byte[])不夠快致使中間緩衝區滿,它也可能阻塞。因此線程中的主循環應該用於讀取InputStream。線程中也應該有單獨的方法用來完成寫OutputStream。
下面是一個如上面描述那樣的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
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) { } } }
|
構造函數中獲得須要的流,一旦執行,線程會等待從InputStream來的數據。當read(byte[])返回從流中讀到的字節後,數據經過父類的成員Handler被送到主Activity,而後繼續等待讀取流中的數據。
向外發送數據只需簡單的調用線程的write()方法。
線程的cancel()方法時很重要的,以便鏈接能夠在任什麼時候候經過關閉BluetoothSocket來終止。它應該總在處理完Bluetooth鏈接後被調用。
從Android 3.0開始,Bluetooth API就包含了對Bluetooth profiles的支持。 Bluetooth profile是基於藍牙的設備之間通訊的無線接口規範。 例如Hands-Free profile(免提模式)。 若是移動電話要鏈接一個無線耳機,他們都要支持Hands-Free profile。
你在你的類裏能夠完成BluetoothProfile接口來支持某一Bluetooth profiles。Android Bluetooth API完成了下面的Bluetooth profile:
下面是使用profile的基本步驟:
1.獲取默認的Bluetooth適配器。
2.使用getProfileProxy()來創建一個與profile相關的profile協議對象的鏈接。在下面的例子中,profile協議對象是BluetoothHeadset的一個實例。
3.設置BluetoothProfile.ServiceListener。該listener通知BluetoothProfile IPC客戶端,當客戶端鏈接或斷連服務器的時候
4.在[android.bluetooth.BluetoothProfile) onServiceConnected()](http://docs.eoeandroid.com/reference/android/bluetooth/BluetoothProfile.ServiceListener.html#onServiceConnectedint,)內,獲得一個profile協議對象的句柄。(
5.一旦擁有了profile協議對象,就能夠用它來監控鏈接的狀態,完成於該profile相關的其餘操做。
例如,下面的代碼片斷顯示如何鏈接到一個BluetoothHeadset協議對象,用來控制Headset profile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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)
|
從Android 3.0開始,應用程序能夠註冊偵聽預約義的Vendor-specific AT命令這樣的系統廣播(如Plantronics +XEVENT command)。例如,應用能夠接收到一個廣播,該廣播代表鏈接的設備電量太低,而後通知用戶作好其餘須要的操做。建立一個帶ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent的broadcast receiver來爲耳機處理
Android4.0(API級別14)推出了支持藍牙醫療設備模式(HDP),這使您能夠建立支持藍牙的醫療設備,使用藍牙通訊的應用程序,例如心率監視器,血液,溫度計和秤。藍牙衛生API包括基礎類BluetoothHealth,BluetoothHealthCallback,BluetoothHealthAppConfiguration。
在使用藍牙衛生API,它有助於理解這些關鍵的HDP概念:
建立 一個Android HDP應用要下面幾步:
1.獲取一個參考的BluetoothHealth代理對象.
相似普通的耳機和A2DP設備,你必須調用BluetoothProfile與getProfileProxy() 。ServiceListener 和醫療配置類型來創建一個配置代理對象的鏈接。
2.建立一個BluetoothHealthCallback和註冊的應用程序配置(BluetoothHealthAppConfiguration)做爲一個醫療sink。
3.創建一個鏈接到醫療設備。一些設備將初始化鏈接。 開展這一步對於這些設備,這是沒必要要的。
4.當鏈接成功到一個醫療設備時,使用文件描述符讀/寫到醫療設備。
接收到的數據須要使用健康管理,實現了IEEE11073-XXXXX規範進行解釋。
5.當完成後,關閉醫療通道和註銷申請。通道也有延伸靜止時關閉。
爲了完善這個例子說明這些步驟。查看Bluetooth HDP (Health Device Profile) 。