深入了解Android藍(lán)牙Bluetooth——《進(jìn)階篇》

深入了解Android藍(lán)牙Bluetooth——《基礎(chǔ)篇》一篇中我們對藍(lán)牙的各個版本的有了一個認(rèn)識杭隙,藍(lán)牙版本的歷程及其優(yōu)劣式介紹。那么接下來咱們就深入一點繼續(xù)開車進(jìn)入BLE的進(jìn)及篇章揽思。

藍(lán)牙BLE4.x

BLE分為三部分:

  • Service

  • Characteristic

  • Descriptor

    這三部分都用UUID作為唯一標(biāo)識符苍苞。UUID為這種格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3個Service,那么就有三個不同的UUID與Service對應(yīng)座泳。這些UUID都寫在硬件里,我們通過BLE提供的API可以讀取到幕与。

  • 一個BLE終端可以包含多個Service钳榨, 一個Service可以包含多個Characteristic,一個Characteristic包含一個value和多個Descriptor纽门,一個Descriptor包含一個Value薛耻。Characteristic是比較重要的,是手機(jī)與BLE終端交換數(shù)據(jù)的關(guān)鍵赏陵,讀取設(shè)置數(shù)據(jù)等操作都是操作Characteristic的相關(guān)屬性饼齿。

API相關(guān)介紹

  • 1.先介紹一下關(guān)于藍(lán)牙4.0中的一些名詞吧:
    (1)GATT(Gneric Attibute Profile)

    通過ble連接,讀寫屬性類小數(shù)據(jù)Profile通用的規(guī)范◎Γ現(xiàn)在所有的ble應(yīng)用Profile 都是基于GATT

    • (2)ATT(Attribute Protocal) GATT是基于ATT Potocal的ATT針對BLE設(shè)備專門做的具體就是傳輸過程中使用盡量少的數(shù)據(jù)缕溉,每個屬性都有個唯一的UUID,屬性chartcteristics and Service的形式傳輸吃型。
    • (3)Service是Characteristic的集合证鸥。
    • (4).Characteristic 特征類型。

    比如勤晚。有個藍(lán)牙ble的血壓計枉层。他可能包括多個Servvice,每個Service有包括多個Characteristic

    注意:藍(lán)牙ble只能支持Android 4.3以上的系統(tǒng) SDK>=18

  • 2.以下是開發(fā)的步驟:

  • 2.1首先獲取BluetoothManager

  • 2.2獲取BluetoothAdapter

  • 2.3創(chuàng)建BluetoothAdapter.LeScanCallback

  • 2.4.開始搜索設(shè)備赐写。

  • 2.5.BluetoothDevice 描述了一個藍(lán)牙設(shè)備 提供了getAddress()設(shè)備Mac地址,getName()設(shè)備的名稱鸟蜡。

  • 2.6開始連接設(shè)備

  • 2.7連接到設(shè)備之后獲取設(shè)備的服務(wù)(Service)和服務(wù)對應(yīng)的Characteristic。

  • 2.8獲取到特征之后挺邀,找到服務(wù)中可以向下位機(jī)寫指令的特征揉忘,向該特征寫入指令跳座。

  • 2.9寫入成功之后,開始讀取設(shè)備返回來的數(shù)據(jù)泣矛。

  • 2.10疲眷、斷開連接

  • 2.11、數(shù)據(jù)的轉(zhuǎn)換方法

大概整體就是如上的步驟您朽。但是也是要具體根據(jù)廠家的協(xié)議來實現(xiàn)通信的過程咪橙。

那么具體要怎么使用呢?我們據(jù)需開車往下走虚倒。

一.添加權(quán)限

和經(jīng)典藍(lán)牙一樣美侦,應(yīng)用使用藍(lán)牙,需要聲明BLUETOOTH權(quán)限魂奥,如果需要掃描設(shè)備或者操作藍(lán)牙設(shè)置菠剩,則還需要BLUETOOTH_ADMIN權(quán)限:

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

除了藍(lán)牙權(quán)限外,如果需要BLE feature則還需要聲明uses-feature:

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

按時required為true時耻煤,則應(yīng)用只能在支持BLE的Android設(shè)備上安裝運(yùn)行具壮;required為false時,Android設(shè)備均可正常安裝運(yùn)行哈蝇,需要在代碼運(yùn)行時判斷設(shè)備是否支持BLE feature:

// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
    finish();
}

第一步:開啟藍(lán)牙:

  • 1.首先獲取有BluetoothAdapter兩種方式:
private BluetoothManager bluetoothManager;

