Android Bluetooth BLE相关开发资源汇总
Android開啟藍(lán)牙開關(guān)
轉(zhuǎn)載自Android:Bluetooth 的打開和關(guān)閉
檢查系統(tǒng)藍(lán)牙是否開啟
BluetoothManager bluetoothManager = (BluetoothManager) this. getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter(); mBluetoothAdapter.isEnabled();開啟系統(tǒng)藍(lán)牙方式:
靜默打開:
- 注冊權(quán)限:
- 開啟方式:
以上靜默打開 Bluetooth 開關(guān)是調(diào)用了 BluetoothAdapter.enable() 方法,首先需要獲取 BluetoothAdapter 對象,如果這個對象為 null 的話,說明當(dāng)前設(shè)備不支持 Bluetooth 功能。還有以下幾點需要注意:
1, 在 Nexus 5 Android 4.4.4 原生系統(tǒng)中,在沒有任何其它管理 Bluetooth 權(quán)限的應(yīng)用情況下,調(diào)用強(qiáng)制打開 Bluetooth 的方法,沒有任何提示就直接打開 Bluetooth 了。
2,在小米手機(jī) MI 2SC / MIUI-4.7.11 (Android 4.1.1 JRO03L) 上系統(tǒng)自帶的 “安全中心” – “應(yīng)用權(quán)限管理” – “開啟藍(lán)牙” 中,有三種設(shè)置:
允許:調(diào)用強(qiáng)制打開 Bluetooth 代碼,沒有任何提示,Bluetooth 被成功打開。
提示:會彈出提示框,提示安全警告 “ ***應(yīng)用嘗試開啟藍(lán)牙”,可以選擇“拒絕”或“允許”,還有記住此次選擇(備注:如果不記住的話,下次還會彈出同樣的提示框,除非你自己去修改了應(yīng)用開啟藍(lán)牙的權(quán)限)。
拒絕:調(diào)用強(qiáng)制打開 Bluetooth 代碼,沒有任何提示,Bluetooth 強(qiáng)制打開失敗。
備注:各種手機(jī)自帶的權(quán)限管理功能或者第三方權(quán)限管理應(yīng)用略有不同。
3,對于 BluetoothAdapter.enable() 這個方法,API 中有以下說明 (備注:初始 API 中,如 Android 2.0 Eclair / API Level 5 中并沒有這段提示)
Bluetooth should never be enabled without direct user consent. If you want to turn on Bluetooth in order to create a wireless connection, you should use the ACTION_REQUEST_ENABLE Intent, which will raise a dialog that requests user permission to turn on Bluetooth. The enable() method is provided only for applications that include a user interface for changing system settings, such as a “power manager” app.
沒有直接的用戶的允許絕不要開啟 Bluetooth。如果你想要打開 Bluetooth 創(chuàng)建一個無線連接,你應(yīng)當(dāng)使用 ACTION_REQUEST_ENABLE Intent,這樣會彈出一個提示框提示用戶是否開啟 Bluetooth,enable() 方法僅提供給有 UI 、更改系統(tǒng)設(shè)置的應(yīng)用來使用,例如“電源管理”應(yīng)用。
從以上官方 API 提示可以看出:不建議你調(diào)用此方法來打開 Bluetooth,至少是在沒有任何用戶提醒的前提下!
調(diào)用系統(tǒng)彈出框提示用戶打開
- 注冊權(quán)限:
- 開啟方式:
對于以上彈出系統(tǒng)彈框提示用戶打開 Bluetooth 的代碼,有以下幾點需要注意:
1,這種調(diào)用系統(tǒng)的彈出框提示用戶打開 Bluetooth 的方式,一般不會受到系統(tǒng)或者第三方權(quán)限管理應(yīng)用的阻止。只有當(dāng)你不提示用戶的情況下,可以理解為“偷偷摸摸”的打開 Bluetooth ,這個是被認(rèn)為侵犯用戶的知情權(quán),系統(tǒng)或者第三方權(quán)限管理應(yīng)用可能加以阻止:直接禁止不提示用戶的情況下打開 Bluetooth,或者提示用戶,又或者是讓用戶自己選擇哪些應(yīng)用可以強(qiáng)制開啟 Bluetooth。而在 Nexus 5 / Android 4.4.4 原生系統(tǒng)強(qiáng)制打開 Bluetooth 是沒有任何提示,并且可以成功打開。
2,彈出系統(tǒng)的提示框提醒用戶打開 Bluetooth 的主要代碼:
this.startActivityForResult(requestBluetoothOn, REQUEST_CODE_BLUETOOTH_ON);
注意:這個方法是需要 Activity 的對象來調(diào)用的!并且需要在 Activity 中重寫 onActivityResult 方法來獲取用戶操作彈出提示框的結(jié)果!
3,這種彈出的系統(tǒng)彈框,根據(jù)系統(tǒng)的不同,UI 會有所不同。會導(dǎo)致用戶app視覺不統(tǒng)一。
跳轉(zhuǎn)到系統(tǒng)設(shè)置中讓用戶自己打開:
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));考慮到涉及用戶隱私和用戶體驗,推薦以下方式開啟 Bluetooth :
1,采用強(qiáng)制開啟 Bluetooth 的方式打開 Bluetooth ,但是調(diào)用強(qiáng)制開啟 Bluetooth 代碼之前,我們自己在應(yīng)用中提示用戶,我們的應(yīng)用需要開啟 Bluetooth ,讓用戶自己選擇是否開啟 Bluetooth 。自己在應(yīng)用中提示用戶我們需要開啟 Bluetooth 相對于彈出系統(tǒng)的提示框提示用戶當(dāng)前應(yīng)用需要開啟 Bluetooth 的優(yōu)勢在于我們可以控制提示的內(nèi)容和提示的方式以及 UI。
2,假若用戶選擇了開啟 Bluetooth,但是強(qiáng)制開啟 Bluetooth 失敗,比如系統(tǒng)自帶的權(quán)限管理禁止你的應(yīng)用開啟 Bluetooth ,我們不去提示用戶說當(dāng)前系統(tǒng)禁止了應(yīng)用開啟 Bluetooth,讓用戶自己去解除禁止。這樣顯然用戶體驗很差。這種情況下,我們再去調(diào)用彈出系統(tǒng)提示框提醒用戶打開 Bluetooth 即可。這種方式一般系統(tǒng)或者第三方應(yīng)用不會禁止。
3,如果彈出系統(tǒng)提示框提醒用戶打開 Bluetooth 有問題的話,最后采用提示用戶自己去系統(tǒng) Bluetooth 設(shè)置中打開 Bluetooth,跳轉(zhuǎn)到系統(tǒng)的 Bluetooth 設(shè)置界面。
PS:在目前Android手機(jī)中,是不支持在飛行模式下開啟藍(lán)牙的。如果藍(lán)牙已經(jīng)開啟,那么藍(lán)牙的開關(guān)狀態(tài)會隨著飛行模式的狀態(tài)而發(fā)生改變。
BLE廣播數(shù)據(jù)解析
轉(zhuǎn)載自BLE 廣播數(shù)據(jù)解析
BLE中peripheral設(shè)備處于被發(fā)現(xiàn)狀態(tài)時會發(fā)送廣播包,peripheral設(shè)備通過廣播被中心設(shè)備發(fā)現(xiàn),廣播中帶有peripheral設(shè)備自身的相關(guān)信息。
廣播包有兩種: 廣播包 (Advertising Data)和 響應(yīng)包 (Scan Response),其中廣播包是每個設(shè)備必須廣播的,而響應(yīng)包是可選的。 數(shù)據(jù)包的格式如下圖所示(圖片來自官方 Spec):
每個包都是 31 字節(jié),數(shù)據(jù)包中分為有效數(shù)據(jù)(significant)和無效數(shù)據(jù)(non-significant)兩部分。
- 有效數(shù)據(jù)部分 :包含若干個廣播數(shù)據(jù)單元,稱為 AD Structure 。如圖中所示,AD Structure 的組成是:第一個字節(jié)是長度值 Len ,表示接下來的 Len 個字節(jié)是數(shù)據(jù)部分。數(shù)據(jù)部分的第一個字節(jié)表示數(shù)據(jù)的類型 AD Type ,剩下的 Len - 1 個字節(jié)是真正的數(shù)據(jù) AD data 。其中 AD type 非常關(guān)鍵,決定了 AD Data 的數(shù)據(jù)代表的是什么和怎么解析,這個在后面會詳細(xì)講;
- 無效數(shù)據(jù)部分 :因為廣播包的長度必須是 31 個 byte,如果有效數(shù)據(jù)部分不到 31 自己,剩下的就用 0 補(bǔ)全。這部分的數(shù)據(jù)是無效的,解釋的時候,忽略即可。
AD type
所有的 AD type 的定義在文檔 Core Specification Supplement 中。 AD Type 包括如下類型:
-
Flags: TYPE = 0x01。這個數(shù)據(jù)用來標(biāo)識設(shè)備 LE 物理連接的功能。DATA 是 0 到多個字節(jié)的 Flag 值,每個 bit 上用 0 或者 1 來表示是否為 True。如果有任何一個 bit 不為 0,并且廣播包是可連接的,就必須包含此數(shù)據(jù)。各 bit 的定義如下:
- bit 0: LE 有限發(fā)現(xiàn)模式
- bit 1: LE 普通發(fā)現(xiàn)模式
- bit 2: 不支持 BR/EDR
- bit 3: 對 Same Device Capable(Controller) 同時支持 BLE 和 BR/EDR
- bit 4: 對 Same Device Capable(Host) 同時支持 BLE 和 BR/EDR
- bit 5…7: 預(yù)留
-
Service UUID: 廣播數(shù)據(jù)中一般都會把設(shè)備支持的 GATT Service 廣播出來,用來告訴外面本設(shè)備所支持的 Service。有三種類型的 UUID:16 bit, 32bit, 128 bit。廣播中,每種類型類型有有兩個類別:完整和非完整的。這樣就共有 6 種 AD Type。
- 非完整的 16 bit UUID 列表: TYPE = 0x02;
- 完整的 16 bit UUID 列表: TYPE = 0x03;
- 非完整的 32 bit UUID 列表: TYPE = 0x04;
- 完整的 32 bit UUID 列表: TYPE = 0x05;
- 非完整的 128 bit UUID 列表: TYPE = 0x06;
- 完整的 128 bit UUID 列表: TYPE = 0x07;
-
Local Name: 設(shè)備名字,DATA 是名字的字符串。 Local Name 可以是設(shè)備的全名,也可以是設(shè)備名字的縮寫,其中縮寫必須是全名的前面的若干字符。
- 設(shè)備全名: TYPE = 0x08
- 設(shè)備簡稱: TYPE = 0x09
-
TX Power Level: TYPE = 0x0A,表示設(shè)備發(fā)送廣播包的信號強(qiáng)度。DATA 部分是一個字節(jié),表示 -127 到 + 127 dBm。
-
帶外安全管理(Security Manager Out of Band):TYPE = 0x11。DATA 也是 Flag,每個 bit 表示一個功能:
- bit 0: OOB Flag,0 表示沒有 OOB 數(shù)據(jù),1 表示有
- bit 1: 支持 LE
- bit 2: 對 Same Device Capable(Host) 同時支持 BLE 和 BR/EDR
- bit 3: 地址類型,0 表示公開地址,1 表示隨機(jī)地址
-
外設(shè)(Slave)連接間隔范圍:TYPE = 0x12。數(shù)據(jù)中定義了 Slave 最大和最小連接間隔,數(shù)據(jù)包含 4 個字節(jié):
- 前 2 字節(jié):定義最小連接間隔,取值范圍:0x0006 ~ 0x0C80,而 0xFFFF 表示未定義;
- 后 2 字節(jié):定義最大連接間隔,同上,不過需要保證最大連接間隔大于或者等于最小連接間隔。
-
服務(wù)搜尋:外圍設(shè)備可以要請中心設(shè)備提供相應(yīng)的 Service。其數(shù)據(jù)定義和前面的 Service UUID 類似:
- 16 bit UUID 列表: TYPE = 0x14
- 32 bit UUID 列表: TYPE = 0x??
- 128 bit UUID 列表: TYPE = 0x15
-
Service Data: Service 對應(yīng)的數(shù)據(jù)。
- 16 bit UUID Service: TYPE = 0x16, 前 2 字節(jié)是 UUID,后面是 Service 的數(shù)據(jù);
- 32 bit UUID Service: TYPE = 0x??, 前 4 字節(jié)是 UUID,后面是 Service 的數(shù)據(jù);
- 128 bit UUID Service: TYPE = 0x??, 前 16 字節(jié)是 UUID,后面是 Service 的數(shù)據(jù);
-
公開目標(biāo)地址:TYPE = 0x17,表示希望這個廣播包被指定的目標(biāo)設(shè)備處理,此設(shè)備綁定了公開地址,DATA 是目標(biāo)地址列表,每個地址 6 字節(jié)。
-
隨機(jī)目標(biāo)地址:TYPE = 0x18,定義和前一個類似,表示希望這個廣播包被指定的目標(biāo)設(shè)備處理,此設(shè)備綁定了隨機(jī)地址,DATA 是目標(biāo)地址列表,每個地址 6 字節(jié)。
-
Appearance:TYPE = 0x19,DATA 是表示了設(shè)備的外觀。
-
廠商自定義數(shù)據(jù): TYPE = 0xFF,廠商自定義的數(shù)據(jù)中,前兩個字節(jié)表示廠商 ID,剩下的是廠商自己按照需求添加,里面的數(shù)據(jù)內(nèi)容自己定義。
還有一些其他的數(shù)據(jù),我這里就不一一列舉了,有需要的可以從這個文檔查閱 Core Specification Supplement 。
GATT
BLE技術(shù)是基于GATT進(jìn)行通信的,GATT是一種屬性傳輸協(xié)議,簡單的講可以認(rèn)為是一種屬性傳輸?shù)膽?yīng)用層協(xié)議。它的結(jié)構(gòu)非常簡單:
你可以把他看成xml來理解:
- 每個GATT由完成不同功能的Service組成;
- 每個Service由不同的Characteristic組成;
- 每個Characteristic由一個value和一個或者多個Descriptor組成;
Service、Characteristic相當(dāng)于標(biāo)簽(Service相當(dāng)于他的類別,Characteristic相當(dāng)于它的名字),而value才真正的包含數(shù)據(jù),Descriptor是對這個value進(jìn)行的說明和描述,當(dāng)然我們可以從不同角度來描述和說明,因此可以有多個Descriptor.
這樣子理解可能不夠準(zhǔn)確,下面我們來舉一個簡單的例子進(jìn)行說明:
常見的小米手環(huán)是一個BLE設(shè)備,(假設(shè))它包含三個Service,分別是提供設(shè)備信息的Service、提供步數(shù)的Service、檢測心率的Service;
而設(shè)備信息的service中包含的characteristic包括廠商信息、硬件信息、版本信息等;而心率Service則包括心率characteristic等,而心率characteristic中的value則真正的包含心率的數(shù)據(jù),而descriptor則是對該value的描述說明,比如value的單位啊,描述啊,權(quán)限啊等。
作者:小時不識月z
鏈接:https://www.jianshu.com/p/29a730795294
來源:簡書
簡書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處。
BluetoothAdapter類介紹
摘錄自Android中藍(lán)牙的基本使用----BluetoothAdapter類簡介
由于網(wǎng)絡(luò)上關(guān)于BluetoothAdapter的一些常用API函數(shù)都有了介紹,因此,我著重介紹一些BluetoothAdapter類疏忽的地方。
1,BluetoothAdapter STATE 狀態(tài)值 , 即開關(guān)狀態(tài)
int STATE_OFF 藍(lán)牙已經(jīng)關(guān)閉 int STATE_ON 藍(lán)牙已經(jīng)打開 int STATE_TURNING_OFF 藍(lán)牙處于關(guān)閉過程中 ,關(guān)閉ing int STATE_TURNING_O 藍(lán)牙處于打開過程中 ,打開ing2,BluetoothAdapter SCAN_MOD狀態(tài)值 ,即掃描狀態(tài)
首先說明,可以掃描其他設(shè)備的,當(dāng)然它同時能被其他藍(lán)牙設(shè)備掃碼。
int SCAN_MODE_CONNECTABLE 表明該藍(lán)牙可以掃描其他藍(lán)牙設(shè)備 int SCAN_MODE_CONNECTABLE_DISCOVERABLE 表明該藍(lán)牙設(shè)備同時可以掃碼其他藍(lán)牙設(shè)備,并且可以被其他藍(lán)牙設(shè)備掃描到。 int SCAN_MODE_NONE 該藍(lán)牙不能掃描以及被掃描。3,獲得藍(lán)牙適配器實例
public static synchronized BluetoothAdapter getDefaultAdapter () 功能:獲得本設(shè)備的藍(lán)牙適配器實例。 返回值:如果設(shè)備具備藍(lán)牙功能,返回BluetoothAdapter 實例;否則,返回null對象。4,掃描藍(lán)牙設(shè)備
public boolean startDiscovery () 功能: 掃描藍(lán)牙設(shè)備 注意: 如果藍(lán)牙沒有開啟,該方法會返回false,即不會開始掃描過程。public boolean cancelDiscovery () 功能: 取消掃描過程。 注意: 如果藍(lán)牙沒有開啟,該方法會返回false。public boolean isDiscovering () 功能: 是否正在處于掃描過程中。 注意: 如果藍(lán)牙沒有開啟,該方法會返回false。5,獲取藍(lán)牙相關(guān)信息
public String getName () 功能:獲取藍(lán)牙設(shè)備Namepublic String getAddress () 功能:獲取藍(lán)牙設(shè)備的硬件地址(MAC地址),例如:00:11:22:AA:BB:CC public boolean setName (String name) 功能:設(shè)置藍(lán)牙設(shè)備的Name,public Set<BluetoothDevice> getBondedDevices () 功能:獲取與本機(jī)藍(lán)牙所有綁定的遠(yuǎn)程藍(lán)牙信息,以BluetoothDevice類實例(稍后講到)返回。 注意:如果藍(lán)牙為開啟,該函數(shù)會返回一個空集合 。public static boolean checkBluetoothAddress (String address) 功能: 驗證藍(lán)牙設(shè)備MAC地址是否有效。所有設(shè)備地址的英文字母必須大寫,48位,形如:00:43:A8:23:10:F1 。 返回值: true 設(shè)備地址有效 false 設(shè)備地址無效public BluetoothDevice getRemoteDevice (String address) 功能:以給定的MAC地址去創(chuàng)建一個 BluetoothDevice 類實例(代表遠(yuǎn)程藍(lán)牙實例)。即使該藍(lán)牙地址不可見,也會產(chǎn)生一個BluetoothDevice 類實例。 返回:BluetoothDevice 類實例 。注意,如果該藍(lán)牙設(shè)備MAC地址不能被識別,其藍(lán)牙Name為null。 異常:如果MAC address無效,拋出IllegalArgumentException。Android Bluetooth Low Energy (BLE) Example
轉(zhuǎn)載自Android Bluetooth Low Energy (BLE) Example
Since BLE was introduced in API 18 and cannot be used on old devices, due to change of Bluetooth specifications. I suggest you to specify the min SDK version to 18 in your app. Next add these permissions and feature tags in the manifest tag of your app manifest:
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>Since I will be printing all the data in logs, there is no need for a layout file, lets have a look at the code for using Bluetooth low energy on Android:
package com.truiton.bleexample;import android.annotation.TargetApi; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.widget.Toast;import java.util.ArrayList; import java.util.List;@TargetApi(21) public class MainActivity extends ActionBarActivity {private BluetoothAdapter mBluetoothAdapter;private int REQUEST_ENABLE_BT = 1;private Handler mHandler;private static final long SCAN_PERIOD = 10000;private BluetoothLeScanner mLEScanner;private ScanSettings settings;private List<ScanFilter> filters;private BluetoothGatt mGatt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mHandler = new Handler();if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {Toast.makeText(this, "BLE Not Supported",Toast.LENGTH_SHORT).show();finish();}final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();}@Overrideprotected void onResume() {super.onResume();if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);} else {if (Build.VERSION.SDK_INT >= 21) {mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();filters = new ArrayList<ScanFilter>();}scanLeDevice(true);}}@Overrideprotected void onPause() {super.onPause();if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {scanLeDevice(false);}}@Overrideprotected void onDestroy() {if (mGatt == null) {return;}mGatt.close();mGatt = null;super.onDestroy();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_ENABLE_BT) {if (resultCode == Activity.RESULT_CANCELED) {//Bluetooth not enabled.finish();return;}}super.onActivityResult(requestCode, resultCode, data);}private void scanLeDevice(final boolean enable) {if (enable) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.stopLeScan(mLeScanCallback);} else {mLEScanner.stopScan(mScanCallback);}}}, SCAN_PERIOD);if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.startLeScan(mLeScanCallback);} else {mLEScanner.startScan(filters, settings, mScanCallback);}} else {if (Build.VERSION.SDK_INT < 21) {mBluetoothAdapter.stopLeScan(mLeScanCallback);} else {mLEScanner.stopScan(mScanCallback);}}}private ScanCallback mScanCallback = new ScanCallback() {@Overridepublic void onScanResult(int callbackType, ScanResult result) {Log.i("callbackType", String.valueOf(callbackType));Log.i("result", result.toString());BluetoothDevice btDevice = result.getDevice();connectToDevice(btDevice);}@Overridepublic void onBatchScanResults(List<ScanResult> results) {for (ScanResult sr : results) {Log.i("ScanResult - Results", sr.toString());}}@Overridepublic void onScanFailed(int errorCode) {Log.e("Scan Failed", "Error Code: " + errorCode);}};private BluetoothAdapter.LeScanCallback mLeScanCallback =new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {runOnUiThread(new Runnable() {@Overridepublic void run() {Log.i("onLeScan", device.toString());connectToDevice(device);}});}};public void connectToDevice(BluetoothDevice device) {if (mGatt == null) {mGatt = device.connectGatt(this, false, gattCallback);scanLeDevice(false);// will stop after first device detection}}private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {Log.i("onConnectionStateChange", "Status: " + status);switch (newState) {case BluetoothProfile.STATE_CONNECTED:Log.i("gattCallback", "STATE_CONNECTED");gatt.discoverServices();break;case BluetoothProfile.STATE_DISCONNECTED:Log.e("gattCallback", "STATE_DISCONNECTED");break;default:Log.e("gattCallback", "STATE_OTHER");}}@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {List<BluetoothGattService> services = gatt.getServices();Log.i("onServicesDiscovered", services.toString());gatt.readCharacteristic(services.get(1).getCharacteristics().get(0));}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristiccharacteristic, int status) {Log.i("onCharacteristicRead", characteristic.toString());gatt.disconnect();}}; }disconnect() 和close()的區(qū)別
在進(jìn)行BLE開發(fā)過程中可能會遇到操作失敗等情況,這個時候可能需要斷開與BLE的連接或者清理相關(guān)資源.在BluetoothGatt類中有兩個相關(guān)的方法 。
- disconnect()
- close()
那么這個兩個方法有什么區(qū)別,又該如何使用呢。
disconnect()方法:如果調(diào)用了該方法之后可以調(diào)用connect()方法進(jìn)行重連,這樣還可以繼續(xù)進(jìn)行斷開前的操作。
close()方法:一但調(diào)用了該方法, 如果你想再次連接,必須調(diào)用BluetoothDevice的connectGatt()方法。 因為close()方法將釋放BluetootheGatt的所有資源。
需要注意的問題:
當(dāng)你需要手動斷開時,調(diào)用disconnect()方法,此時斷開成功后會回調(diào)onConnectionStateChange方法,在這個方法中再調(diào)用close方法釋放資源。
如果在disconnect后立即調(diào)用close,會導(dǎo)致無法回調(diào)onConnectionStateChange方法。
常見問題:
BLE連接之后onServicesDiscovered不被調(diào)用
摘錄自ble連接之后onServicesDiscovered 不被調(diào)用
問題:onServicesDiscovered never called while connecting to GATT Server
Something that has been really useful for me is to wait for about 600ms after the connection has been established and then start the service discovery.
項目中出現(xiàn)藍(lán)牙連接上之后,始終不進(jìn)onServicesDiscovered回調(diào),mBluetoothGatt.discoverServices()做如下延時即可
if (newState == BluetoothProfile.STATE_CONNECTED) {intentAction = ACTION_GATT_CONNECTED;broadcastUpdate(intentAction);Log.i(TAG, "Connected to GATT server.");// Attempts to discover services after successful connection.//有時候發(fā)現(xiàn)服務(wù)不回調(diào),需延時 https://stackoverflow.com/questions/41434555/onservicesdiscovered-never-called-while-connecting-to-gatt-server#comment70285228_41526267try {Thread.sleep(600);Log.i(TAG, "Attempting to start service discovery:"+ mBluetoothGatt.discoverServices());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }相關(guān)資源:
Android低功耗藍(lán)牙的那點事兒
總結(jié)
以上是生活随笔為你收集整理的Android Bluetooth BLE相关开发资源汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ContextLoaderListene
- 下一篇: 时间跟踪图