1. 程式人生 > >Android 藍芽程式設計基礎

Android 藍芽程式設計基礎

在移動裝置上,聯網的方式很多,也存在了很大的差異,包括速度,有效範圍等等因素都會對網路有不同的要求,本文我們就先分析一下Ophone平臺上如何通過藍芽進行網路連線,進而使用藍芽來開發一些小的遊戲或者應用,這裡我們先從最基礎的開始,首先學習藍芽程式設計,我在查看了android sdk之後,發現藍芽聊天這個示例基本上已經包含了所有的藍芽基礎知識,但是學習例項之前,我們有必要介紹一下藍芽的基礎知識,我大概瀏覽了一下,沒有看到過多介紹藍芽開發包的使用的文章,因此我們這裡會對Ophone平臺中藍芽開發包進行一個詳細的介紹,後面則會通過一個藍芽聊天程式來進行實際開發。


藍芽API
  在OPhone平臺中,藍芽api主要存在於"android.bluetooth"包中,它提供了皆如掃描裝置、連線裝置以及對裝置間的資料傳輸進行管理的類,這些類對藍芽裝置進行功能性管理,藍芽模組API提供的應用包括一下幾個方面:
 掃描其它藍芽裝置
 通過查詢本地藍芽介面卡來匹配藍芽裝置
 建立RFCOMM(無線射頻通訊協議)的通道/埠
 從其他的藍芽裝置中連線到指定的埠
 傳輸資料到其他裝置,或者從其他裝置中接收資料
如需運用這些API來執行藍芽通訊,應用程式必須宣告BLUETOOTH許可。對於皆如尋找裝置請求等的一些附加功能,也同樣需要BLUETOOTH_ADMIN許可。比如本文所介紹的藍芽聊天程式就包含了一下兩個許可權許可:

  1. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />  
  2.   <uses-permission android:name="android.permission.BLUETOOTH" />  


在藍芽包(android.bluetooth)中有存在了以下幾個類和介面,下面我們看一下他們分別具有什麼樣的功能,如下表所示。

類\介面 功能描述
BluetoothAdapter 本地的藍芽介面卡裝置
BluetoothClass 描述了裝置通用特性和功能的藍芽類
BluetoothClass.Device 定義了所有裝置類的常量
BluetoothClass.Device.Major 定義了所有主要裝置類的常量
BluetoothClass.Service 定義了所有服務類的常量
BluetoothDevice 代表一個遠端的藍芽裝置
BluetoothServerSocket 監聽藍芽服務的埠
BluetoothSocket 一個雙向連線的藍芽埠socket

  BluetoothAdapter
  本地的藍芽介面卡。該類主要用來操作藍芽的基本服務。比如:初始化裝置的可見,查詢可匹配的裝置集,使用一個已知的MAC地址來初始化一個BluetoothDevice類,建立一個BluetoothServerSocket類以監聽其它裝置對本機的連線請求等。
如果要獲得本地藍芽介面卡,只有一個唯一的方式就是呼叫getDefaultAdapter()函式,同時也只有獲得了藍芽介面卡之後才能進一步的操作!下面我們將本地藍芽介面卡的api整理成以下一個表格。

 

  那麼上面的表中所列出的都是一些常用的操作,我們在稍後實現藍芽聊天程式時,都會介紹如何詳細的使用這些api。通常我們在使用一下程式碼請求使用藍芽時,會彈出一個許可權對話方塊,如圖14-1所示。

  1. Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
  2.   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);  


圖14-1 請求使用藍芽的許可權


當我們在使用ACTION_REQUEST_DISCOVERABLE來請求藍芽可見狀態時,也會彈出一個對話方塊來讓使用者確認,如圖14-2所示。請求藍芽可見程式碼如下:

  1. Intent discoverableIntent = new
  2.   Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
  3.   discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);  
  4.   startActivity(discoverableIntent);  


圖14-2 請求藍芽可見


最後,當我們的藍芽首次在配對時,同樣會出現如圖14-3所示的確認對話方塊。

 

  圖14-3 請求配對


BluetoothClass
  該類用來描述裝置通用特性和功能的藍芽類。比如,一個藍芽類會指定比如電話、計算機或耳機的通用裝置型別,可以提供比如音訊或者電話的服務。每個藍芽類都是有0個或更多的服務類,以及一個裝置類組成。裝置類將被分解成主要和較小的裝置類部分。BluetoothClass 用作一個能大致描述一個裝置(比如關閉使用者介面上一個圖示的裝置)的特性,但當藍芽服務事實上是被一個裝置所支撐的時候,BluetoothClass的描述則不一定很準確。精確的服務搜尋通過SDP請求來完成。當運用createRfcommSocketToServiceRecord(UUID) 和listenUsingRfcommWithServiceRecord(String, UUID)來建立RFCOMM埠的時候,SDP請求就會自動執行。我們可以使用getBluetoothClass()方法來獲取為遠端裝置所提供的類。
同樣,我們還是將該類的常用api列一個表,如下所示。

內部類
class BluetoothClass.Device 定義所有裝置類的常量。
class BluetoothClass.Service 定義所有服務類的常量。
常用方法
boolean equals(Object o) 判斷相等操作。
int getDeviceClass() 返回BluetoothClass.中的裝置類部分。
int getMajorDeviceClass() 返回BluetoothClass.中裝置類的主要部分。
boolean hasService(int service) 如果該指定服務類被BluetoothClass.所支援,則返回true。
int hashCode() 返回這個物件的整型雜湊碼。
String toString() 返回這個物件的字串。

這裡,有幾個方法需要說明一下,首先getDeviceClass()返回BluetoothClass.中的裝置類部分,從函式中返回的值可以和在BluetoothClass.Device中的公共常量做比較,從而確定哪個裝置類在這個藍芽類中是被編碼的;其次,getMajorDeviceClass()返回BluetoothClass.中裝置類的主要部分,從函式中返回的值可以和在BluetoothClass.Device.Major中的公共常量做比較,從而確定哪個主要類在這個藍芽類中是被編碼的。
BluetoothClass.Device
BluetoothClass.Device.Major
BluetoothClass.Service
  這三個類比較簡單,主要是包含了一推常量,其中BluetoothClass.Device中的常量代表主要和較小的裝置類部分(完整的裝置類)的組合。BluetoothClass.Device.Major的常量只能代表主要裝置類。而BluetoothClass.Service定義了所有服務類的常量。由於這些常量的數量比較多,這裡我們就不一一列舉了,詳細資訊大家可以參考sdk文件中:
  1. docs/reference/android/bluetooth/BluetoothClass.Device.html  
  2.   docs/reference/android/bluetooth/BluetoothClass.Device.Major.html  
  3.   docs/reference/android/bluetooth/BluetoothClass.Service.html  


BluetoothDevice
  該類是一個遠端藍芽裝置。我們可以建立一個帶有各自裝置的BluetoothDevice或者查詢其皆如名稱、地址、類和連線狀態等資訊。對於藍芽硬體地址而言,這個類僅僅是一個包裝器。這個類的物件是不可改變的。這個類上的操作會使用這個用來建立BluetoothDevice類的BluetoothAdapter類執行在遠端藍芽硬體上。為了獲得BluetoothDevice類,我們可以使用BluetoothAdapter.getRemoteDevice(String)方法去建立一個指定MAC地址的裝置(使用者可以通過帶有BluetoothAdapter類來完成對裝置的查詢)或者從一個通過BluetoothAdapter.getBondedDevices()得到返回值的有聯絡的裝置集合來得到該裝置。注意:使用該類需要加入BLUETOOTH許可權。該類主要包含一下api可供我們使用。

常量
String ACTION_ACL_CONNECTED 廣播活動:指明一個與遠端裝置建立的低級別(ACL)連線。
String ACTION_ACL_DISCONNECTED 廣播活動:指明一個來自於遠端裝置的低級別(ACL)連線的斷開。
String ACTION_ACL_DISCONNECT_REQUESTED 廣播活動:指明一個為遠端裝置提出的低級別(ACL)的斷開連線請求,並即將斷開連線。
String ACTION_BOND_STATE_CHANGED 廣播活動:指明一個遠端裝置的連線狀態的改變。
String ACTION_CLASS_CHANGED 廣播活動:一個已經改變的遠端裝置的藍芽類。
String ACTION_FOUND 廣播活動:發現遠端裝置。
String ACTION_NAME_CHANGED 廣播活動:指明一個遠端裝置的名稱第一次找到,或者自從最後一次找到該名稱開始已經改變。
int BOND_BONDED 表明遠端裝置已經匹配。
int BOND_BONDING 表明和遠端裝置的匹配正在進行中。
int BOND_NONE 表明遠端裝置並未匹配。
int ERROR 錯誤資訊。
String EXTRA_BOND_STATE 作為一個ACTION_BOND_STATE_CHANGED的整型附加域。
String EXTRA_CLASS 作為一個ACTION_FOUND and和ACTION_CLASS_CHANGED的Parcelabe BluetoothClass附加域。
String EXTRA_DEVICE 每次通過該類進行廣播時,作為Parcelable BluetoothDevice的附加域。
String EXTRA_NAME 作為ACTION_NAME_CHANGED和ACTION_FOUND的字串附加域。
String EXTRA_PREVIOUS_BOND_STATE 作為ACTION_BOND_STATE_CHANGED的整型附加域。
String EXTRA_RSSI 作為ACTION_FOUND的可選短整型附加域。
常用方法
BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) 建立一個RFCOMM 以準備開始一個對使用uuid的SDP查詢的遠端裝置進行安全而連線。
int describeContents() 描述了包含在Parcelable's marshalled representation中的特殊物件的種類。
String getAddress() 返回該藍芽裝置的硬體地址。
BluetoothClass getBluetoothClass() 獲得遠端裝置的藍芽類。
int getBondState() 獲得遠端裝置的連線狀態。
String getName() 獲得遠端藍芽裝置的名稱。
 

  下面有幾個需要說明的,ACL連線通過Android藍芽棧自動進行管理,需要BLUETOOTH去獲取。該類中常量所對應需要的常量值如下:


注意:toSting()函式會返回該藍芽裝置的字串表示式。當我們在取得藍芽地址時,一般會得到一個類似於"00:11:22:AA:BB:CC" 的字串,如果使用者明確需要藍芽硬體地址以防以後toString()表示式會改變的話,使用者總是需要使用getAddress()方法來獲取藍芽的地址。getName()函式也只獲取遠端藍芽裝置的名稱,當執行裝置掃描的時候,本地介面卡將自動尋找遠端名稱。該方法只返回來自儲存器中該裝置的名稱。該類中大多數方法的使用都需要獲得BLUETOOTH許可權。


BluetoothServerSocket
  該類用於實現一個藍芽的監聽埠,藍芽埠的監聽介面和TCP埠類似:Socket和ServerSocket類。在伺服器端,使用BluetoothServerSocket類來建立一個監聽服務埠。當一個連線被BluetoothServerSocket所接受,它會返回一個新的BluetoothSocket來管理該連線。在客戶端,使用一個單獨的BluetoothSocket類去初始化一個外接連線和管理該連線。最通常使用的藍芽埠是RFCOMM,它是被Android API支援的型別。RFCOMM是一個面向連線,通過藍芽模組進行的資料流傳輸方式,它也被稱為串列埠規範(Serial Port Profile,SPP)。為了建立一個對準備好的新來的連線去進行監聽BluetoothServerSocket類,使用BluetoothAdapter.listenUsingRfcommWithServiceRecord()方法。然後呼叫accept()方法去監聽該連結的請求。在連線建立之前,該呼叫會被阻斷,也就是說,它將返回一個BluetoothSocket類去管理該連線。每次獲得該類之後,如果不再需要接受連線,最好呼叫在BluetoothServerSocket類下的close()方法。關閉BluetoothServerSocket類不會關閉這個已經返回的BluetoothSocket類
