科技評論
目前的智能時代已經到來,智能穿戴,智能家居,一切都是智能的了,很幸運,我做的也是智能行業,所以發表點觀點也是可以的,以我見到的,所謂智能穿戴,智能家居,無非都是用手機中的軟件作爲媒介,把手機和智能設備聯繫到了一起,那麼聯繫到一起的方式就是我們很熟悉的藍牙了,或者是無線網,但是大多數都使用的是藍牙,包括很出色的Garmin智能手錶,手環,也是通過藍牙4.0讓手機軟件和手錶硬件進行通信的,所以我們能夠掌握藍牙的技能顯得格外重要,也並不是說他就是未來,誰也說不準,下一個替代者將會出現,但是目前好像還沒有發現,在智能行業裏,這就是必需品,但是據我估計,在未來5年內,不會有變動,藍牙也在繼續完善,傳輸效率更高了,總之優點還是很多的。智能讓生活變得很神奇,雖然我身處在這個行業裏,但是我也會感到很是神奇,列位,擦亮眼睛,讓我們一起來完爆它吧
效果演示
掃盲
- 藍牙有傳統藍牙(3.0以下)和低功耗藍牙(ble,又稱藍牙4.0)之分
- android手機必須系統版本4.3及以上才支持BLE API。低功耗藍牙較傳統藍牙, 傳輸速度更快,覆蓋範圍更廣,安全性更高,延遲更短,耗電極低等等優點,這也是爲什麼近年來智能穿戴的東西越來越多,越來越火
- 傳統藍牙與低功耗藍牙通信方式也有所不同,傳統的一般通過socket方式,而低功耗藍牙是通過Gatt協議來實現
- 低功耗藍牙也叫BLE
藍牙的組成
請先看一張圖
解釋:
BLE分爲三個部分Service、Characteristic、Descriptor,每個部分都擁有不同的 UUID來標識。一個BLE設備可以擁有多個Service,一個Service可以包含多個Characteristic, 一個Characteristic包含一個Value和多個Descriptor,一個Descriptor包含一個Value。 通信數據一般存儲在Characteristic內,目前一個Characteristic中存儲的數據最大爲20 byte。 與Characteristic相關的權限字段主要有READ、WRITE、WRITE_NO_RESPONSE、NOTIFY。 Characteristic具有的權限屬性可以有一個或者多個。
介紹完了我們就開始看如何開發藍牙4.0和開發流程
開發步驟
1. 檢查該設備是否支持BLE設備
檢查該設備是否支持BLE設備,谷歌在Android4.3纔開始支持BLE設備
//第一步 檢查設備時候支持BLE
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "請注意,您的手機不支持BLE", Toast.LENGTH_SHORT).show();
}
2. 拿到藍牙管理器
一個Android系統只有一個BluetoothAdapter
//第二步 拿到藍牙管理器
manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = manager.getAdapter();
3. 打開藍牙
//檢查藍牙是否已打開 如未打開 則打開藍牙
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();
}
4. 掃描藍牙
注意:掃描藍牙是比較耗資源的,所以掃描一段時間後應該及時關閉掃描
//10秒鐘後停止掃描,掃描藍牙設備是很費資源的
mhandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
bluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, 10000);
mScanning = true;
//需要參數 BluetoothAdapter.LeScanCallback(返回的掃描結果)
bluetoothAdapter.startLeScan(mLeScanCallback);
5. 實現掃描結果的回調
在第4步的時候在開始掃描的bluetoothAdapter.startLeScan(mLeScanCallback)
中的mLeScanCallback,就是我們要實現的回調BluetoothAdapter.LeScanCallback,掃描的所有結果都會出現在回調裏
/**
* 藍牙掃面結果的回調
*/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
if (bluetoothDevice != null && bluetoothDevice.getName() != null) {
mData.add(bluetoothDevice);
runOnUiThread(new Runnable() {
@Override
public void run() {
//將掃描的到的bluetoothDevice添加到集合中 展示出來
ListAdapter = new MyAdapter(mData);
listview.setAdapter(ListAdapter);
}
});
} else {
ToastUtil.showToast("沒有獲取到設備信息",MainActivity.this);
}
}
};
6. 連接藍牙
連接時應關閉掃描,連接是通過獲取到設備的mac地址進行連接的
//停止掃描
if (mScanning) {
bluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
//通過藍牙設備地址 獲取遠程設備 開始連接
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(mData.get(i).getAddress());
//第二個參數 是否要自動連接
mBluetoothGatt = device.connectGatt(MainActivity.this, false, mBluetoothGattCallback);
7. 實現連接成功或者失敗狀態的回調
點擊要連接的設備之後都會調用用BluetoothGattCallback
回調,在這裏我定義的是mBluetoothGattCallback
,然後在實現回調裏的onConnectionStateChange
方法,系統會自動調用此方法
private BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
/**
* 藍牙連接狀態改變後調用 此回調 (斷開,連接)
* @param gatt
* @param status
* @param newState
*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
LogUtil.fussenLog().d("10086" + "===newState===" + newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {//連接成功
Message message = new Message();
message.what = CONNECT_SUCCESS;
mhandler.sendMessage(message);
//連接成功後去發現該連接的設備的服務
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//連接失敗 或者連接斷開都會調用此方法
Message message = new Message();
message.what = CONNECT_FIAL;
mhandler.sendMessage(message);
}
}
}
8. 連接成功後發現設備的所有服務
連接成功後緊接着就得去發現連接設備中的所有服務Service,爲什麼要發現服務?看下前面的第一張圖你就明白了,繼續實現BluetoothGattCallback
中的onServicesDiscovered
方法,因爲系統會自動調用此方法
/**
* 連接成功後發現設備服務後調用此方法
* @param gatt
* @param status
*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
LogUtil.fussenLog().d("10086" + "===搜到服務===");
if (status == BluetoothGatt.GATT_SUCCESS) {//發現該設備的服務
//拿到該服務 1,通過UUID拿到指定的服務 2,可以拿到該設備上所有服務的集合
List<BluetoothGattService> serviceList = mBluetoothGatt.getServices();
//可以遍歷獲得該設備上的服務集合,通過服務可以拿到該服務的UUID,和該服務裏的所有屬性Characteristic
for (int x = 0; x < serviceList.size(); x++) {
services.add(serviceList.get(x));
}
Message message = new Message();
message.what = FIND_SERVICE;
mhandler.sendMessage(message);
} else {//未發現該設備的服務
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.showToast("未發現服務", MainActivity.this);
}
});
}
}
9. 向藍牙設備發送數據
連接成功之後,我們總不能什麼都不做吧,要做的就是和設備通信啊,也就是向設備發送數據嘍,一般數據都會寫在藍牙設備的某個服務中的一個特徵中,然後發送出去,當然這還得具體看廠家的藍牙協議
//1.準備數據
byte[] data = new byte[6];
data[0] = 0x55;
data[1] = (byte) 0xAA;
data[2] = 0x00;
data[3] = 0x03;
data[4] = 0x02;
data[5] = (byte) 0xFB;
//2.通過指定的UUID拿到設備中的服務也可使用在發現服務回調中保存的服務
BluetoothGattService bluetoothGattService = services.get(0);
//3.通過指定的UUID拿到設備中的服務中的characteristic,也可以使用在發現服務回調中通過遍歷服務中信息保存的Characteristic
BluetoothGattCharacteristic gattCharacteristic = bluetoothGattService.getCharacteristic(UUID1);
//4.將byte數據設置到特徵Characteristic中去
gattCharacteristic.setValue(data);
//5.將設置好的特徵發送出去
mBluetoothGatt.writeCharacteristic(gattCharacteristic);
一般硬件裏讀出寫入的數據爲二進制類型,所以要熟悉整型,字符串,二進制,十六進制等它們之間的轉換,這些我會在藍牙進階裏再展開,還有如何不停的寫數據和讀取數據,一併會在藍牙進階中給出最佳方案
10. 發送數據後的回調
藍牙採用的是一應一答的模式,就是說,你給他發送了一個數據,不管你是發送失敗還是成功,藍牙都會給你應答一下,我們暫且這樣理解,我們肯定也是希望我們自己能夠監視自己到底有沒有把數據發送出去,那麼此時就應該重寫BluetoothGattCallback
中的onCharacteristicWrite
方法
/**
* Characteristic數據發送後調用此方法
* @param gatt
* @param characteristic
* @param status
*/
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {//寫入成功
Message message = new Message();
message.what = SEND_DATA_SUCCESS;
mhandler.sendMessage(message);
} else if (status == BluetoothGatt.GATT_FAILURE) {//寫入失敗
Message message = new Message();
message.what = SEND_DATA_FAIL;
mhandler.sendMessage(message);
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {// 沒有寫入的權限
}
}
需要注意的是,藍牙採用的是一應一答模式,也就是說,只要你對他做了操作之後,那麼藍牙設備都會響應你,就拿寫入數據來說,只有當第一條數據寫入完畢之後,才能寫入第二條數據,換句話說,只有當這個回調中的onCharacteristicWrite方法執行完之後,才能繼續寫入數據,具體我們如何知道藍牙什麼時候響應和在什麼地方響應,那麼此時BluetoothGattCallback
就顯得尤爲重要,藍牙設備的所有響應都會在BluetoothGattCallback
回調,並且執行相應的方法,下面我們就給出BluetoothGattCallback
的解釋和說明
11. BluetoothGattCallback
BluetoothGattCallback一共有9個方法,那麼只有當你調用或者和連接的設備發生互動的時候,他的與之對應的方法纔會回調,下面就是方法的對應
notification對應onCharacteristicChanged;
gatt.setCharacteristicNotification(characteristic, true);readCharacteristic對應onCharacteristicRead;
gatt.readCharacteristic(characteristic);writeCharacteristic對應onCharacteristicWrite;
gatt.wirteCharacteristic(mCurrentcharacteristic);連接藍牙或者斷開藍牙 對應 onConnectionStateChange;
readDescriptor對應onDescriptorRead;
writeDescriptor對應onDescriptorWrite;
gatt.writeDescriptor(descriptor);readRemoteRssi對應onReadRemoteRssi;
gatt.readRemoteRssi()executeReliableWrite對應onReliableWriteCompleted;
discoverServices對應onServicesDiscovered。
gatt.discoverServices()。