Android藍芽4.0(ble)開發的解決方案
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/u010046908/article/details/50614888
最近,隨著智慧穿戴式裝置、智慧醫療以及智慧家居的普及,藍芽開發在移動開中顯得非常的重要。由於公司需要,研究了一下,藍芽4.0在Android中的應用。以下是我的一些總結。
1.先介紹一下關於藍芽4.0中的一些名詞吧:
(1)GATT(Gneric Attibute Profile)
通過ble連線,讀寫屬性類小資料Profile通用的規範。現在所有的ble應用Profile 都是基於GATT
(2)ATT(Attribute Protocal)
GATT是基於ATT Potocal的ATT針對BLE裝置專門做的具體就是傳輸過程中使用盡量少的資料,每個屬性都有個唯一的UUID,屬性chartcteristics and Service的形式傳輸。
(3)Service是Characteristic的集合。
(4).Characteristic 特徵型別。
比如。有個藍芽ble的血壓計。他可能包括多個Servvice,每個Service有包括多個Characteristic
注意:藍芽ble只能支援Android 4.3以上的系統 SDK>=18
2.以下是開發的步驟:
2.1首先獲取BluetoothManager
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
2.2獲取BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
2.3建立BluetoothAdapter.LeScanCallback
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
String struuid = NumberUtils.bytes2HexString(NumberUtils.reverseBytes(scanRecord)).replace("-", "").toLowerCase();
if (device!=null && struuid.contains(DEVICE_UUID_PREFIX.toLowerCase())) {
mBluetoothDevices.add(device);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
2.4.開始搜尋裝置。
mBluetoothAdapter.startLeScan(mLeScanCallback);
2.5.BluetoothDevice 描述了一個藍芽裝置 提供了getAddress()裝置Mac地址,getName()裝置的名稱。
2.6開始連線裝置
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* @param address
* The device address of the destination device.
*
* @return Return true if the connection is initiated successfully. The
* connection result is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect. (先前連線的裝置。 嘗試重新連線)
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
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);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
2.7連線到裝置之後獲取裝置的服務(Service)和服務對應的Characteristic。
// Demonstrates how to iterate through the supported GATT
// Services/Characteristics.
// In this sample, we populate the data structure that is bound to the
// ExpandableListView
// on the UI.
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null)
return;
String uuid = null;
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<>();
mGattCharacteristics = new ArrayList<>();
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap<>();
uuid = gattService.getUuid().toString();
if (uuid.contains("ba11f08c-5f14-0b0d-1080")) {//服務的uuid
//System.out.println("this gattService UUID is:" + gattService.getUuid().toString());
currentServiceData.put(LIST_NAME, "Service_OX100");
currentServiceData.put(LIST_UUID, uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<>();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<>();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<>();
uuid = gattCharacteristic.getUuid().toString();
if (uuid.toLowerCase().contains("cd01")) {
currentCharaData.put(LIST_NAME, "cd01");
} else if (uuid.toLowerCase().contains("cd02")) {
currentCharaData.put(LIST_NAME, "cd02");
} else if (uuid.toLowerCase().contains("cd03")) {
currentCharaData.put(LIST_NAME, "cd03");
} else if (uuid.toLowerCase().contains("cd04")) {
currentCharaData.put(LIST_NAME, "cd04");
} else {
currentCharaData.put(LIST_NAME, "write");
}
currentCharaData.put(LIST_UUID, uuid);
gattCharacteristicGroupData.add(currentCharaData);
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
mCharacteristicCD01 = gattService.getCharacteristic(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD02 = gattService.getCharacteristic(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD03 = gattService.getCharacteristic(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD04 = gattService.getCharacteristic(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"));
mCharacteristicWrite = gattService.getCharacteristic(UUID.fromString("0000cd20-0000-1000-8000-00805f9b34fb"));
//System.out.println("=======================Set Notification==========================");
// 開始順序監聽,第一個:CD01
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD01, true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD02, true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD03, true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD04, true);
}
}
}
2.8獲取到特徵之後,找到服務中可以向下位機寫指令的特徵,向該特徵寫入指令。
public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.writeCharacteristic(characteristic);
}
2.9寫入成功之後,開始讀取裝置返回來的資料。
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
//System.out.println("=======status:" + status);
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
//從特徵中讀取資料
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//System.out.println("onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//向特徵中寫入資料
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//System.out.println("--------write success----- status:" + status);
}
/*
* when connected successfully will callback this method this method can
* dealwith send password or data analyze
*當連線成功將回撥該方法
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
if (characteristic.getValue() != null) {
//System.out.println(characteristic.getStringValue(0));
}
//System.out.println("--------onCharacteristicChanged-----");
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
//System.out.println("onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + descriptor.getUuid().toString());
UUID uuid = descriptor.getCharacteristic().getUuid();
if (uuid.equals(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"))) {
broadcastUpdate(ACTION_CD01NOTIDIED);
} else if (uuid.equals(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"))) {
broadcastUpdate(ACTION_CD02NOTIDIED);
} else if (uuid.equals(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"))) {
broadcastUpdate(ACTION_CD03NOTIDIED);
} else if (uuid.equals(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"))) {
broadcastUpdate(ACTION_CD04NOTIDIED);
}
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//System.out.println("rssi = " + rssi);
}
};
----------------------------------------------
//從特徵中讀取資料
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//System.out.println("onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
2.10、斷開連線
/**
* Disconnects an existing connection or cancel a pending connection. The
* disconnection result is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
2.11、資料的轉換方法
// byte轉十六進位制字串
public static String bytes2HexString(byte[] bytes) {
String ret = "";
for (byte aByte : bytes) {
String hex = Integer.toHexString(aByte & 0xFF);
if (hex.length() == 1) {
hex = `0` + hex;
}
ret += hex.toUpperCase(Locale.CHINA);
}
return ret;
}
/**
* 將16進位制的字串轉換為位元組陣列
*
* @param message
* @return 位元組陣列
*/
public static byte[] getHexBytes(String message) {
int len = message.length() / 2;
char[] chars = message.toCharArray();
String[] hexStr = new String[len];
byte[] bytes = new byte[len];
for (int i = 0, j = 0; j < len; i += 2, j++) {
hexStr[j] = "" + chars[i] + chars[i + 1];
bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
}
return bytes;
}
大概整體就是如上的步驟。但是也是要具體根據廠家的協議來實現通訊的過程。
就那一個我們專案中的demo說一下。
一個藍芽ble的血壓計。 上位機—手機 下位機 — 血壓計
1.血壓計與手機連線藍芽之後。
2.上位機主動向下位機傳送一個身份驗證指令,下位機收到指令後開始給上位做應答,
3.應答成功,下位機會將測量的血壓資料傳送到上位機。
4.最後斷開連線。
相關文章
- iOS藍芽4.0(BLE)開發(一)iOS藍芽
- 藍芽4.0 BLE藍芽
- React Native 藍芽4.0 BLE開發React Native藍芽
- 藍芽4.0BLE中協議棧詳解藍芽協議
- Android BLE藍芽詳細解讀Android藍芽
- Android藍芽那點事——深入瞭解藍芽BlE藍芽 《總結篇》Android藍芽
- Android Ble藍芽入門Android藍芽
- Android BLE 藍芽開發——掃碼槍基於BLESSEDAndroid藍芽
- BLE藍芽那些事—深入瞭解Android藍芽Bluetooth基礎篇藍芽Android
- android藍芽BLE(三) —— 廣播Android藍芽
- android藍芽BLE(二) —— 通訊Android藍芽
- android藍芽BLE(一) —— 掃描Android藍芽
- iOS-BLE藍芽開發持續更新iOS藍芽
- BLE低功耗藍芽藍芽
- iOS藍芽4.0開發基礎教程iOS藍芽
- android 4.0 藍芽分析之一Android藍芽
- android 4.0 藍芽分析之二Android藍芽
- iOS 藍芽4.0開發使用(內附Demo)iOS藍芽
- Android開發--藍芽操作Android藍芽
- iOS之BLE藍芽SDK開發個人總結(進階篇)iOS藍芽
- iOS之BLE藍芽SDK開發個人總結(基礎篇)iOS藍芽
- Android 傳統藍芽開發Android藍芽
- Android 藍芽音響開發Android藍芽
- Android藍芽使用詳解(普通藍芽)Android藍芽
- Android藍芽開發流程實踐Android藍芽
- Android藍芽開發全面總結Android藍芽
- ios微信小程式 BLE藍芽通訊開發介面UI卡頓問題iOS微信小程式藍芽UI
- iOS藍芽開發iOS藍芽
- 藍芽Mesh解決方案加速物聯網設計藍芽
- Android 開啟藍芽流程Android藍芽
- iOS藍芽開發 Bluetooth藍芽CoreBluetooth 藍芽中心裝置的實現 藍芽外設的實現 有DemoiOS藍芽
- Android藍芽那點事——深入瞭解Android藍芽Bluetooth《進階篇》Android藍芽
- Android BLE開發小記Android
- Android 藍芽開發相關知識總結Android藍芽
- iOS BLE藍芽開發資料傳輸協議詳解 常用演算法(AES加密,HMAC_hash,PRF)iOS藍芽協議演算法加密Mac
- Android藍芽協議-藍芽掃描 startDiscoveryAndroid藍芽協議
- iOS 藍芽開發 - swift版iOS藍芽Swift
- 微信小程式藍芽開發微信小程式藍芽