藍牙BLE

前提說明:
去年有個項目是關于通過手機控制平衡車(小車)來實現加速檐薯、鎖車等一系列操作躬拢,其實就是通過藍牙來控制的窿侈,項目做了很長時間了,一直想把有關藍牙的這個模塊自己記錄下來方便自己查看鸽心,也算知識的一個積累吧滚局。
自己第一次接觸藍牙開發(fā)的項目,對藍牙這塊不太熟悉顽频,然后經過一番搜索找到的都是以下的藍牙開發(fā)藤肢,自己也開始做起來,以為很簡單糯景,直接上代碼了嘁圈。

步驟(不支持BLE):
1、搜索藍牙設備莺奸;
<pre>
// 1丑孩、獲取系統(tǒng)的藍牙適配器
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 2冀宴、搜索藍牙設備(搜索過程中會發(fā)出廣播灭贷,可以注冊廣播,從廣播中搜索到我們需要的設備)
bluetoothAdapter.startDiscovery();
</pre>

簡單說明:

  • bluetoothAdapter.startDiscovery():是異步方法略贮,它會對其他藍牙設備進行搜索甚疟,持續(xù)時間為12秒;
  • 搜索過程其實是在System Service中進行逃延,我們可以通過cancelDiscovery()方法來停止這個搜索览妖;
  • 在系統(tǒng)搜索藍牙設備的過程中,系統(tǒng)可能會發(fā)送以下三個廣播:
    ACTION_DISCOVERY_START(開始搜索)
    ACTION_DISCOVERY_FINISHED(搜索結束)
    ACTION_FOUND(找到設備)
  • ACTION_FOUND這個才是我們想要的揽祥,這個Intent中包含兩個extra fields:EXTRA_DEVICE讽膏、EXTRA_CLASS,包含的分別是BluetoothDevice和BluetoothClass拄丰,BluetoothDevice中的EXTRA_DEVICE就是我們搜索到的設備對象府树;確認搜索到設備后俐末,我們可以從得到的BluetoothDevice對象中獲得設備的名稱和地址;

2奄侠、獲取設備卓箫、配對、連接垄潮;
<pre>
// 3烹卒、注冊系統(tǒng)廣播,得到我們需要的設備
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
receiver = new BluetoothReceiver();
registerReceiver(receiver, filter);

// 廣播
private class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (isLock(device)) {
devices.add(device.getName());
}
deviceList.add(device);
}
showDevices();
}
}
// 4弯洗、獲取設備旅急,并配對(只有配對好之后才能連接)
// 在連接設備之前停掉搜索設備,否則連接可能會變得非常慢并且容易失敗
bluetoothAdapter.cancelDiscovery();</pre>
3涂召、連接后獲取輸入輸出流和藍牙設備進行通信坠非;
4、斷開連接果正、關閉藍牙炎码;
<pre>
這兩個步驟不說明,因為到這里我就發(fā)現問題了秋泳,
開發(fā)文檔上說明找到uuid潦闲,在通道上發(fā)送和接收命令,
我卻連個通道都沒有見到過迫皱,找了很久都是以上這樣的文章歉闰,
后來再從頭閱讀文檔,發(fā)現了藍牙BLE卓起,
呵呵~和敬,懵逼了吧,再重新去搜索戏阅,又是另一番景象了昼弟。
</pre>

藍牙BLE介紹(摘抄)

  • 在BLE協議中,有兩個角色奕筐,周邊(Periphery)和中央(Central)舱痘;
  • 周邊是數據提供者,中央是數據使用/處理者离赫;
  • 在Android SDK里面芭逝,在Android4.4.2,Android手機只能作為中央來使用和處理數據渊胸;那數據從哪兒來旬盯?從BLE設備來,現在的很多可穿戴設備都是用BLE來提供數據的。
  • 一個中央可以同時連接多個周邊胖翰,但是一個周邊某一時刻只能連接一個中央频丘。