bluetoothManager =   (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

或者是:

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

兩行方式都是可以的棺妓。

注:這里通過getSystemService獲取BluetoothManager,再通過BluetoothManager獲取BluetoothAdapter炮赦。BluetoothManager在Android4.3以上支持(API level 18)怜跑。

  • 2.判斷手機(jī)設(shè)備是否有藍(lán)牙模塊
// 檢查設(shè)備上是否支持藍(lán)牙
        if (mBluetoothAdapter == null) {
            showToast("沒有發(fā)現(xiàn)藍(lán)牙模塊");
            return;
        }
  • 3.開啟藍(lán)牙設(shè)備

    開啟藍(lán)牙設(shè)備有兩種方式:

    • 第一種直接簡單暴力不給用戶進(jìn)行提示:
if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
}
*   第二種直優(yōu)雅的踐行開啟并且有彈框進(jìn)行提示,隱式啟動Intent:
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
  • 4.掃描藍(lán)牙設(shè)備

    我這里是把掃描到的BLE地址存放到List集合中去吠勘。這里我們可以寫一個方法進(jìn)行封裝一下性芬。

/***********
     * 掃描設(shè)備
     ********/
    private void scanLeDevice(final boolean enable) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            if (enable) {
                devices.clear();//清空集合
                // Stops scanning after a pre-defined scan period.
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                            mBluetoothAdapter.stopLeScan(mLeScanCallback);
                        }
                    }
                }, INTERVAL_TIME);
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                try {
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                } catch (Exception e) {
                }
            }
        }
    }

在這個掃描方法中,我們在AndroidStudio或者是Eclipse中會看到startLeScan方法會有橫線剧防,表明這個方式顯示過期的方法植锉,那么

如果你只需要搜索指定UUID的外設(shè),你可以調(diào)用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法峭拘。 其中UUID數(shù)組指定你的應(yīng)用程序所支持的GATT Services的UUID俊庇。

那么LeScanCallback的初始化代碼如下:

private void initCallBack(){
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (device != null) {
                                if (!TextUtils.isEmpty(device.getName())) {
                                   // devices.add(device);
                                    String name = device.getName();
                                    if (name.contains(BluetoothDeviceAttr.OYGEN_DEVICE_NAME)) {
                                        if (!devices.contains(device)) {
                                            devices.add(device);
                                        }
                                    }
                                }
                            }
                        }
                    });
                }
            };
        } else {
            getToast("設(shè)備藍(lán)牙版本過低");
            return;
        }
}

那么如果在設(shè)備多的情況下我們講搜出很多的設(shè)備。我們可以選擇我們所需要的地址進(jìn)行鏈接鸡挠。但是這類要注意的是:搜索時辉饱,你只能搜索傳統(tǒng)藍(lán)牙設(shè)備或者BLE設(shè)備,兩者完全獨(dú)立宵凌,不可同時被搜索.

  • 5.進(jìn)行鏈接設(shè)備
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        // We want to directly connect to the device, so we are setting the autoConnect
        // parameter to false.
        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

這里調(diào)用的是device的connectGatt方法

/**
     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
     * The callback is used to deliver results to Caller, such as connection status as well
     * as any further GATT client operations.
     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
     * GATT client operations.
     * @param callback GATT callback handler that will receive asynchronous callbacks.
     * @param autoConnect Whether to directly connect to the remote device (false)
     *                    or to automatically connect as soon as the remote
     *                    device becomes available (true).
     * @throws IllegalArgumentException if callback is null
     */
    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
                                     BluetoothGattCallback callback) {
        return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
    }

api中闡述的是第一個參數(shù)是上下文對象Context鞋囊,第二個參數(shù)是是否自動連接,第三個是藍(lán)牙的GattCallback回調(diào)瞎惫。

private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
    // 這里有9個要實現(xiàn)的方法溜腐,看情況要實現(xiàn)那些,用到那些就實現(xiàn)那些
    //當(dāng)連接狀態(tài)發(fā)生改變的時候
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){
        
    };
    //回調(diào)響應(yīng)特征寫操作的結(jié)果瓜喇。
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
        
    };
    //回調(diào)響應(yīng)特征讀操作的結(jié)果挺益。
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    }
    //當(dāng)服務(wù)被發(fā)現(xiàn)的時候回調(diào)的結(jié)果
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    }
    當(dāng)連接能被被讀的操作
    @Override
   public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            
            super.onDescriptorRead(gatt, descriptor, status);
      }  
    ......
};

連接的過程我們一個通過service來進(jìn)行連接,也可以在activity中進(jìn)行操作乘寒。 好望众,到此為止,一個BLE藍(lán)牙連接設(shè)備的整個流程我們已經(jīng)清楚完畢伞辛。

Android4.x的藍(lán)牙不太成熟性

