一.蓝牙硬件操作

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() {@Overridepublic void onConnectionStateChange(final BluetoothGatt gatt, final int status,final int newState) {if (newState == BluetoothGatt.STATE_CONNECTED) {gatt.discoverServices();}else{...}}@Overridepublic void onServicesDiscovered(final BluetoothGatt gatt, final int status) {if (status == BluetoothGatt.GATT_SUCCESS){//todo 可以去找特征值了}}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic, final int status) {}@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic, final int status) {}@Overridepublic 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中得到我们刚发送的消息的结果,

  @Overridepublic void onCharacteristicWrite(BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic, final int status) {if (status == BluetoothGatt.GATT_SUCCESS){}}

这就证明发送成功了。

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

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

bluetoothGatt.setCharacteristicNotification(characteristic, true);@Overridepublic 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() { @Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {if (newState == BluetoothGatt.STATE_CONNECTED) {gatt.discoverServices();//四.连接蓝牙成功之后,发现服务}super.onConnectionStateChange(gatt, status, newState);}@Overridepublic 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);}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);Log.i(TAG,"onCharacteristicRead" + ByteHelper.BytesToHexString(characteristic.getValue()));}@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);      Log.i(TAG,"onCharacteristicWrite:"+ByteHelper.BytesToHexString(characteristic.getValue()));}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {super.onCharacteristicChanged(gatt, characteristic);Log.i(TAG,"onCharacteristicChanged"+ByteHelper.BytesToHexString(characteristic.getValue()));}};@Overrideprotected 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() {//二.搜索蓝牙@Overridepublic 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字节限制

通知与指示器的区别

等等等等。。。

Android使用低功耗蓝牙BLE进行简单通信相关推荐

  1. 泰凌微ble mesh蓝牙模组天猫精灵学习之旅④如何在Android开发低功耗蓝牙ble控制 TB-02 模块,代码工程全部开源!(附带Demo)

    本<泰凌微ble mesh蓝牙模组天猫精灵学习之旅>系列博客学习由半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.小白也痴迷,如 ...

  2. Android低功耗蓝牙(BLE)开发(二)

    在上一篇文章Android低功耗蓝牙(BLE)开发(一)中我们了解了BLE的相关概念,这里我们来实际用代码演示安卓进行BLE连接和通讯的功能.本文代码基于Android5.0以上(API 21) 1. ...

  3. (Android)低功耗蓝牙(BLE)开发一文全(详)解

    前言:如果你是刚开始接触android关于低功耗(ble)蓝牙的开发,还是应该花点是时间了解一下BLE协议,因为哪怕你把蓝牙ble协议梳理个一知半解,那么开发就只剩下调用API了... 为了快速编辑, ...

  4. Android低功耗蓝牙BLE

    低功耗蓝牙BLE与传统的蓝牙相比最大的优势是功耗降低90%,同时传输距离增大(超过100米).安全和稳定性提高(支持AES加密和CRC验证),允许Android应用程序与具有更严格电源要求的BLE设备 ...

  5. PyQt5之QtBluetooth模块:低功耗蓝牙BLE通信

    PyQt5之QtBluetooth模块:低功耗蓝牙BLE通信 最近使用PyQt5开发PC端工具,正巧手上有一个富芮坤的低功耗蓝牙,于是想在PC端试试与之通信,不过发现使用PyQt5开发低功耗蓝牙的教程 ...

  6. 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解 ...

  7. java 协议栈_深入浅出讲解低功耗蓝牙(BLE)协议栈

    详解BLE连接建立过程 https://www.cnblogs.com/iini/p/8972635.html 详解BLE 空中包格式-兼BLE Link layer协议解析 https://www. ...

  8. 蓝牙:深入浅出低功耗蓝牙(BLE)协议栈

    深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解BLE"连接"?如果BLE协议只有ATT层没有GATT层会发生什么? 协议栈框架 一般而言,我们把某个协议的实 ...

  9. 低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端

    低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端 Android对外模模式(peripheral)的支持 从Android5.0开始才支持 关键术语和概念 以下是关键BLE术语和 ...

最新文章

  1. sql左连接排序取第一个_详解kettle工具记录集连接功能及实验测试
  2. awk小技巧之执行shell命令
  3. 老鸟程序员才知道的40个小技巧
  4. 金蝶kis云触发器解决审核和反审核的问题
  5. 还是畅通工程 最小生成树
  6. python urlopen_Python爬虫教程-02-使用urlopen
  7. 测试线程池(Java)
  8. 分治法 —— 快速排序和归并排序(自底向上和自顶向下)
  9. 半监督学习入门基础(一)
  10. java基础27 单例集合Collection及其常用方法
  11. SurfaceView 之满屏的代码雨效果
  12. 三级网络技术无纸化模拟软件 (未来)教育
  13. esp8266教程:网络基础知识
  14. WIN7电脑语言栏不见了---解决方案
  15. 什么是自然语言处理(NLP)?
  16. 常用邮箱的 IMAP/POP3/SMTP 设置
  17. 微信公众号新变动!你都发现了吗?
  18. 无线笔记本怎么连接服务器打印机驱动,笔记本怎么连接无线打印机驱动程序
  19. 【并发编程的艺术】并发机制原理
  20. 根据PyTorch学习CONV1D

热门文章

  1. java集成阿里云短信,实现登录功能
  2. STM32H7双核培训
  3. 七牛云直播-Android端播放卡顿问题处理
  4. 一份最新最全的 5G PPT 来了!
  5. YARN Registry DNS启动提示“53端口被占用”错误的解决方法
  6. 2020-07-09:mysql如何开启慢查询?
  7. IE和Chrome可以并行下载多少个资源?
  8. Nature neuroscience:功能脑组织表征的挑战和未来方向
  9. C++ 使用zlib开源库的minizip解压缩文件及文件夹
  10. Mastodon 用户易受密码窃取攻击