Android -BLE藍牙小DEMO


代碼地址如下:
http://www.demodashi.com/demo/13890.html

原文地址:

https://blog.csdn.net/vnanyesheshou/article/details/51943870

一 環境

開發環境:
 jdk1.6 Eclipse
 or jdk1.8 AS3.0.1
運行環境:
 華為V10(Android8.0)
實現功能:
 Android 藍牙BLE (搜索設備、藍牙連接、通信等)。

二 代碼結構

AS

Eclipse

三、程序實現

一、ble簡單介紹

BLE: Bluetooth Low Energy,即藍牙低功耗,它是一種技術,從藍牙4.0開始支持。藍牙低功耗芯片有兩種模式:單模和雙模。

單模:只能執行低功耗協議棧,也就是只支持ble。
雙模:支持傳統藍牙以及ble的使用。

較傳統藍牙:傳輸速度更快,覆蓋范圍更廣,安全性更高,延遲更短,耗電低等優點。

關鍵術語和概念:
Gatt:(Generic Attribute Profile)—通用屬性配置文件,用於在ble鏈路上發送和接收被稱為“屬性”的數據塊。目前所有的ble應用都是基於GATT的。一個設備可以實現多個配置文件。

ble交互的橋梁是Service、Characteristic、Desciptor。
Characteristic:可以理解為一個數據類型,它包括一個value和0至多個對此characteristic的描述(Descriptor)。

Descriptor:對Characterisctic的描述,如范圍、單位等。

Service:Characteristic的集合。它可以包含多個Characteristic。

一個ble終端可以包含多個Service,一個Service可以包含多個Characteristic,一個Characteristic包含一個value和多個Descriptor,一個Descriptor包含一個value。其中Characteristic比較重要,用的比較多。
這三部分都由UUID作為唯一標示符,以此區分。
UUID(Universally Unique Identifier),含義是通用唯一識別碼,它是在一定范圍內唯一的機器生成的標識符。標准的UUID格式為:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12)。

ble中有四個角色:
廣播者(Braodcaster):廣播發送者,是不可連接的設備。
觀察者(Observer):掃描廣播,不能夠啟動連接。
廣播者和觀察者不能建立連接。應用:溫度傳感器和溫度顯示器。
外圍(periphery):廣播發送者,可連接的設備,在單一鏈路層作為從機。
中央(central):掃描廣播,啟動連接,在單一或多鏈路層作為主機。

中央和外圍可以進行配對、連接、數據通信。應用:手機和手表。
一個中央可以同時連接多個周邊,但是一個周邊只能連接一個中央(但是我測試,周邊可以連接多個中央設備,並且能正常通信)。

二、Android

注意:Android 4.3(API 18)引入ble相關接口。
相關類
目錄:frameworks/base/core/java/android/bluetooth/
BluetoothGatt:中央使用和處理數據;
BluetoothGattCallback:中央的回調。

BluetoothGattServer:周邊提供數據;

BluetoothGattServerCallback:周邊的回調

BluetoothGattService:Gatt服務

BluetoothGattCharacteristic:Gatt特性

BluetoothGattDescriptor:Gatt描述

2.1 中央設備

搜索ble設備

//搜索附近所有的外圍設備
mBluetoothAdapter.startLeScan(mLeScanCallback);
//搜索某些uuid的外圍設備。
mBluetoothAdapter.startLeScan(uuid[] ,mLeScanCallback);
停止掃描
mBluetoothAdapter.stopLeScan(mLeScanCallback);

監聽掃描結果。

mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
	public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
	}
};

device 搜索到的ble設備。
rssi 信號強度
scanRecord 遠程設備廣告記錄的內容(藍牙名稱)

發起連接請求,獲得中央。

mBluetoothGatt = device.connectGatt(mContext, false,mGattCallback);
第二個參數:

如果為false,則直接立即連接。
如果為true,則等待遠程設備可用時(在范圍內,。。)連接。並不是斷開后重新連接。

第三個參數:連接回調
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {};
BluetoothGattCallback 類中提供了許多回調,包括:連接狀態改變、characteristic的read、write、change,mtu change等。根據需要實現即可。

連接成功后,發送 gatt服務發現請求。mBluetoothGatt.discoverServices().
發現服務成功會失敗都會回調onServicesDiscovered()函數。通過mBluetoothGatt.getServices()獲取連接的ble設備所提供的服務列表,返回值類型為List

