、低功耗藍牙的使用
Android中關于藍牙的開發文檔,可以參考Google提供的官方藍牙文檔:https://developer.android.google.cn/guide/topics/connectivity/bluetooth.html
在Android開發中,應用可通過官方提供的藍牙API執行以下操作:
一個近距離無線通信技術,最早是由愛立信研發出來。藍牙 Bluetooth 這個詞是一個丹麥的國王的綽號,當時研發它的工程師正在看一個關于這個國王的書,就起了這個名字。藍牙的技術特點是:
藍牙從被發明到目前,經過了幾個版本的變化:
低功耗藍牙全稱為Bluetooth Low Energy,簡稱為BLE,最大特點就是低功耗,另外低功耗藍牙還具備成本低,連接速度快,安全性高的特點。當然,低功耗藍牙也相應的會有一些不足,比如說:低功耗對應的是低傳輸效率,因此低功耗藍牙主要用來傳輸少量數據,結合低功耗的特點,非常適合用在移動智能設備上。
低功耗藍牙分為兩種模式:單模和雙模。
注意:需要在Android 4.3及以上版本才能支持具備低功耗功能的藍牙4.0。
首先來看一下使用藍牙的基本流程:
先簡單來了解一下低功耗藍牙的協議框架,在BLE協議棧中,大致分為三個部分,從下到上依次為:控制器(Controller) 、主機(Host)、應用(Applications)。
協議層從下往上,依次包含如下協議:
UUID 是全局唯一標識,是128bit的值,為了便于識別和閱讀,一般標示成:8-4-4-12 的16進制格式。
Android 中提供了 UUID.randomUUID() 來生成一個隨機的 UUID。
在低功耗藍牙中,長度為128bit的UUID數據長度是受限的,因此藍牙中又產生出來了16bit和32bit的UUID,本質上和128bit的UUID一樣。
開發BLE應用,主要有兩大類:
本篇文章中,我們來討論面向連接的通信的情況。如果要與另外一個BLE設備進行通信,需要經過連接,確認狀態,然后再通信的過程。首先是開啟連接,然后會觸發對應的連接回調,然后發現服務,觸發發現服務回調,獲取服務內部的特征值,對其讀寫命令(和 BLE 共同約束的規范),就是這么一個過程,比較簡單。
每個移動智能設備幾乎都帶有WIFI連接功能,在Android系統中,同樣也提供了WIFI開發的相關的API。
Android系統提供的WIFI API,主要包含在兩個包中:
和wifi相關的核心API主要有以下幾個內容:
public void addNetworkAndConn(WifiConfiguration wcg) {
int netId = mWifiManager.addNetwork(wcg);
mWifiManager.enableNetwork(netId, true);
}
public void disconnectWifi(int netId) {
mWifiManager.disableNetwork(netId);
mWifiManager.disconnect();
}
public void startScan() {
mWifiManager.startScan();
// 得到掃描結果
List<ScanResult> wifiList = mWifiManager.getScanResults();
// 得到配置好的網絡連接
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
}
在進行wifi開發時,既要用到網絡,也要用到硬件資源,因此需要申請一些必要的權限,而且涉及到的還比較的多,主要的權限如下:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"></uses-permission>
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"></uses-permission>
WIFI Direct 意為通過 WIFI 直接建立連接。允許無線網絡中的設備無須通過無線路由器即可相互連接。這種標準支持 WIFI 的無線設備像藍牙那樣以點對點的形式互連,但是在傳輸速度與傳輸距離方面都比藍牙有大幅提升。
WIFI Direct 提供 WifiP2pManager 類,其功能主要分為以下三部分:
WifiP2pManager的核心API用法說明如下所示:
在WifiP2pManager使用時,同樣支持使用各種監聽回調接口:
Android 傳感器屬于虛擬設備,可提供來自以下各種物理傳感器的數據:
以上的這些均可以歸納為傳感器類別,在Android中,這些傳感器有一個相同的定義文件,存在一個 sensors.h文件,其中定義了Android系統支持的每一種傳感器。格式為:ENSOR_TYPE_傳感器名稱。
該圖為Android系統中傳感器的的架構和分層。可以看出,幾乎和Android系統整體的架構一樣。從上層到下層,從應用層到底層內核層。
Android傳感器框架放在android.hardware包中,核心的API如下所示:
無論如何變化,其實通過上面的描述和介紹,我們看到,傳感器是底層系統提供的,數據也是相關的API返回獲取的。因此,在涉及到傳感器開發時,開發者的核心操作只有兩個:
因此,Android中的傳感器部分的應用開發,重點不是在于傳感器的使用,是開發者自己特定的應用,在獲取到數據后,對數據的處理和挖掘,是重中之重。
Android中支持的傳感器分為很多類別,主要有:
經過本篇文檔的介紹,結合之前的課程內容,我們可以總結出一個規律。在Android開發時,很多情況下我們都可以直接通過某個上下文,獲取xxxManager,往往是某個管理者。這些管理者是Android系統提供的系統服務,我們可以統稱為SystemService,現在我們了解一下SystemService有關的內容,并做個總結。
SystemService是系統提供給開發者的調用系統層的控制接口,應用層的開發者只需要了解這些接口的使用方式,就可以非常方便的進行系統控制,完成自己想要的功能操作,獲取系統的相關信息,而不需要了解接口的具體內部實現方式。這些SystemManager是在framework層或者更底層進行實現的。
相反的對于Framework層的開發者而言,需要了解XXXManager服務的實現細節和方式,并維護Manager接口,擴展或者實現新接口等。
我們可以列舉一下我們在學習過程中遇到的Manager,比如:
除此以外,還有很多很多,以上這些管理者,其實背后都是有一個系統服務SystemService。
getSystemService是Android很重要的一個API,它是Activity的一個方法,根據傳入的NAME來取得對應的Object,然后轉換成相應的服務對象。
款指紋模塊
支持APP遠程控制
HLK-EL605A是一款藍牙半導體指紋鎖解決方案,與市面上已有的產品相比,該模組具有功耗低、識別速度快、識別準確度高等優勢。
HLK-EL605A使用方便,尤其適合室內房門鎖等體積較小、使用電池供電的設備中,低功耗的同時可以保持優異的反應性能及高速的識別速度。
HLK-EL605A模塊使用05mm*8Pin FPC插座與擴展板連接可以使用普通線纜進行連接,增強連接可靠性。
HLK-EL605A的資料鏈接:
https://h.hlktech.com/Mobile/download/fdetail/237.html
一、指紋+APP兩種解鎖方式
HLK-EL605A指紋模塊支持BLE5.1藍牙通訊,在日常使用中支持指紋識別解鎖和APP遠程控制解鎖兩種解鎖方式。
01
指紋極速解鎖
HLK-EL605A指紋模塊采用電容式指紋傳感器,通過測量指紋信號,可以有效檢測假手指問題。指紋傳感器表面使用高硬度涂層,在日常使用中,可以極大的減少對指紋傳感器的磨損。
0.3S內極速解鎖,指紋就是鑰匙,開門快人一步,非常適用于智能門鎖、考勤門鎖等產品。
算法規格:
① 認假率FAR(FalseAcceptanceRate):<1/100000
② 拒真率 FRR(False Rejection Rate): <1%
③ 響應速度(平均):特征提取時間<0.25s,單枚平均匹配時間<0.002s
④ 指紋存儲:支持存儲20枚指紋特征
⑤ 支持指紋拼接,拼接最大次數:6次
⑥ 支持360°識別
⑦ 支持自學習功能
02
APP遠程控制
HLK-EL605A指紋模塊支持通過涂鴉APP遠程控制。在通過藍牙添加指紋設備后,可以實現APP對指紋模塊的智能管理。
涂鴉APP智能控制指紋模塊功能:
① 剩余電量實時顯示
② 查看開鎖記錄和警告信息
③ 快速添加或者刪除指紋
④ 遠程開鎖
除了上述功能外,用戶可根據需求開發更多功能,提高產品的實用性。
二、BLE5.1藍牙通訊
HLK-EL605A指紋模塊支持存儲20枚指紋特征; 支持指紋拼接,拼接最大次數6次。
同時,HLK-EL605A指紋模塊支持BLE5.1藍牙通訊,可以通過藍牙連接小程序和APP控制模塊,支持定制開發小程序和APP。
三、支持電機、蜂鳴器等控制
HLK-EL605A指紋模塊支持 3.4V~6V供電;支持1路電機芯片正反轉控制支持1路電機堵轉檢測;支持1路蜂鳴器控制;支持1路按鍵檢測;支持1路可擴展輸入/輸出IO。
四、自學習功能
當手指小面積接觸到采集器時,系統自動激活并采集對比指紋圖像及特征點信息。
指紋識別過程中,新提取的指紋特征值識別成功后將該特征值融合到指紋數據庫中。要次用戶成功解鎖手機后,指紋傳感器就會記錄之前尚未錄入的指紋部分,然后將該區域添加到數據中,使指紋數據更完整。隨著時間的推移,數據庫中關于指紋的信息會更多,解鎖會更快。
ndroid ble藍牙開發
BLE介紹
安卓4.3(API 18)為BLE的核心功能提供平臺支持和API,App可以利用它來發現設備、查詢服務和讀寫特性。相比傳統的藍牙,BLE更顯著的特點是低功耗。這一優點使AndroidApp可以與具有低功耗要求的BLE設備通信,如近距離傳感器、心臟速率監視器、健身設備等。
BLE開發
BLE權限添加
為了在app中使用藍牙功能,必須聲明藍牙權限BLUETOOTH。利用這個權限去執行藍牙通信,例如請求連接、接受連接、和傳輸數據。如果想讓你的app啟動設備發現或操縱藍牙設置,必須聲明BLUETOOTH_ADMIN權限。注意:如果你使用BLUETOOTH_ADMIN權限,你也必須聲明BLUETOOTH權限。在你的app manifest文件中聲明藍牙權限。
設置BLE
你的app能與BLE通信之前,你需要確認設備是否支持BLE,如果支持,確認已經啟用。雖然現在的手機基本都支持BLE,但是考慮到程序的健碩性,如果設置為false,這個檢查是必需的。
BluetoothAdapter類介紹
獲取:所有的藍牙活動都需要藍牙適配器。BluetoothAdapter代表設備本身的藍牙適配器(藍牙無線)。整個系統只有一個藍牙適配器,而且你的app使用它與系統交互。下面的代碼片段顯示了如何得到適配器。注意該方法使用getSystemService()]返回BluetoothManager,然后將其用于獲取適配器的一個實例。Android 4.3(API 18)引入BluetoothManager。
// 初始化藍牙適配器
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
有了mBluetoothAdapter之后就可以判斷當前藍牙開關狀態、藍牙未開啟情況下代碼里面自動開啟藍牙、以及掃描周邊的ble設備
開啟藍牙
接下來,你需要確認藍牙是否開啟。調用isEnabled())去檢測藍牙當前是否開啟。如果該方法返回false,藍牙被禁用。下面的代碼檢查藍牙是否開啟,如果沒有開啟,可以提示用戶去設置開啟藍牙。
// 確保藍牙在設備上可以開啟
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
//藍牙未開啟
}
發現BLE設備
為了發現BLE設備,使用startLeScan())方法。這個方法需要一個參數BluetoothAdapter.LeScanCallback。你必須實現它的回調函數,那就是返回的掃描結果。因為掃描非常消耗電量,你應當遵守以下準則:
1·只要找到所需的設備,停止掃描。
2·不要在循環里掃描,并且對掃描設置時間限制。以前可用的設備可能已經移出范圍,繼續掃描消耗電池電量。
以下代碼顯示如何掃描設備和停止掃描設備
// 10秒后停止尋找.
private static final long SCAN_PERIOD = 10000;
private void scanLeDevice(final boolean enable) {
if (enable) {
// 經過預定掃描期后停止掃描
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
...
}
...
}
如果你只想掃描指定類型的外圍設備,可以改為調用startLeScan(UUID[], BluetoothAdapter.LeScanCallback)),需要提供你的app支持的GATT services的UUID對象數組。
掃描的信息在LeScallCallback里面返回
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
//device 里面包含設備的mac地址和設備的名稱
//scanRecord里面就是ble設備發出的廣播包數據
//rssi表示ble設備的信號值,該值為負數,值越大表示信號值越好
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
連接到GATT服務端
與一個BLE設備交互的第一步就是連接它——更具體的,連接到BLE設備上的GATT服務端。為了連接到BLE設備上的GATT服務端,需要使用connectGatt( )方法。這個方法需要三個參數:一個Context對象,自動連接(boolean值,表示只要BLE設備可用是否自動連接到它),和BluetoothGattCallback調用。
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
連接到GATT服務端時,由BLE設備做主機,并返回一個BluetoothGatt實例,然后你可以使用這個實例來進行GATT客戶端操作。請求方(Android app)是GATT客戶端。BluetoothGattCallback用于傳遞結果給用戶,例如連接狀態,以及任何進一步GATT客戶端操作。
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {//當連接狀態發生改變
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {//當藍牙設備已經連接
//獲取ble設備上面的服務
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//當設備無法連接
}
}
@Override
//調用discoverServices后的回調
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//獲取服務成功
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
@Override
// 讀寫特性
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
...
};
...
}
發送數據
首先通過UUID拿到對應的服務,再通過UUID拿到服務的特征,設置特征的屬性是BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE。設置成功后可以在該特征值上發送數據到ble設備和接收ble設備的數據。看到這里也許各位不熟ble開發和剛ble開發的看官也許就一臉懵逼,我只是想發送數據到ble設備,怎么一下子搞出個UUID 服務和特征值了,難道就不能和B/S開發一樣,連接之后我把數據發送到一個接口,服務器端就返回我需要的數據那么簡單。這還得從ble藍牙的架構說起。
BLE分為三部分Service、Characteristic、Descriptor,這三部分都由UUID作為唯一標示符。一個藍牙4.0的終端可以包含多個Service,一個Service可以包含多個Characteristic,一個Characteristic包含一個Value和多個Descriptor,一個Descriptor包含一個Value。service是characteristic的集合.一個characteristic包括一個單一變量和0-n個用來描述characteristic變量的descriptor.Descriptor用來描述characteristic變量的屬性。例如,一個descriptor可以規定一個可讀的描述,或者一個characteristic變量可接受的范圍,或者一個characteristic變量特定的測量單位。一般來說,Characteristic是手機與BLE終端交換數據的關鍵.。
舉個栗子:當我們想要用手機與BLE設備進行通信時,實際上也就相當于我們要去找一個學生交流,首先我們需要搭建一個管道,也就是我們需要先獲取得到一個BluetoothGatt,其次我們需要知道這個學生在哪一個班級,學號是什么,這也就是我們所說的serviceUUID,和charUUID。這里我們還需要注意一下,找到這個學生后并不是直接和他交流,他就好像一個中介一樣,在手機和BLE終端設備之間幫助這兩者傳遞著信息,我們手機所發數據要先經過他,在由他傳遞到BLE設備上,而BLE設備上的返回信息,也是先傳遞到他那邊,然后手機再從他那邊進行讀取。
在發送數據之前需先設置特征的具有notificaion功能
private BluetoothGatt mBluetoothGatt;
BluetoothGattCharacteristic characteristic;
boolean enabled;
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
mBluetoothGatt.writeDescriptor(descriptor);
設置完成后回調
@Override
public final void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {
//設置成功
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
設置成功后就開始發送數據了。
//將指令放置進特征中
characteristic.setValue(data);
//設置回復形式characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
//開始寫數據
mBluetoothGatt.writeCharacteristic(chharacteristic);
寫入數據成功后回調
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
//發送數據成功啦啦啦
}
如何設備回復數據則會回調
@Override
public final void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
}
關閉客戶端App
當你的app完成BLE設備的使用后,應該調用close( )),系統可以合理釋放占用資源。
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
最后分享我在BLE 開發中遇到的坑和一些經驗
1 在所有藍牙的回調中不要操作UI。我是不會告訴你我是怎么發現這個坑的。
2 在所有的藍牙回調中不要執行耗時操作。
3 發送數據要等到上一條數據發送成功后再發下一條數據,畢竟BLE設備運算沒有手機快,這里可以推薦一個開源藍牙連接工具https://github.com/NordicSemiconductor/Android-nRF-Toolbox,里面非常好的對發送的數據做了一個數據隊列。
4 合理的控制掃描過程,一般出現133錯誤的時候重連就可以先去掃描再去連接。若掃描不到時不要馬上又去掃描,不然你把手機放那一夜,把設備遠離它,第二天回來看手機時會驚喜的發現手機沒電自動關機了
遇到的坑
1 斷線重連的時候總是報133錯誤,
斷線后不要馬上去連接.先掃描設備,掃描到設備后再去連接。
2 掃描不到設備
手動關閉藍牙再打開藍牙開關。這個可能是重連里面的掃描引起的,如果設備未在周邊,一直去掃描的話,后來設備在身邊也可能掃描不到設備。如果未能連接設備,也不能一直去掃描。掃描不到設備時說明設備并不到周邊,可以延遲多少時間后再去掃描
3 連接設備后發送數據,發送數據的回調函數也已經走了。沒有接收到數據
查看設置特征值的描述值
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
mBluetoothGatt.writeDescriptor(descriptor)的回調里面是不是回調成功了
4反復斷開藍牙后再重連導致連接失敗
斷開藍牙后應該調用close()方法釋放資源.連接時應該設置超時,在超時時間內繼續去連接,基本低、中、高端機都能重新連接上。
5 連接上之后自動斷開連接,重連上之后又自動斷開連接,如此反復。
我們的BLE設備在某些低端機會遇到這種問題。聽固件工程師說是BLE設備藍牙芯片頻率和手機藍牙頻率問題,需調BLE設備頻率。遇到這種問題APP就束手無策了。
6 反復操作斷開和連接導致系統藍牙掛掉(無響應)
基本也是沒有合理釋放資源導致
7 調用掃描操作導致APP無響應
查看系統藍牙是否掛掉了。基本和問題6類似
最后附上一個Nordic 公司開源的Android藍牙開發封裝好的庫地址
https://github.com/NordicSemiconductor/Android-BLE-Library
參考:http://www.cnblogs.com/cxk1995/p/5693979.html
*請認真填寫需求信息,我們會在24小時內與您取得聯系。