但是在實際操作過程中難免會出現(xiàn)一些比較坑人的問題烂翰。比如我用一個地址進(jìn)行藍(lán)牙設(shè)備連接,偶爾會出現(xiàn)藍(lán)牙連接不上或者是說連接上設(shè)備后不返回數(shù)據(jù)等問題蚤氏。那么此時我們可能會重啟一下藍(lán)牙或手機(jī)就立馬有成功了甘耿。此時我們千萬不能蒙蔽,也不要懷疑自己的人生竿滨。這是因為Android4.x的藍(lán)牙還是不太成熟佳恬。目前可以來說是個測試階段。

  • 手機(jī)可能會搜索不到藍(lán)牙設(shè)備
  • 有時候會在廣播中接收不到數(shù)據(jù)
  • 出現(xiàn)異常需要重新啟動手機(jī)或者是重啟才能恢復(fù)正常

這個時候我們怎么辦呢于游?

此時不要抱怨什么毁葱,難到我們作為Android程序員就注定如此的苦逼嗎?

答案是否定的贰剥。

如何去優(yōu)化呢倾剿?那么我們就應(yīng)該從UI界面,用戶體驗上進(jìn)行操作來實現(xiàn)

  • 做一個定時器蚌成,如果在在確定藍(lán)牙設(shè)備一打開并且存在的情況系柱告,可以在手機(jī)搜索5s內(nèi)沒有搜索到藍(lán)牙設(shè)備時重啟藍(lán)牙,并且在廣播中接收到藍(lán)牙開啟后再次搜索

  • 可以在UI上進(jìn)行對用戶進(jìn)行相對應(yīng)的提示

    • 當(dāng)藍(lán)牙為啟動時笑陈,提示用戶去開啟器藍(lán)牙
    • 當(dāng)藍(lán)牙開啟后际度,在處在開啟狀態(tài)后,提示用戶藍(lán)牙正在開啟...
    • 藍(lán)牙已開啟涵妥,設(shè)備并沒有連接上乖菱,提示用戶去進(jìn)行連接
    • 設(shè)備正在連接上手機(jī),提示用戶蓬网,正在連接窒所,請等待...
    • 藍(lán)牙設(shè)備連接上手機(jī),正在讀取帆锋,提示數(shù)據(jù)正在讀取中...

    我們不能子在Android系統(tǒng)上來操作什么吵取,我們在體驗上做到了我們能做的就可以的。

手機(jī)藍(lán)牙連接BLE設(shè)備要求

  • 手機(jī)Android 4.3以上的系統(tǒng) SDK>=18
  • 藍(lán)牙版本>=4.0

學(xué)習(xí)參考道demo下載地址: https://github.com/androidstarjack/Bluetooth_4.3-master

學(xué)到這里锯厢,關(guān)于AndroidBLE藍(lán)牙連接我們已經(jīng)基本上實現(xiàn)了藍(lán)牙的搜索皮官,連接脯倒,讀取等。

大家項目中如果經(jīng)常涉及到硬件比如手環(huán)捺氢,溫度計藻丢,汗液儀,心電圖摄乒,血壓計等這些ble的藍(lán)牙設(shè)備悠反,就一定會用到藍(lán)相關(guān)方面的知識。這里筆者先給大家提前踩一下坑馍佑,進(jìn)行了總結(jié)斋否,為后面的小伙伴在研究藍(lán)牙方面盡量的少踩一些坑。如多對藍(lán)牙的歷程還未有清楚的認(rèn)識拭荤,請參考深入了解Android藍(lán)牙Bluetooth4.0——《基礎(chǔ)篇》茵臭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市穷劈,隨后出現(xiàn)的幾起案子笼恰,更是在濱河造成了極大的恐慌,老刑警劉巖歇终,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件社证,死亡現(xiàn)場離奇詭異,居然都是意外死亡评凝,警方通過查閱死者的電腦和手機(jī)追葡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奕短,“玉大人宜肉,你說我怎么就攤上這事◆岜” “怎么了谬返?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長日杈。 經(jīng)常有香客問我遣铝,道長,這世上最難降的妖魔是什么莉擒? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任酿炸,我火速辦了婚禮,結(jié)果婚禮上涨冀,老公的妹妹穿的比我還像新娘填硕。我一直安慰自己,他們只是感情好鹿鳖,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布扁眯。 她就那樣靜靜地躺著壮莹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恋拍。 梳的紋絲不亂的頭發(fā)上垛孔,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天藕甩,我揣著相機(jī)與錄音施敢,去河邊找鬼。 笑死狭莱,一個胖子當(dāng)著我的面吹牛僵娃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腋妙,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼默怨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了骤素?” 一聲冷哼從身側(cè)響起匙睹,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎济竹,沒想到半個月后痕檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡送浊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年梦谜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袭景。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡唁桩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耸棒,到底是詐尸還是另有隱情荒澡,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布与殃,位于F島的核電站单山,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奈籽。R本人自食惡果不足惜饥侵,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望衣屏。 院中可真熱鬧躏升,春花似錦、人聲如沸狼忱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佃却,卻和暖如春者吁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饲帅。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工复凳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灶泵。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓育八,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赦邻。 傳聞我的和親對象是個殘疾皇子髓棋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容