//連接狀態改變回調
onConnectionStateChange(BluetoothGatt gatt, int status, int newState){
 if(newState == BluetoothProfile.STATE_CONNECTED){
    //連接成功后,發送發現服務請求。
  mBluetoothGatt.discoverServices();
 }
}
//發現服務回調。
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
 if(status == BluetoothGatt.GATT_SUCCESS){
  //發現成功后,則可以通過下面方法獲取service 列表。
  mBluetoothGatt.getServices();
 }
}

獲得Characteristic和Descriptor。

通過服務列表中的BluetoothGattService,可以獲取到服務所包含的characteristic(getCharacteristics()返回值類型為List )。

通過BluetoothGattCharacteristic可以獲取特征所包含的descriptor(getDescriptors()返回值類型是List )。

BluetoothGattService、BluetoothGattCharacteristic和BluetoothGattDescriptor三個類中都提供了一個方法getUuid(),通過該方法可以獲取其對應的uuid,從而可以判斷是否是自己需要的service、characteristic或者descriptor。

通過獲取的特征值,可以進行下操作:

寫入特性值

讀取特性值

訂閱特性值。

寫入特征值:

characteristic.setValue(data.getBytes());

mBluetoothGatt.writeCharacteristic(characteristic);

要想成功寫入特征值:

首先此characteristic屬性滿足BluetoothGattCharacteristic.PROPERTY_WRITY或BluetoothGattCharacteristic.PROPERTY_WRITY_NO_RESPONSE,如果其property都不包含這兩個,寫特征值writeCharacteristic()函數直接返回false,什么都不做處理(具體可以看BluetoothGatt源碼)。
其次此characteristic權限應滿足BluetoothGattCharacteristic.PERMISSION_WRITE,否則onCharacteristicWrite()回調收到GATT_WRITE_NOT_PERMITTED回應。
寫特征值前可以設置寫的類型setWriteType(),寫類型有三種,如下:

WRITE_TYPE_DEFAULT 默認類型,需要外圍設備的確認,也就是需要外圍設備的回應,這樣才能繼續發送寫。
WRITE_TYPE_NO_RESPONSE 設置該類型不需要外圍設備的回應,可以繼續寫數據。加快傳輸速率。
WRITE_TYPE_SIGNED 寫特征攜帶認證簽名,具體作用不太清楚。

外圍設備收到中央寫特征值的請求,會回調 onCharacteristicWriteRequest
如果此次請求需要回應,則外圍設備回應 mGattServer.sendResponse
中央設備收到響應,回調onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status)

讀取特征值:

mBluetoothGatt.readCharacteristic(characteristic);
讀特征值與寫類似,也需要響應的權限和屬性。
該characteristic屬性需包含PROPERTY_READ,否則直接返回false(具體可以看BluetoothGatt源碼)。
該characteristic權限應滿足BluetoothGattCharacteristic.PERMISSION_READ,否則onCharacteristicRead()回調收到GATT_READ_NOT_PERMITTED回應。

外圍設備接收到中央設備的讀特征值請求,則會回調 onCharacteristicReadRequest()函數,
外圍設備應該回應此請求 sendResponse。
中央設備收到響應回調
onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)

訂閱:

//第二個參數:true則訂閱該特征,false則取消訂閱。
mBluetoothGatt.setCharacteristicNotification(characteristic, true);
當指定Characteristic值發生變化時,是否接收通知。
當設為true,如果Characteristic發生變化時,會回調方法:
onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
通過參數characteristic,可獲得getValue獲得其中的內容。
注意:雖然訂閱了該特征,並且該特征屬性也滿足PROPERTY_NOTIFY,但是並沒有收到特征值改變的回調。這是為什么呢?查看sdk中的demo,發現需要寫一下Descriptor。這樣就可以正常監聽特征值的改變了。

//CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb"
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(      UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);

中央設備的其他一些方法
readDescriptor(descriptor) 讀取描述
writeDescriptor(descriptor) 寫描述
readRemoteRssi() 讀取連接設備的rssi。
disconnect(); 斷開bel連接。
close(); 關閉中央設備。(不用時及時關閉,否則有的手機重連連不上。)

2.2 外圍設備

獲取/打開周邊(外圍)

mGattServer = mBluetoothManager.openGattServer(mContext, callback);
//其中callback是一個MyGattServerCallback(繼承了BluetoothGattServerCallback)對象。

