Android使用低功耗蓝牙BLE进行简单通信

一.蓝牙硬件操作

Android操作蓝牙需要申请蓝牙权限、定位权限,部分手机还必须要打开GPS才能使用。
蓝牙的打开、关闭、搜索,这部分内容只是简单的调用API就能实现,这里不做说明。
但是从连接开始就要了解一些低功耗蓝牙的知识,这些是在Android以外的知识,现在介绍最基础的使用。

1.连接

public void connect(Context context, BluetoothDevice device)

    mBluetoothGatt = device.connectGatt(context, false, mBluetoothGattCallback);

}

这里着重说明BluetoothGatt和BluetoothGattCallback这两个东西,Gatt是一种协议一种规范,低功耗蓝牙就是建立在这个协议之上的通信方式。

二.在连接之后,要把蓝牙看作一个什么样的对象把蓝牙看作一个树形结构

调用完连接方法之后,就把蓝牙看作上面这棵树,最重要的就是characteristic节点,characteristic(特征值)是手机与蓝牙设备交互信息的关键。

现在要通过BluetoothGatt这个对象来操纵蓝牙,而通过BluetoothGattCallback这个回调来接收蓝牙的消息和状态变化。下面按照顺序说明,连接后应该做的操作

mBluetoothGattCallback = new BluetoothGattCallback() {

  @Override

  public void onConnectionStateChange(final BluetoothGatt gatt, final int status,

    final int newState) {

    if (newState == BluetoothGatt.STATE_CONNECTED) {

       gatt.discoverServices();

    }else{...}

  }

  @Override

  public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {

    if (status == BluetoothGatt.GATT_SUCCESS){

      //todo 可以去找特征值了

    }

  }

  @Override

  public void onCharacteristicRead(BluetoothGatt gatt,

      final BluetoothGattCharacteristic characteristic, final int status) {

  }

  @Override

  public void onCharacteristicWrite(BluetoothGatt gatt,

      final BluetoothGattCharacteristic characteristic, final int status) {

  }

  @Override

  public void onCharacteristicChanged(BluetoothGatt gatt,

      final BluetoothGattCharacteristic characteristic) {

    //todo 按照协议解析数据,characteristic.getValue()

  }

};

1.设备连接状态的变化

在onConnectionStateChange中等待接收连接状态的改变,这里能够接收,连接成功、连接失败、断开等状态。

2.在判断到连接成功之后,发现服务

gatt.discoverServices();

在调用发现服务之后会,这个回调会得到消息onServicesDiscovered,当服务发现之后,就代表我们可以去操作我们需要的service和characteristic了。

3.如何找到要用的characteristic

UUID(通用唯一识别码),蓝牙中用到了这个概念,每一个service,characteristic都有唯一的UUID。我们需要的UUID应该由蓝牙硬件一方提供说明文档,告知做app的开发人员,不同的characteristic可能对应不同的功能。

这是两个很常用的UUID

String UUID_service ="0000FFE0-0000-1000-8000-00805F9B34FB";

String UUID_characteristic ="0000FFE1-0000-1000-8000-00805F9B34FB";

UUID serviceUUID = UUID.fromString(UUID_service);

UUID characteristicUUID = UUID.fromString(UUID_characteristic);

service =bluetoothGatt.getService(serviceUUID);

characteristic =service.getCharacteristic(characteristicUUID);

至此,我们终于拿到了最关键的这个对象,我们可以主动去读一下这个特征值瞧瞧

bluetoothGatt.readCharacteristic(characteristic)

结果会在onCharacteristicRead中得到

三.如何使用特征值与蓝牙设备互发消息

1.向蓝牙设备发送消息

蓝牙与手机的交流都是通过字节数组,当我们修改蓝牙设备特征值,蓝牙就收到了我们发送的这串数据,

characteristic.setValue(byte[] data);

bluetoothGatt.writeCharacteristic(characteristic);

然后就会在回调onCharacteristicWrite中得到我们刚发送的消息的结果,

  @Override

  public void onCharacteristicWrite(BluetoothGatt gatt,

      final BluetoothGattCharacteristic characteristic, final int status) {

      if (status == BluetoothGatt.GATT_SUCCESS){

      }

  }

这就证明发送成功了。

2.接收蓝牙设备发送的消息

手机端通过监听特征值的变化,来接收消息,如果蓝牙设备改变了一个特征值的值,被我们监听到了,这就相当于,蓝牙设备向app发送了字节数组。

bluetoothGatt.setCharacteristicNotification(characteristic, true);

  @Override

  public void onCharacteristicChanged(BluetoothGatt gatt,

      final BluetoothGattCharacteristic characteristic) {

      //todo 按照协议解析数据,characteristic.getValue(),注意:每次传输大小有限制,如果过长,这个回调就会执行多次,要自己把每次的到的数据拼接成一个完整的数据帧

  }

