Android之開發BLE 詳細步驟
Android之開發BLE
有問題可以加群討論:517018699
開發之前我們必須知道藍芽廣播常量所代表的含義:
參考文件
- String ACTION_ACL_CONNECTED=”android.bluetooth.device.action.ACL_CONNECTED” 與遠端裝置建立連線(低級別)
- String ACTION_ACL_DISCONNECTED= “android.bluetooth.device.action.ACL_DISCONNECTED”與遠端裝置斷開連線(低級別)
- String ACTION_ACL_DISCONNECT_REQUESTED=”android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED”裝置提出斷開連線請求,即將斷開連線
- String ACTION_BOND_STATE_CHANGED= “android.bluetooth.device.action.BOND_STATE_CHANGED”遠端裝置連線狀態發生改變
- String ACTION_CLASS_CHANGED=”android.bluetooth.device.action.CLASS_CHANGED” 遠端裝置被改變
- String ACTION_FOUND=”android.bluetooth.device.action.FOUND” 發現一個遠端裝置
- String ACTION_NAME_CHANGED=”android.bluetooth.device.action.NAME_CHANGED” 遠端裝置名字傳送改變或者第一次發現遠端藍芽裝置的名稱
- String ACTION_PAIRING_REQUEST=”android.bluetooth.device.action.PAIRING_REQUEST” 廣播配對請求
String ACTION_UUID=”android.bluetooth.device.action.UUID” 遠端裝置取回UUID廣播
String ACTION_BOND_STATE_CHANGED = “android.bluetooth.device.action.BOND_STATE_CHANGED”; 獲取配對狀態
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); //當前的配對的狀態
int state = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.BOND_NONE); //前一次的配對狀態
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //配對的裝置資訊- 已配對:int BOND_BONDED =12;
- 配對中:int BOND_BONDING=11;
- 配對未成功:int BOND_NONE =10;
- String ACTION_CONNECTION_STATE_CHANGED = “android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED”; 配對後的連線狀態
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.ERROR); //當前的連線狀態
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, BluetoothAdapter.ERROR); //前一次的連線狀態
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //連線的裝置資訊
- 未連線 int STATE_DISCONNECTED = 0;
- 連線中 int STATE_CONNECTING = 1;
- 連線成功 int STATE_CONNECTED = 2;
- 藍芽型別常量:
- 傳統藍芽:int DEVICE_TYPE_CLASSIC = 1;
- 低功耗藍芽(BLE):int DEVICE_TYPE_LE= 2;
- 雙模藍芽:int DEVICE_TYPE_DUAL = 3;
- 未知藍芽:int DEVICE_TYPE_UNKNOWN =0;
- 本地藍芽開關狀態廣播: String ACTION_STATE_CHANGED = “android.bluetooth.adapter.action.STATE_CHANGED”
得到狀態值: int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
- 藍芽關閉 int STATE_OFF = 10;
- 藍芽開啟 int STATE_ON = 12;
- 藍芽正在關閉 STATE_TURNING_OFF = 13;
- 藍芽正在開啟 int STATE_TURNING_ON = 11;
- String DISCOVERY_START = BluetoothAdapter.ACTION_DISCOVERY_STARTED; //開始搜尋
- String END_FIND_DEVICE = BluetoothAdapter.ACTION_DISCOVERY_FINISHED; //搜尋結束
- String FIND_DEVICE = BluetoothDevice.ACTION_FOUND; //搜尋到裝置
- String PAIRING_REQUEST = BluetoothDevice.ACTION_PAIRING_REQUEST; //請求配對
開發流程
開發步驟詳解
第一步:在Manifests檔案中註冊許可權
<!--需要硬體支援低功耗藍芽-->
<uses-feature android:name"android.permission.BLUETOOTH_ADMIN"/>
<!--藍芽許可權-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--Android 5.0以上藍芽好需要位置許可權-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="andriod.permission.ACCESS_FINE_LOCATION"/>
第二步開啟藍芽
/**
* 檢查BLE是否起作用
*/
private void checkBLEFeature() {
//判斷是否支援藍芽4.0
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
//獲取藍芽介面卡
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//判斷是否支援藍芽
if (mBluetoothAdapter == null) {
//不支援
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}else
//開啟藍芽
if (!mBluetoothAdapter.isEnabled()) {//判斷是否已經開啟
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
第三步:掃描BEL裝置
//掃描BLE裝置
private void scanLeDevice(final boolean enable) {
if (enable) {
if (mBluetoothAdapter.isEnabled()) {
if (mScanning)
return;
mScanning = true;
mLeDeviceListAdapter.clear();
mHandler.postDelayed(mScanRunnable, 5000);//五秒後關閉掃描
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
ToastUtil.showMsg(getActivity(), R.string.scan_bt_disabled);
}
} else {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mRefreshLayout.setRefreshing(false);
mHandler.removeCallbacks(mScanRunnable);
mScanning = false;
}
}
//關閉掃描
private final Runnable mScanRunnable = new Runnable() {
@Override
public void run() {
scanLeDevice(false);
}
};
第四步:檢視掃描後的回撥
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
/**
* 簡單說一下這三個引數的含義:
* @param device:識別的遠端裝置
* @param rssi: RSSI的值作為對遠端藍芽裝置的報告; 0代表沒有藍芽裝置;
* @param scanRecord:遠端裝置提供的配對號(公告)
*/
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//儲存到本地:用來展示掃描得到的內容
mLeDeviceListAdapter
.addDevice(new LeDevice(device.getName(), device.getAddress(), rssi, scanRecord));
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
第五步:連線裝置
BluetoothGatt常規用到的幾個操作示例:
* connect() :連線遠端裝置。
* discoverServices() : 搜尋連線裝置所支援的service。
* disconnect():斷開與遠端裝置的GATT連線。
* close():關閉GATTClient端。
* readCharacteristic(characteristic) :讀取指定的characteristic。
* setCharacteristicNotification(characteristic, enabled):設定當指定characteristic值變化時,發出通知。
* getServices() :獲取遠端裝置所支援的services。
//獲取BluetoothDevice物件後呼叫coonnectGatt()進行連線
mBluetoothDevice.connectGatt(context,false,mGattCallbask);//第一個引數:上下文,第二個引數:斷開連線是否重連,第三個
//mBluetoothGatt.discoverServices();//此步驟根據業務需求新增
引數連線狀態回撥。
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
//連線狀態改變的回撥
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 連線成功後啟動服務發現
Log.e("AAAAAAAA", "啟動服務發現:" + mBluetoothGatt.discoverServices());
}
};
//發現服務的回撥
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "成功發現服務");
}else{
Log.e(TAG, "服務發現失敗,錯誤碼為:" + status);
}
};
//寫操作的回撥
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "寫入成功" +characteristic.getValue());
}
};
//讀操作的回撥
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "讀取成功" +characteristic.getValue());
}
}
//資料返回的回撥(此處接收BLE裝置返回資料)
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
};
};
}
第六步:傳送資料()回撥也是BluetoothGattCallback
* 讀操作,讀操作比較簡單,只需將相應的特徵值傳入即可得到該特徵值下的資料,如下程式碼:
mBluetoothGatt.readCharacteristic(characteristic);
讀取的結果通過onCharacteristicRead回撥返回:(通過characteristic.getValue()就可以得到讀取到的值了)
// 讀操作的回撥
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "讀取成功" +characteristic.getValue());
}
}
* 寫操作,寫操作是我們的重點,我們可以通過向characteristic寫入指令(傳送指令)以此來達到控制BLE終端裝置的目的:
mBluetoothGatt.setCharacteristicNotification(characteristic,true)//設定該特徵具有Notification功能
//將指令放置進特徵中
characteristic.setValue(new byte[] {資料});
//設定回覆形式
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
//開始寫資料
mBluetoothGatt.writeCharacteristic(chharacteristic);
* 注:
BLE傳輸過程每次最大隻能傳輸20個位元組,所以如果傳送的指令大於20位元組的話要分包傳送,例如現在要傳送28個位元組的,可以先write(前20個位元組),開啟執行緒sleep(幾十毫秒)後在write(後面8個位元組)。
第七步:關閉藍芽
BluetoothAdapter. disable();//關閉藍芽