初始化描述、特性和服務。

//描述: 
new BluetoothGattDescriptor(UUID.fromString(DESC_UUID), descPermissions);
//特性 :
final int properties = BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_WRITE  
| BluetoothGattCharacteristic.PROPERTY_NOTIFY; 
final int permissions = BluetoothGattCharacteristic.PERMISSION_READ;
| BluetoothGattCharacteristic.PERMISSION_WRITE;
new BluetoothGattCharacteristic(UUID.fromString(CHAR_UUID), properties, permissions);
gattChar.addDescriptor(gattDesc);

property 表示屬性。permission 表示權限。這兩個都和權限相關。
如果property未設置PROPERTY_READ,permission設置PERMISSION_READ,則中央設備readCharacteristic主動讀取特征值方法返回false,此操作失敗。
而如果property設置PROPERTY_READ,permission未設置PERMISSION_READ,則中央設備readCharacteristic主動讀取特征值方法返回true,此操作成功,外圍設備發送響應,中央設備收到響應 GATT_READ_NOT_PERMITTED。
所以說如果想要characteristic可讀,則這兩個都要設置。
PROPERTY_WRITE和PERMISSION_WRITE也和上面類似。
PROPERTY_NOTIFY 表示支持notification。

//服務:
BluetoothGattService bs = new BluetoothGattService( UUID.fromString(SERV_UUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
bs.addCharacteristic(gattChar);

第二個參數為service type,
SERVICE_TYPE_PRIMARY 基礎服務、主要服務。
SERVICE_TYPE_SECONDARY 輔助服務(由初級服務包含在內)。
BluetoothGattService 類中方法
addService(bluetoothGattService),將輔助服務添加到主要服務中。
getIncludeedServices() 獲取包含的服務列表。
getType() 獲取服務的type。
getUuid() 獲取服務的UUID。

添加服務
mGattServer.addService(bs);
設置廣播數據
開始廣播
這在android4.3沒有提供,在android5.0才提供了設置廣播數據,發送廣告包等方法。我們開發是基於android4.3的,按理說我們是不可以作為外圍設備的,不過我們framework以及底層都進行了修改,提供了這些方法,說以我們的android4.3設備可以作為外圍。

mGattServer.startAdvertising();//開始廣播
mGattServer.stopAdvertising();//停止廣播
收到central掃描請求,回應掃描請求。
這個不需要我們管理,此時會廣播之前的設置的廣播數據。

收到central連接請求,建立連接。

連接成功后 外圍可以斷開連接。
mGattServer.cancelConnection(device);
響應central發起的gatt服務發現請求,回應服務信息。
響應central發起的gatt特性發現請求,回應特性信息。
響應central發起的gatt描述發現請求,回應描述信息。
這三個不需要我們去操作,系統底層會處理。

對central的讀寫做響應。
回應特性值
更新特性值。

回應特征值:
MyGattServerCallback extends BluetoothGattServerCallback.
其中有幾個常用的方法:
onConnectionStateChange(BluetoothDevice device, int status, int newState)
監聽設備連接狀態。
  device遠程設備
  newStateble連接狀態,只能為BluetoothProfile.STATE_CONNECTED和BluetoothProfile.STATE_DISCONNECTED。

onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattCharacteristic characteristic)
監聽中心設備讀Characteristic的請求,
  requestId 請求的標識。
  offset 特性值偏移量。
 Characteristic 要讀的特性。
此方法要求作出響應。
mGattServer.sendResponse(device, requestId,
BluetoothGatt.GATT_SUCCESS, offset, null);
 最后一個參數可以設置傳的數據,byte[]類型的。

onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
監聽中心設備寫Characteristic的請求,
 preparedWrite true則寫操作必須排隊等待稍后執行。
 responseNeeded 是否需要響應。
 value 寫的數據。
需要響應則必須sendResponse.

更新特征值:
外圍設備向中心設備不能發送數據,必須通過notify 或者indicate的方式,andorid只發現notify接口。
characteristic.setValue(res.getBytes());
mGattServer.notifyCharacteristicChanged(device,
characteristic, false);
最后一個參數表示是否需要客戶端確認。

歡迎掃一掃關注我的微信公眾號,定期推送優質技術文章:


Android -BLE藍牙小DEMO

代碼地址如下:
http://www.demodashi.com/demo/13890.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM