Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> Android藍牙開發全面總結

Android藍牙開發全面總結

編輯:Android資訊

基本概念

安卓平台提供對藍牙的通訊棧的支持,允許設別和其他的設備進行無線傳輸數據。應用程序層通過安卓API來調用藍牙的相關功能,這些API使程序無線連接到藍牙設備,並擁有P2P或者多端無線連接的特性。

藍牙的功能:

1、掃描其他藍牙設備

2、為可配對的藍牙設備查詢藍牙適配器

3、建立RFCOMM通道(其實就是尼瑪的認證)

4、通過服務搜索來鏈接其他的設備

5、與其他的設備進行數據傳輸

6、管理多個連接

藍牙建立連接必須要求:

1、打開藍牙

2、查找附近已配對或可用設備

3、連接設備

4、設備間數據交互

首先,要操作藍牙,先要在AndroidManifest.xml裡加入權限

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

Android所有關於藍牙開發的類都在android.bluetooth包下,只有8個類

1.BluetoothAdapter 藍牙適配器

直到我們建立bluetoothSocket連接之前,都要不斷操作它BluetoothAdapter裡的方法很多,常用的有以下幾個:

  cancelDiscovery() 根據字面意思,是取消發現,也就是說當我們正在搜索設備的時候調用這個方法將不再繼續搜索
  disable()關閉藍牙
  enable()打開藍牙,這個方法打開藍牙不會彈出提示,更多的時候我們需要問下用戶是否打開,一下這兩行代碼同樣是打開藍牙,不過會提示用戶:
  Intemtenabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enabler,reCode);//同startActivity(enabler);
  getAddress()獲取本地藍牙地址
  getDefaultAdapter()獲取默認BluetoothAdapter,實際上,也只有這一種方法獲取BluetoothAdapter
  getName()獲取本地藍牙名稱
  getRemoteDevice(String address)根據藍牙地址獲取遠程藍牙設備
  getState()獲取本地藍牙適配器當前狀態(感覺可能調試的時候更需要)
  isDiscovering()判斷當前是否正在查找設備,是返回true
  isEnabled()判斷藍牙是否打開,已打開返回true,否則,返回false
  listenUsingRfcommWithServiceRecord(String name,UUID uuid)根據名稱,UUID創建並返回BluetoothServerSocket,這是創建BluetoothSocket服務器端的第一步
  startDiscovery()開始搜索,這是搜索的第一步

  使用BluetoothAdapter的startDiscovery()方法來搜索藍牙設備
  startDiscovery()方法是一個異步方法,調用後會立即返回。該方法會進行對其他藍牙設備的搜索,該過程會持續12秒。該方法調用後,搜索過程實際上是在一個System Service中進行的,所以可以調用cancelDiscovery()方法來停止搜索(該方法可以在未執行discovery請求時調用)。
  請求Discovery後,系統開始搜索藍牙設備,在這個過程中,系統會發送以下三個廣播:
  ACTION_DISCOVERY_START:開始搜索
  ACTION_DISCOVERY_FINISHED:搜索結束
  ACTION_FOUND:找到設備,這個Intent中包含兩個extra fields:EXTRA_DEVICE和EXTRA_CLASS,分別包含BluetooDevice和BluetoothClass。
  我們可以自己注冊相應的BroadcastReceiver來接收響應的廣播,以便實現某些功能

2.BluetoothDevice 描述了一個藍牙設備

   createRfcommSocketToServiceRecord(UUIDuuid)根據UUID創建並返回一個BluetoothSocket
   getState() 藍牙狀態這裡要說一下,只有在 BluetoothAdapter.STATE_ON 狀態下才可以監聽,具體可以看andrid api;
   這個方法也是我們獲取BluetoothDevice的目的――創建BluetoothSocket
   這個類其他的方法,如getAddress(),getName(),同BluetoothAdapter

3.BluetoothServerSocket

這個類一種只有三個方法兩個重載的accept(),accept(inttimeout)兩者的區別在於後面的方法指定了過時時間,需要注意的是,執行這兩個方法的時候,直到接收到了客戶端的請求(或是過期之後),都會阻塞線程,應該放在新線程裡運行!

還有一點需要注意的是,這兩個方法都返回一個BluetoothSocket,最後的連接也是服務器端與客戶端的兩個BluetoothSocket的連接

   void	close()
   Closes the object and release any system resources it holds.
   void	connect()
   Attempt to connect to a remote device.
   InputStream	getInputStream()
   Get the input stream associated with this socket.
   OutputStream	getOutputStream()
   Get the output stream associated with this socket.
   BluetoothDevice	getRemoteDevice()
   Get the remote device this socket is connecting, or connected, to.
   獲取遠程設備,該套接字連接,或連接到---。
   boolean	isConnected()
   Get the connection status of this socket, ie, whether there is an active connection with remote device.
   判斷當前的連接狀態

4.BluetoothSocket

跟BluetoothServerSocket相對,是客戶端一共5個方法,不出意外,都會用到

  close(),關閉
  connect()連接
  getInptuStream()獲取輸入流
  getOutputStream()獲取輸出流
  getRemoteDevice()獲取遠程設備,這裡指的是獲取bluetoothSocket指定連接的那個遠程藍牙設備

5、BluetoothClass

代表一個描述了設備通用特性和功能的藍牙類。比如,一個藍牙類會指定皆如電話、計算機或耳機的通用設備類型,可以提供皆如音頻或者電話的服務。

每個藍牙類都是有0個或更多的服務類,以及一個設備類組成。設備類將被分解成主要和較小的設備類部分。

BluetoothClass 用作一個能粗略描述一個設備(比如關閉用戶界面上一個圖標的設備)的線索,但當藍牙服務事實上是被一個設備所支撐的時候,BluetoothClass的 介紹則不那麼可信任。精確的服務搜尋通過SDP請求來完成。當運用createRfcommSocketToServiceRecord(UUID) 和listenUsingRfcommWithServiceRecord(String, UUID)來創建RFCOMM端口的時候,SDP請求就會自動執行。

使用getBluetoothClass()方法來獲取為遠程設備所提供的類。

兩個內部類:

class   BluetoothClass.Device

定義所有設備類的常量

class   BluetoothClass.Service

定義所有服務類的常量

公共方法:

public int describeContents ()

描述包含在可封裝編組的表示中所有特殊對象的種類。

返回值 

一個指示被Parcelabel所排列的特殊對象類型集合的位掩碼。

public boolean equals (Object o)

比較帶有特定目標的常量。如果他們相等則標示出來。 為了保證其相等,o必須代表相同的對象,該對象作為這個使用類依賴比較的常量。通常約定,該比較既要可移植又需靈活。

當且僅當o是一個作為接收器(使用==操作符來做比較)的精確相同的對象是,這個對象的實現才返回true值。子類通常實現equals(Object)方法,這樣它才會重視這兩個對象的類型和狀態。

通常約定,對於equals(Object)和hashCode() 方法,如果equals對於任意兩個對象返回真值,那麼hashCode()必須對這些對象返回相同的紙。這意味著對象的子類通常都覆蓋或者都不覆蓋這兩個方法。

參數

o   需要對比常量的對象

返回值

如果特定的對象和該對象相等則返回true,否則返回false。

public int getDeviceClass ()

返回BluetoothClass中的設備類部分(主要的和較小的)

從函數中返回的值可以和在BluetoothClass.Device中的公共常量做比較,從而確定哪個設備類在這個藍牙類中是被編碼的。

返回值

設備類部分

public int getMajorDeviceClass ()

返回BluetoothClass中設備類的主要部分

從函數中返回的值可以和在BluetoothClass.Device.Major中的公共常量做比較,從而確定哪個主要類在這個藍牙類中是被編碼的。

返回值

主要設備類部分

public boolean hasService (int service)

如果該指定服務類被BluetoothClass所支持,則返回true

在BluetoothClass.Service中,合法的服務類是公共常量,比如AUDIO類。

參數

service 合法服務類

返回值

如果該服務類可被支持,則返回true

public int hashCode ()

返回這個對象的整型哈希碼。按約定,任意兩個在equals(Object)中返回true的對象必須返回相同的哈希碼。這意味著對象的子類通常通常覆蓋或者都不覆蓋這兩個方法。

注意:除非同等對比信息發生改變,否則哈希碼不隨時間改變而改變。

public String toString ()  

返回這個對象的字符串,該字符串包含精確且可讀的介紹。系統鼓勵子類去重寫該方法,並且提供了能對該對象的類型和數據進行重視的實現方法。默認的實現方法只是簡單地把類名、“@“符號和該對象hashCode()方法的16進制數連接起來(如下列所示的表達式):