BluetoothSocket類執行緒安全。特別的,close()方法總會馬上放棄外界操作並關閉伺服器埠。如果使用需要BLUETOOTH許可權的許可。我們後面將要介紹的藍芽聊天服務則整需要使用該功能。
該類提供了一下一些常用操作方法。


accept()函式將在一個成功建立的連線上返回一個已連線的BluetoothSocket類。每當該呼叫返回的時候,它可以在此呼叫去接收以後新來的連線。close()方法可以用來放棄從另一執行緒來的呼叫。close()將馬上關閉埠,並釋放所有相關的資源。在其他執行緒的該埠中引起阻塞,從而使系統馬上丟擲一個IO異常。關閉BluetoothServerSocket不會關閉接受自accept()的任意BluetoothSocket。


BluetoothSocket
  上面說過藍芽埠監聽介面和TCP埠類似:Socket和ServerSocket類。在伺服器端,使用BluetoothServerSocket類來建立一個監聽服務埠。當一個連線被BluetoothServerSocket所接受,它會返回一個新的BluetoothSocket來管理該連線。在客戶端,使用一個單獨的BluetoothSocket類去初始化一個外接連線和管理該連線。最通常使用的藍芽埠是RFCOMM,它是被Android API支援的型別。RFCOMM是一個面向連線,通過藍芽模組進行的資料流傳輸方式,它也被稱為串列埠規範(Serial Port Profile,SPP)。為了建立一個BluetoothSocket去連線到一個已知裝置,使用方法BluetoothDevice.createRfcommSocketToServiceRecord()。然後呼叫connect()方法去嘗試一個面向遠端裝置的連線。這個呼叫將被阻塞指導一個連線已經建立或者該連結失效。為了建立一個BluetoothSocket作為服務端(或者"主機"),檢視BluetoothServerSocket文件。每當該埠連線成功,無論它初始化為客戶端,或者被接受作為伺服器端,通過getInputStream()和getOutputStream()來開啟IO流,從而獲得各自的InputStream和OutputStream物件BluetoothSocket類執行緒安全。特別的,close()方法總會馬上放棄外界操作並關閉伺服器埠。如果使用需要BLUETOOTH許可權的許可。該類也就以下幾個方法需要大家掌握。


connect()函式連結到遠端裝置時,該方法將阻塞,指導一個連線建立或者失效。如果該方法沒有返回異常值,則該埠現在已經建立。當裝置查詢正在進行的時候,建立對遠端藍芽裝置的新連線不可被嘗試。在藍芽介面卡上,裝置查詢是一個重量級過程,並且肯定會降低一個裝置的連線。使用cancelDiscovery()方法去取消一個外界的查詢。查詢並不由活動所管理,而作為一個系統服務來執行,所以即使它不能直接請求一個查詢,應用程式也總會呼叫cancelDiscovery()方法。close()方法可以用來放棄從另一執行緒而來的呼叫。getInputStream()函式通過連線的埠獲得輸入資料流,即使該埠未連線,該輸入資料流也會返回。不過在該資料流上的操作將丟擲異常,直到相關的連線已經建立,當然在聊天例項中,也是我們用來讀取曉得資料流。而getOutputStream ()函式通過連線的埠獲得輸出資料流,即使該埠未連線,該輸出資料流也會返回。不過在該資料流上的操作將丟擲異常,直到相關的連線已經建立,同樣用於聊天例項上的傳送訊息操作。


總結
  本文主要分析了Ophone平臺中藍芽開發包中的各個類介面的功能和用途,同時也說明了藍芽程式設計並不苦難,掌握其通行機制,熟悉其API就能輕鬆的完成,當然了本文也還沒有涉及到具體的例項操作,但是這也是大家必須需要先掌握的基礎知識,大家對這些api有一個認識之後,下一篇文章我們就開始動手來做一個藍芽聊天程式。