Android BLE低功耗藍牙開發(fā)極簡系列(一)之掃描與連接

背景

公司硬件模塊升級犹褒,由原本的單模式藍牙熙侍,換成現(xiàn)在的雙模藍牙搁廓。單模藍牙就是通過BlueTooth 2.0傳統(tǒng)藍牙進行音頻或者數(shù)據(jù)傳輸甸饱,雙模藍牙兼容傳統(tǒng)藍牙,可以和傳統(tǒng)藍牙通信撑碴,也可以和BLE通信撑教,谷歌在Android 4.3后開始支持BLE低功耗藍牙。

由來

公司使用的藍牙模塊醉拓,供應商那邊提供了相應的sdk驮履,在代碼測試和開發(fā)工程中,發(fā)現(xiàn)連接速度的穩(wěn)定性存在問題廉嚼,和其他公司的技術人員聯(lián)系,協(xié)商問題倒戏,應該是工作中費時費力的一件事怠噪,最后還不一定能夠得到解決。詢問過sdk那邊相關人員杜跷,說可以自己用系統(tǒng)的方法進行調(diào)試傍念。

BLE相關概念

UUID

Universally Unique Identifier ,唯一標示符葛闷,一般開發(fā)中會用到SERVICE憋槐、WRITE、NOTIFICATION等的UUID淑趾,需固件端配合修改阳仔。

Generic Attribute Profile (GATT)

GATT是用于發(fā)送和接收的通用規(guī)范,不同于傳統(tǒng)藍牙使用socket扣泊, BLE之間的文件數(shù)據(jù)傳輸基于GATT近范。GATT連接是一對一的,也就說一個BLE設備智能連接一個設備延蟹。一旦連接成功评矩,只有當連接斷開,否則其它設備無法連接當前設備的的阱飘。

Attribute Protocol (ATT)

GATT是建立在ATT的基礎上斥杜,ATT針對BLE設備進行了優(yōu)化虱颗,在傳輸中使用盡量少的數(shù)據(jù),每個屬性都有一個唯一的UUID蔗喂,屬性間的傳輸會以characteristics 和services的形式來進行傳輸忘渔。

Characteristic

Characteristic特征值,包含一個或者多個value,可以通過characteristic進行文件的讀寫操作弱恒。

Descriptor

用于描述特征值的屬性

Service

特征值得集合

開發(fā)

權限

進行藍牙相關操作辨萍,需要使用到藍牙權限,在AndroidManifest.xml清單文件中添加相應權限

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

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

在android6.0以后返弹,藍牙BLE還需要需要獲得位置權限

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

初始化藍牙Adapter

使用藍牙進行相關操作之前锈玉,需要先獲取藍牙適配器

  final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    if (bluetoothManager != null) {
    mBluetoothAdapter = bluetoothManager.getAdapter();
    }

判斷藍牙是否可用或者是否開啟,如果藍牙關閉义起,那么開啟藍牙

    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new   Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, 1);
    }

掃描

掃描過程中拉背,需要對掃描結果進行回調(diào),在onLeScan()方法中對掃描的結果進行相關處理

private BluetoothDevice mDevice;
final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {

        Log.d("haha", "onLeScan:  " + device.getName() + " : " + rssi);
        String name = device.getName();
        if (name != null) {
            deviceName.setText(name);
            if (name.equals("test_ble")) {
                mDevice = device;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);

            }
        }
    }

};

由于藍牙掃描耗時耗電默终,所以在進行掃描的時候椅棺,注意自定義一個合適的掃描時間,在實際的開發(fā)和項目應用過程中齐蔽,自己選擇合適的時間两疚。定義好藍牙掃描回調(diào),開始掃描藍牙含滴,掃描到想要的藍牙诱渤,就可以停止掃描

    private void scanLeDevice(final boolean enable) {
    if (enable) {
        // Stops scanning after a pre-defined scan period.
        // 預先定義停止藍牙掃描的時間(因為藍牙掃描需要消耗較多的電量)

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
        }, 30000);
        mScanning = true;
        // 定義一個回調(diào)接口供掃描結束處理
        mBluetoothAdapter.startLeScan(mLeScanCallback);
    } else {
        mScanning = false;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
    }
}