public void writeToParcel (Parcel out, int flags)
     將類的數據寫入外部提供的Parcel中
    參數
out     對象需要被寫入的Parcel
flags  和對象需要如何被寫入有關的附加標志。可能是0,或者可能是PARCELABLE_WRITE_RETURN_VALUE。

以上是藍牙主要操作的類。

基本用法:

1、獲取本地藍牙適配器

  BluetoothAdapter mAdapter= BluetoothAdapter.getDefaultAdapter();

2、打開藍牙

  if(!mAdapter.isEnabled()){
  //彈出對話框提示用戶是後打開
  Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enabler, REQUEST_ENABLE);
  //不做提示,強行打開,此方法需要權限<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" />
  // mAdapter.enable();
}

3、搜索設備

1)mAdapter.startDiscovery() 是第一步,可能你會發現沒有返回的藍牙設備

2)定義BroadcastReceiver,代碼如下

// 創建一個接收ACTION_FOUND廣播的BroadcastReceiver
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  public void onReceive(Context context, Intent intent) {
	 String action = intent.getAction();
    // 發現設備
    if (BluetoothDevice.ACTION_FOUND.equals(action)) {
        // 從Intent中獲取設備對象
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        // 將設備名稱和地址放入array adapter,以便在ListView中顯示
        mArrayAdapter.add(device.getName() + "/n" + device.getAddress());
    }else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED  
                .equals(action)) {  
            if (mNewDevicesAdapter.getCount() == 0) {  
                Log.v(TAG, "find over");  
            }  
     }  
};
// 注冊BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // 不要忘了之後解除綁定

4、建立連接

首先Android sdk(2.0以上版本)支持的藍牙連接是通過BluetoothSocket建立連接,服務器端(BluetoothServerSocket)和客戶端(BluetoothSocket)需指定同樣的UUID,才能建立連接,因為建立連接的方法會阻塞線程,所以服務器端和客戶端都應啟動新線程連接

1)服務器端:
//UUID格式一般是"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"可到
    //http://www.uuidgenerator.com 申請
BluetoothServerSocket serverSocket = mAdapter. listenUsingRfcommWithServiceRecord(serverSocketName,UUID);
serverSocket.accept();

2)客戶端:
//通過BroadcastReceiver獲取了BLuetoothDevice
BluetoothSocket clienSocket=dcvice. createRfcommSocketToServiceRecord(UUID);
clienSocket.connect();

5、數據傳遞

通過以上操作,就已經建立的BluetoothSocket連接了,數據傳遞是通過流

1)獲取流

inputStream = socket.getInputStream();
	outputStream = socket.getOutputStream();

2)寫出、讀入(JAVA常規操作)

補充一下,使設備能夠被搜索

Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
	startActivityForResult(enabler,REQUEST_DISCOVERABLE);

關於藍牙連接:

可以直接用以下代碼進行連接:

final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";          
UUID uuid = UUID.fromString(SPP_UUID);          
BluetoothSocket socket;          
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);      
adapter.cancelDiscovery();       
socket.connect();

1.startDiscovey有可能啟動失敗

一般程序中會有兩步:開啟藍牙、開始尋找設備。順序執行了開啟藍牙-尋找設備的步驟,但是由於藍牙還沒有完全打開,就開始尋找設備,導致尋找失敗。

解決辦法:

adapter = BluetoothAdapter.getDefaultAdapter();     
 if (adapter == null)      {        
  // 設備不支持藍牙      
 }     
 // 打開藍牙       
if (!adapter.isEnabled()){          
	adapter.enable();     
	adapter.cancelDiscovery(); 
}      
// 尋找藍牙設備,android會將查找到的設備以廣播形式發出去       
while (!adapter.startDiscovery()){     
	Log.e("BlueTooth", "嘗試失敗");     
	try {         
		Thread.sleep(100);     
	} catch (InterruptedException e) {         
		e.printStackTrace();     
	} 
}

2.接收數據轉換

使用socket.getInputStream接收到的數據是字節流,這樣的數據是沒法分析的,所以很多情況需要一個byte轉十六進制String的函數:

public static String bytesToHex(byte[] bytes) { 
	char[] hexChars = new char[bytes.length * 2]; 
	for ( int j = 0; j < bytes.length; j++ ) {     
		int v = bytes[j] & 0xFF;     
		hexChars[j * 2] = hexArray[v >>> 4];     
		hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
	} 
	return new String(hexChars);
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved