1. 程式人生 > >Android之開發BLE 詳細步驟

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();//關閉藍芽