通過獲取的mBluetoothAdapter調(diào)用startLeScan()傳入mLeScanCallback參數(shù),即可進行藍牙掃描谈况。

BluetoothGattCallback實現(xiàn)

GATT是用于發(fā)送和接收的通用規(guī)范勺美, BLE之間的文件數(shù)據(jù)傳輸基于GATT,因此在進行連接之前碑韵,需要進行Gatt接口回調(diào)赡茸。

  private String TAG = "haha";
private boolean isServiceConnected;
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {


    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        Log.d("haha", "onConnectionStateChange: " + newState);

        if (status != BluetoothGatt.GATT_SUCCESS) {
            String err = "Cannot connect device with error status: " + status;
            // 當嘗試連接失敗的時候調(diào)用 disconnect 方法是不會引起這個方法回調(diào)的,所以這里
            //   直接回調(diào)就可以了祝闻。
            gatt.close();
            if (mBluetoothGatt != null) {
                mBluetoothGatt.disconnect();
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            if (mDevice != null) {
                mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
            }
            Log.e(TAG, err);
            return;
        }
        if (newState == BluetoothProfile.STATE_CONNECTED) {
      //當藍牙設備已經(jīng)接
      Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).show();
            Log.i("haha", "Attempting to start service discovery:" +

            Log.d("haha", "onConnectionStateChange: " + "連接成功");

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//當設備無法連接
            if (mBluetoothGatt != null) {
                mBluetoothGatt.disconnect();
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            gatt.close();
            if (mDevice != null) {
                mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
            }
        }
};

通過status對當前連接進行判斷占卧,當status != BluetoothGatt.GATT_SUCCESS時,可以進行Gatt的重置操作治筒,嘗試重連屉栓。當newState == BluetoothProfile.STATE_CONNECTED時,此時連接成功耸袜。

連接

當實現(xiàn)了Gatt連接回到之后友多,即可對Ble藍牙進行連接操作

    public void startConnect(View view) {
    if (mDevice != null) {
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }
        mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
    }
}

注意事項

BLE實現(xiàn)android 4.3以后google才提供了支持,所以Ble項目只可運行在API 18以上的手機堤框;Android 6.0以上域滥,Ble服務還需要定位權限纵柿,否則使用不了。不使用時启绰,還應注意對藍牙進行關閉或斷開操作昂儒,由于Ble連接屬于獨占操作,有設備連接上了委可,其它設備是無法進行任何操作的渊跋。

Github

喜歡或對你有幫助,可以關注或者點贊BleDemo
下一篇Android BLE低功耗藍牙開發(fā)極簡系列(二)之讀寫操作

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末着倾,一起剝皮案震驚了整個濱河市拾酝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卡者,老刑警劉巖蒿囤,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異崇决,居然都是意外死亡材诽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門恒傻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脸侥,“玉大人,你說我怎么就攤上這事盈厘∈。” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵扑庞,是天一觀的道長。 經(jīng)常有香客問我拒逮,道長罐氨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任滩援,我火速辦了婚禮栅隐,結果婚禮上,老公的妹妹穿的比我還像新娘玩徊。我一直安慰自己租悄,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布恩袱。 她就那樣靜靜地躺著泣棋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪畔塔。 梳的紋絲不亂的頭發(fā)上潭辈,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天鸯屿,我揣著相機與錄音,去河邊找鬼把敢。 笑死寄摆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的修赞。 我是一名探鬼主播婶恼,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼柏副!你這毒婦竟也來了勾邦?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤搓扯,失蹤者是張志新(化名)和其女友劉穎检痰,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锨推,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡铅歼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了换可。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椎椰。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沾鳄,靈堂內(nèi)的尸體忽然破棺而出慨飘,到底是詐尸還是另有隱情,我是刑警寧澤译荞,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布瓤的,位于F島的核電站,受9級特大地震影響吞歼,放射性物質(zhì)發(fā)生泄漏圈膏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一篙骡、第九天 我趴在偏房一處隱蔽的房頂上張望稽坤。 院中可真熱鬧,春花似錦糯俗、人聲如沸尿褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杖玲。三九已至,卻和暖如春淘正,著一層夾襖步出監(jiān)牢的瞬間天揖,已是汗流浹背夺欲。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留今膊,地道東北人些阅。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像斑唬,于是被迫代替她去往敵國和親市埋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

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