藍牙BLE相關API:
  • BluetoothAdapter(系統(tǒng)默認藍牙適配器)
  • BluetoothManager(藍牙管理類)
  • BluetoothDevice
  • BluetoothGattServer作為周邊來提供數據、BluetoothGattServerCallback返回周邊的狀態(tài)泡态;
  • BluetoothGattService(服務):每一個周邊BluetoothGattServer搂漠,包含多個服務Service;
  • BluetoothGattCharacteristic(特征):每一個Service包含多個特征Characteristic某弦;
  • BluetoothGatt作為中央來使用和處理數據桐汤、BluetoothGattCallback返回中央的狀態(tài)和周邊提供的數據;

步驟
1靶壮、開啟手機藍牙怔毛、搜索設備、取消搜索設備和以上相同腾降;
2拣度、藍牙連接,發(fā)現服務螃壤、讀寫數據全部在回調里可以監(jiān)聽到:
<pre>
mBluetoothGatt = device.connectGatt(context, false, mGattCallback);

// 回調
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
final String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED)
{
intentAction = ACTION_GATT_CONNECTED;
// 開啟查找服務
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// 斷開連接
// Log.d(TAG, "Disconnected from GATT server.");
intentAction = ACTION_GATT_DISCONNECTED;
}
if (status == 133) { // 藍牙連接自動斷開的原因->需要清除所有的連接抗果,重連機制
// Log.e(TAG, "藍牙連接自動斷開,status=" + status);
close();
sleep();
connect(mBluetoothDeviceAddress);
}
}

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {

// Log.d(TAG, "onServicesDiscovered received: " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// 解析服務
displayGattServices(getSupportedGattServices());
}
}

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic,
                                     int status) {
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
    }

    @Override public void onCharacteristicWrite(BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic, int status) {
    }
};

</pre>

解析服務,因為我是在FFE0奸晴、FFE5通道上操作的冤馏,所以只需要找到這兩個通道即可:
<pre>
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) {
return;
}
for (BluetoothGattService gattService : gattServices) {
//-----Service的字段信息-----//
// Log.e(TAG,"-->service uuid:"+gattService.getUuid());

        String serviceUUID = gattService.getUuid().toString().toUpperCase();
        if (serviceUUID.contains(DefaultConstant.SERVICE_UUID_FFE0))
        {
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {

// Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid());
String charUUID = gattCharacteristic.getUuid().toString().toUpperCase();
if (charUUID.contains(DefaultConstant.CHAR_UUID_FFE4)) {
mCharacFFE4 = gattCharacteristic;
// 打開通道,只有打開了通道寄啼,才能在通道上進行讀和寫
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
break;
}
}
}
if (serviceUUID.contains(DefaultConstant.SERVICE_UUID_FFE5))
{
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
// Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid());
String charUUID = gattCharacteristic.getUuid().toString().toUpperCase();
if (charUUID.contains(DefaultConstant.CHAR_UUID_FFE9)) {
mCharacFFE9 = gattCharacteristic;
break;
}
}
}
if (mCharacFFE4 != null && mCharacFFE9 != null) {
break;
}
}

}

</pre>

實際的值如下所示:


實際打印的服務和特征值.png

3逮光、讀寫完成后記得關閉連接;

總結:最后總算順利的完成了項目的開發(fā)墩划,但是也還是遇到了很多的問題涕刚,這里自己做下記錄:

  • 某些手機不支持藍牙4.0設備,記得做事先的判斷乙帮;(一般4.3及以上手機才支持)
  • 搜索藍牙設備過程很緩慢杜漠,且項目要求一直都需要開啟搜索,但是我還是在連接成功后取消了搜索蚣旱,一個是為了加快藍牙的連接碑幅,一個也是為了省電戴陡,畢竟是很耗電的塞绿,既然已經連接了為啥還要一直在搜索呢;為了讓用戶視覺上覺得搜索很快恤批,記得搜索到一個設備就立即展示异吻,否則可能搜到你需要的設備會等很長時間,這樣也能起到緩沖作用;
  • 藍牙的連接诀浪,最好能對非BLE設備或者不是你需要的設備連接的時候做迅速的處理棋返,因為我試過,故意去連接某些電腦或者不知名設備的時候會有一個很長時間的響應雷猪,最后我自己處理是找到了BluetoothDevice的type


    bluetooth device type.png

    簡單的判斷了下睛竣,是否是BLE設備,直接斷開不去連接求摇;

  • 藍牙的連接射沟、讀寫過程我都是通過發(fā)送廣播進行處理,項目需要在所有頁面都能監(jiān)聽到設備的連接的狀態(tài)以及在某些頁面需要進行讀寫与境,干脆我改成了單例+廣播的形式验夯,這里要注意內存的泄漏哦;
  • 藍牙的斷開不徹底問題:斷開小車的時候總是斷開的不徹底摔刁,導致別人手機搜索不到挥转,自己也不能再去搜索連接,據說是小車有反應的時間共屈,經過多次測試后绑谣,發(fā)現每次斷開不徹底會返回133狀態(tài),至今沒弄明白拗引,只能這樣處理了域仇,表示很無奈,徹底關閉寺擂、沉睡500毫秒暇务,再次重連;


    徹底斷開處理.png

    或者再多加層判斷:


    徹底斷開重連處理.png
    總算起了一定的效果了怔软。垦细。。
  • 還漏寫了一個藍牙讀寫全是二進制數據挡逼,這里面的轉換也要注意括改,避免溢出;

好不容易鼓起自己去寫了家坎,一定會再接再勵嘱能,代碼自己會抽時間把之前寫在項目中的代碼抽離出來寫個demo放github上去,知識需要沉淀虱疏。

添加github demo地址惹骂,寫的較簡單,后續(xù)逐漸完善https://github.com/ywqian/BluetoothDemo做瞪;

參考和好的鏈接文章:
http://www.pinnace.cn/bluetooth/tech/1940.shtml
http://www.cnblogs.com/savagemorgan/p/3722657.html
一個不錯的github列子:https://github.com/alt236/Bluetooth-LE-Library---Android

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末对粪,一起剝皮案震驚了整個濱河市右冻,隨后出現的幾起案子,更是在濱河造成了極大的恐慌著拭,老刑警劉巖纱扭,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異儡遮,居然都是意外死亡乳蛾,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門鄙币,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屡久,“玉大人,你說我怎么就攤上這事爱榔”换罚” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵详幽,是天一觀的道長筛欢。 經常有香客問我,道長唇聘,這世上最難降的妖魔是什么版姑? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮迟郎,結果婚禮上剥险,老公的妹妹穿的比我還像新娘。我一直安慰自己宪肖,他們只是感情好表制,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著控乾,像睡著了一般么介。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜕衡,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天壤短,我揣著相機與錄音,去河邊找鬼慨仿。 笑死久脯,一個胖子當著我的面吹牛,可吹牛的內容都是我干的镰吆。 我是一名探鬼主播帘撰,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鼎姊!你這毒婦竟也來了骡和?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤相寇,失蹤者是張志新(化名)和其女友劉穎慰于,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體唤衫,經...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡婆赠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了佳励。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片休里。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赃承,靈堂內的尸體忽然破棺而出妙黍,到底是詐尸還是另有隱情辐啄,我是刑警寧澤砍的,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站浮入,受9級特大地震影響抓于,放射性物質發(fā)生泄漏做粤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一捉撮、第九天 我趴在偏房一處隱蔽的房頂上張望怕品。 院中可真熱鬧,春花似錦巾遭、人聲如沸肉康。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迎罗。三九已至,卻和暖如春片仿,著一層夾襖步出監(jiān)牢的瞬間纹安,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工砂豌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厢岂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓阳距,卻偏偏與公主長得像塔粒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筐摘,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內容