每当特征值被蓝牙修改,我们就会在onCharacteristicChanged接收到修改的信息,这就是蓝牙发送消息给app。

3.解析数据

数据的解析,要根据协议来执行,这个协议一般由app的开发和蓝牙硬件的开发人员一起制定。

举例说明:

假设这样制定一个协议,将接收到的字节数组转成十六进制,每个字节的范围就是00-FF

规定每一个完整的数据帧是以BB开头,以7E结尾,数组中第二个位置的数字代表有用数据体的长度。app可以根据这个规定拼接完整数据帧,以及排除一些多余的或者错误的字节

BB 02 A7 64 7E

这个数据帧中代表特别含义的数据体就是 A7 64

其中第一位代表功能标识,其中A7可能就代表这个消息是电池的电量,64表示剩余电量是100%

四.DEMO

private final String TAG = "BLE_TEST"; 

private String UUID_service = "0000FFE0-0000-1000-8000-00805F9B34FB"; 

private String UUID_characteristic ="0000FFE1-0000-1000-8000-00805F9B34FB"; 

private BluetoothGatt mBluetoothGatt; 

private BluetoothGattCharacteristic mCharacteristic; 

private BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() { 

  @Override

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

    if (newState == BluetoothGatt.STATE_CONNECTED) {

      gatt.discoverServices();//四.连接蓝牙成功之后,发现服务

    }

  super.onConnectionStateChange(gatt, status, newState);

}

  @Override

  public void onServicesDiscovered(BluetoothGatt gatt, int status) {

    if (status == BluetoothGatt.GATT_SUCCESS){ //五.发现服务成功之后,去找需要的特征值

      UUID serviceUUID = UUID.fromString(UUID_service);

      UUID characteristicUUID = UUID.fromString(UUID_characteristic);

      BluetoothGattService service = mBluetoothGatt.getService(serviceUUID);

      mCharacteristic = service.getCharacteristic(characteristicUUID); //找到特征值之后进行收发操作,设置接收特征值通知

      mBluetoothGatt.setCharacteristicNotification(mCharacteristic, true);

      send(); //发个消息给蓝牙

  }

  super.onServicesDiscovered(gatt, status);

}

  @Override

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

    super.onCharacteristicRead(gatt, characteristic, status);

     Log.i(TAG,"onCharacteristicRead" + ByteHelper.BytesToHexString(characteristic.getValue()));

}

  @Override

   public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

    super.onCharacteristicWrite(gatt, characteristic, status);      Log.i(TAG,"onCharacteristicWrite:"+ByteHelper.BytesToHexString(characteristic.getValue()));

  }

   @Override

   public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {

    super.onCharacteristicChanged(gatt, characteristic);

 Log.i(TAG,"onCharacteristicChanged"+ByteHelper.BytesToHexString(characteristic.getValue()));

   }

};

@Override

protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  if (VERSION.SDK_INT >= VERSION_CODES.M) {

    int checkResult = ContextCompat.checkSelfPermission(this, permission.ACCESS_FINE_LOCATION);

    if (checkResult== PackageManager.PERMISSION_DENIED){ 

      ActivityCompat.requestPermissions(this, new String[]{permission.ACCESS_FINE_LOCATION}, 1);

      }

    }

   initBluetooth();

}

private void initBluetooth() {

  BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

  BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();

  bluetoothAdapter.enable();//一.打开蓝牙

  final BluetoothLeScanner bluetoothLeScanner =bluetoothAdapter.getBluetoothLeScanner();

  bluetoothLeScanner.startScan(new ScanCallback() {//二.搜索蓝牙

    @Override

    public void onScanResult(int callbackType, ScanResult result) {

      super.onScanResult(callbackType, result);

      if ("我的蓝牙".equals(result.getDevice().getName())){//三.连接蓝牙

        mBluetoothGatt = result.getDevice().connectGatt(getApplicationContext(), false, mBluetoothGattCallback);

        bluetoothLeScanner.stopScan(this);

      }

     }

  });

}

private void send() {

   byte[] mes = new byte[4];

   mes[0] = (byte) 0xAB;

   mes[1] = (byte) 0xA8;

   mes[2] = (byte) 0x58;

   mes[3] = (byte) 0xFE;

   mCharacteristic.setValue(mes);

   mBluetoothGatt.writeCharacteristic(mCharacteristic);

}

五.总结

这些只是低功耗蓝牙操作的最基本使用,而且只是站在app开发者的角度进行描述。

蓝牙开发还有其他很多可扩展的细节,如:

解析广播包

将手机作为外围设备

单次传输突破20字节限制

通知与指示器的区别

等等等等。。。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值