欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BLE入门

程序员文章站 2022-07-13 17:53:47
...

权限及feature

    应用使用蓝牙

<uses-permission android:name="android.permission.BLUETOOTH"/>

    扫描设备或者操作蓝牙设置 则还需

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

  除蓝牙权限外,还需声明BLE feature

<uses-feature android:name="android:handware.bluetooth_le"
              android:required="true"/>

   设置为 true 时,应用只能在支持BLE的设备上安装运行,为false时,安卓设备均可安装运行,可在代码中判断设备是否支持BLE

getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);

 

 

启动蓝牙

获取Bluetooth Adapter

      整个系统中 BluetoothAdapter是单例的

final BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapater mBluetoothAdapter = mBluetoothManager.getAdapter();

   或者

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

判断是否支持蓝牙,并打开蓝牙

if(mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()){
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} 
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  // User chose not to enable Bluetooth.
  // 如果用户选择不开启蓝牙就直接finish()
  if (requestCode == REQUEST_ENABLE_BT
    && resultCode == Activity.RESULT_CANCELED) {
   finish();
   return;
  }
  super.onActivityResult(requestCode, resultCode, data);
 }

 

搜索BLE设备

调用BluetoothAdapter对象的 startLeScan(LeScanCallback callBack)方法搜索设备(停止搜索方法为 stopLeScan(LeScanCallback callBack))

获取设备之后的操作在 LeScanCallback中 重写处理。

搜索设备需要尽量减少功耗,因此需注意:

  1. 找到对应设备后,立即停止扫描

  2. 不要循环扫描设备,为每次搜索设置合适的时间限制,避免设备不在可用范围的时候持续不停地扫描消耗电量

private void scanLeDevice() {
     // Stops scanning after a pre-defined scan period.
      mHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
         mScanning = false;
         // 10秒后停止扫描
         mBluetoothAdapter.stopLeScan(mLeScanCallback);
      }
  }, 10000);
  mBluetoothAdapter.startLeScan(mLeScanCallback);
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
  @Override
  public void onLeScan(final BluetoothDevice device, int rssi,
    byte[] scanRecord) {
       runOnUiThread(new Runnable() {
         @Override
         public void run() {
          //更新device list 列表
          mLeDeviceListAdapter.addDevice(device);
          mLeDeviceListAdapter.notifyDataSetChanged();
         }
      });
   }
 };

连接GATT Server

获取设备之后,需建立Gatt连接进行通信

使用BluetoothDevice 对象的connectGatt() 方法获取BluetoothGatt对象。 

 

 */
 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()) {
        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;
   return true;
 }

核心代码  mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

实现BluetoothGattCallback 接口 需重写4个函数

 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)

    gatt 连接状态改变时回调

 public void onServicesDiscovered(BluetoothGatt gatt, int status)

    调用 mBluetoothGatt.discoveryServices()后回调

 public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)

   调用 mBluetoothGatt.readCharacteristic()后 回调

 public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)

   characteristic 改变时回调,需要为characteristic 设置notification

 

 private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
  @Override
  public void onConnectionStateChange(BluetoothGatt gatt, int status,
    int newState) {
   String intentAction;
   if (newState == BluetoothProfile.STATE_CONNECTED) {
      intentAction = ACTION_GATT_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;
      Log.i(TAG, "Disconnected from GATT server.");
      mBluetoothGatt.close();
      mBluetoothGatt = null;
      broadcastUpdate(intentAction);
    }
  }
  @Override
  public void onServicesDiscovered(BluetoothGatt gatt, int status) {
   if (status == BluetoothGatt.GATT_SUCCESS) {
   setCharacteristicNotification(readCharacteristic, true);
    broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
   } else {
    Log.w(TAG, "onServicesDiscovered received: " + status);
   }
  }
  @Override
  public void onCharacteristicRead(BluetoothGatt gatt,
    BluetoothGattCharacteristic characteristic, int status) {
   if (status == BluetoothGatt.GATT_SUCCESS) {
    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
   }
  }
  @Override
  public void onCharacteristicChanged(BluetoothGatt gatt,
    BluetoothGattCharacteristic characteristic) {
      broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
   }
 };

public void setCharacteristicNotification(
   BluetoothGattCharacteristic characteristic, boolean enabled) {
  if (mBluetoothAdapter == null || mBluetoothGatt == null) {
   Log.w(TAG, "BluetoothAdapter not initialized");
   return;
  }
  mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
  List<BluetoothGattDescriptor> descriptors = characteristic
    .getDescriptors();
   for (BluetoothGattDescriptor dp : descriptors) {
   dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
   mBluetoothGatt.writeDescriptor(dp);
  }
 }

断开Gatt

 public void disconnect() {
  if (mBluetoothAdapter == null || mBluetoothGatt == null) {
   Log.w(TAG, "BluetoothAdapter not initialized");
   return;
  }
  mBluetoothGatt.disconnect();
  Log.w(TAG, "bleSevice gatt disconnect()");
 }

GATT 相关概念

Characteristic : 可理解为一个数据类型,包含一个value和 0 到多个对此value的描述

Descriptor : 对characteristic的描述,例如范围 计量单位等

Service : characteristic的集合

其他:

一般来说为了代码的整洁规范,会将ble 包装成service 独立出去,并且实现BluetoothGattCallback 时并不在内部直接写业务逻辑,而是广播出来,在MainActivity中处理,

与gatt相关的操作在ble service内封装成函数,在Activity中 bindservice,通过service对象调用函数。

转载于:https://my.oschina.net/u/2287911/blog/544095