最近做了一个智能硬件开发(针灸仪)的项目,有一部分涉及到低功耗蓝牙的开发,就是通过蓝牙和设备进行数据的交互,比如控制改设备的LED的开关,设备的开关机,设置设备的时间和温度等,下面就项目中遇到的坑一一说明:首先给出官网对于BLE开发的讲解,https://developer.Android.com/guide/topics/connectivity/bluetooth-le.html#terms官方demo:https://github.com/googlesamples/android-BluetoothLeGatt,demo也比较好理解,主要是四个类,其中,DeviceControlActivity通过启动BluetoothLeService用来进行与蓝牙外围设备的交互。(注意,因为本人是将UI做了更改,并放到了fragment中,所以部分代码跟demo不一致,请主动忽略,关注蓝牙核心代码)

BLE开发所需要的知识,通过官方demo,我们会发现很多service,点击service后,每个service下面是Characteristic,每个service和Characteristic都对应一个唯一的UUID。所以,在做BLE时候,首先你应该找出你的蓝牙外围设备uuid,不然会很头疼,这个UUID也可能是硬件给你的,也可以你自己试出来,当然自己试出来是个很烦的过程。自己试的方法就是根据demo,加上一份读写的协议,然后,排着点击,显示出来的蓝牙列表进行测试,看是否和协议对应。另外,BluetoothLeService类不用做太多的更改。

一,蓝牙设备的扫描

这一部分基本上很简单,只要设备上电以后,这部分代码执行后,便可以扫描出设备,并获得BluetoothDevice对象

public void scanLeDevice(final boolean enable) {

LogUtils.debug(TAG, "-----------开始扫描蓝牙=" + enable);

if (enable) {

// Stops scanning after a pre-defined scan period.

mHandler.postDelayed(new Runnable() {

@Override

public void run() {

stopScanOuter();

}

}, SCAN_PERIOD);

LogUtils.debug("----------startLeScan--");

mScanning = true;

mBluetoothAdapter.startLeScan(this);

} else {

mScanning = false;

mBluetoothAdapter.stopLeScan(this);

}

}

上面代码为开始扫描周围已上电的设备,当发现设备后,BluetoothAdapter.LeScanCallback会执行onLeScan回调,将BluetoothDevice返回,

@Override

public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {

Fragment dcfrag = getActivity().getSupportFragmentManager().findFragmentByTag("MyDeviceFragment");

if(dcfrag != null && dcfrag.isVisible()) {

getActivity().runOnUiThread(new Runnable() {

@Override

public void run() {

LogUtils.debug(TAG, "---------获得设备" + device);

mLeDeviceListAdapter.addDevice(device);

mLeDeviceListAdapter.notifyDataSetChanged();

}

});

}

}

到此,我们便可以得到扫描到的蓝牙设备,但是目前仅仅是扫描到,并不代表已经连接上蓝牙设备。

二,蓝牙设备的连接

1,绑定service

private final ServiceConnection mServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName componentName, IBinder service) {

LogUtils.debug(TAG, "开始绑定service onServiceConnected"+device+"---name="+device.getName()+"--address="+device.getAddress());

mDeviceAddress = device.getAddress();

mDeviceName = device.getName();

mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();

if (!mBluetoothLeService.initialize()) {

Log.i(TAG, "Unable to initialize Bluetooth");

}

// Automatically connects to the device upon successful start-up initialization.

mBluetoothLeService.connect(mDeviceAddress);

}

@Override

public void onServiceDisconnected(ComponentName componentName) {

LogUtils.debug(TAG, "--------onServiceDisconnected service无法绑定了");

mBluetoothLeService = null;

}

};

public void mybindService(){

LogUtils.debug(TAG, "---------开始执行onCreate---bindservice");

Intent gattServiceIntent = new Intent(getActivity(), BluetoothLeService.class);

getActivity().bindService(gattServiceIntent, mServiceConnection, getActivity().BIND_AUTO_CREATE);

}

2,连接蓝牙

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

final String action = intent.getAction();

if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {

LogUtils.debug(TAG, "--mGattUpdateReceiver ACTION_GATT_CONNECTED");

mConnected = true;

LogUtils.debug(TAG, "--------ACTION_GATT_CONNECTED devicename"+mDeviceName);

Fragment dcfrag = getActivity().getSupportFragmentManager().findFragmentByTag("ConnectFragment");

if((dcfrag != null && dcfrag.isVisible())){

//暂时写死在这可以连接的BLE设备

if(mDeviceName == null || !deviceFilter(mDeviceName)){

connectService.switchFragment(false, mDeviceName);

}else{

connectService.switchFragment(true, mDeviceName);

}

}

} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {

LogUtils.debug(TAG, "--mGattUpdateReceiver ACTION_GATT_DISCONNECTED");

mConnected = false;

Fragment dcfrag = getActivity().getSupportFragmentManager().findFragmentByTag("ConnectFragment");

if((dcfrag != null && dcfrag.isVisible()))

connectService.switchFragment(false, mDeviceName);

Fragment contfrag = getActivity().getSupportFragmentManager().findFragmentByTag("ControlorFragment");

if((contfrag != null && contfrag.isVisible())){

transfertoControler.closeButton(false, false);

}

} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {

LogUtils.debug(TAG, "--mGattUpdateReceiver ACTION_GATT_SERVICES_DISCOVERED");

initMoxibustionService(

mBluetoothLeService.getSupportedGatteService(

SampleGattAttributes.SERVIECE_NOTIFY_DATA));

initMoxibustionService(

mBluetoothLeService.getSupportedGatteService(

SampleGattAttributes.SERVIECE_WRITE_DATA));

// Show all the supported services and characteristics on the user interface.

// displayGattServices(mBluetoothLeService.getSupportedGattServices());

} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {

LogUtils.debug(TAG, "--mGattUpdateReceiver ACTION_DATA_AVAILABLE");

// byte[] data = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);

// StringBuilder stringBuilder = new StringBuilder(data.length);

// for(byte byteChar : data)

// stringBuilder.append(String.format("0x%02X ", byteChar));

// String log = stringBuilder.toString();

// LogUtils.debug(TAG, "---字节数组为="+ log);

parsedata(intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA));

} else if (BluetoothLeService.ACTION_DATA_SEND_CONFIRM.equals(action)) {

// ECHO from android

LogUtils.debug(TAG, "write ok!");

}

}

};

public void myConnetService(){

getActivity().registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());

LogUtils.debug(TAG, "------mBluetoothLeService myConnetService" + mBluetoothLeService);

if (mBluetoothLeService != null) {

final boolean result = mBluetoothLeService.connect(mDeviceAddress);

LogUtils.debug(TAG, "Connect request result=" + result);

}

}

当连接上蓝牙后,我们会得到ACTION_GATT_CONNECTED的广播,然后是ACTION_GATT_SERVICES_DISCOVERED,这个时候我们需要对service进行初始化,以便能够读写数据,以下为初始化代码(注意,初始化时候我们需要用到读写service的UUID)

private void initMoxibustionService(BluetoothGattService gattService) {

String uuid = "";

if (gattService == null)

{

LogUtils.debug(TAG, "gattService is null");

return;

}

List gattCharacteristics = gattService.getCharacteristics();

for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {

uuid = gattCharacteristic.getUuid().toString();

if (SampleGattAttributes.CHARACTER_NOTIFY_DATA.substring(0,8).equals(uuid.substring(0, 8))) {

mNotifyCharacteristic = gattCharacteristic;

mBluetoothLeService.setCharacteristicNotification(

mNotifyCharacteristic, true);

LogUtils.debug(TAG, "NOTIFY_DATA");

LogUtils.debug(TAG, "getProperties()=" + mNotifyCharacteristic.getProperties());

} else if (SampleGattAttributes.CHARACTER_WRITE_DATA.substring(0,8).equals(uuid.subSequence(0, 8))) {

// mCommandCharacteristic = gattCharacteristic;

//写数据的服务和characteristic

mCommandCharacteristic = mBluetoothLeService.getSupportedGatteService(SampleGattAttributes.SERVIECE_WRITE_DATA)

.getCharacteristic(UUID.fromString(SampleGattAttributes.CHARACTER_WRITE_DATA));

LogUtils.debug(TAG, "WRITE_CMD");

LogUtils.debug(TAG, "getProperties()=" + mCommandCharacteristic.getProperties());

mCommandCharacteristic.setWriteType(

BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

LogUtils.debug(TAG, "getProperties()=" + mCommandCharacteristic.getProperties());

}

}

}

CHARACTER_NOTIFY_DATA和CHARACTER_WRITE_DATA为读和写数据的CHARACTER的UUID,如下,注意这四个UUID

3,解析数据

至此,如果顺利的话,我们就可以得到ACTION_DATA_AVAILABLE的广播,也就拿到了从蓝牙设备获得的byte数组,大多数协议里,每个字节代表一个命令。这里涉及到Java中byte值与int值的转换。因为Java中,所有的值都是singed性的,最高位为符号位,所以,大家请自行补下该部分的知识,对于有符号数,它的值相当于取补码,此处将不详述,

上面为读数据,下面我们说写数据,比如,如下的开关机命令,

// 01 10 01 01 92 07 17

public void controlpower(boolean isOpen){

if (mCommandCharacteristic == null) return;

if (mBluetoothLeService == null) return;

byte[] setDataAfter;

if(isOpen){

byte[] setDataBefore = {0x01, 0x10, 0x01, 0x01};

byte[] trans = inttobyte(integrityCheck(setDataBefore));

byte[] transV = Arrays.copyOfRange(trans, 2, 4);

byte[] setData = byteMerger(setDataBefore, reverse(transV));

byte[] dd = {0x17};

setDataAfter = byteMerger(setData, dd);

LogUtils.debug(TAG, "---setDataAfter[4]="+setDataAfter[4]+",setDataAfter[5]="+setDataAfter[5]);

}else{

byte[] setDataBefore = {0x01, 0x10, 0x01, 0x00};

byte[] trans = inttobyte(integrityCheck(setDataBefore));

byte[] transV = Arrays.copyOfRange(trans, 2, 4);

byte[] setData = byteMerger(setDataBefore, reverse(transV));

byte[] dd = {0x17};

setDataAfter = byteMerger(setData, dd);

printDataHex(setDataAfter);

}

mCommandCharacteristic.setValue(setDataAfter);

mBluetoothLeService.writeCharacteristic(mCommandCharacteristic);

}

mCommandCharacteristic.setValue(setDataAfter);

mBluetoothLeService.writeCharacteristic(mCommandCharacteristic);

这两行代码,是核心代码,但是,我们要进行字节数组的正确传递,这里,给大家贴出来几个很有可能用到的方法,

CRC算法Java版:

//crc java

public int integrityCheck(byte[] bytes) {

int wCrc = 0xffff;

for (byte srcData : bytes) {

int data = byteToInt(srcData);

for(int j = 0; j < 8; j++) {

if ((((wCrc & 0x8000) >> 8) ^ ((data << j) & 0x80)) != 0) {

wCrc = (wCrc << 1) ^ 0x1021;

} else {

wCrc = wCrc << 1;

}

}

}

wCrc = (wCrc << 8) | (wCrc >> 8 & 0xff);

return wCrc & 0xffff;

}

public static int byteToInt(byte b) {

return b & 0xff;

}

// int to byte

public static byte[] inttobyte(int value) {

byte b0 = (byte) ((value >> 24) & 0xFF);

byte b1 = (byte) ((value >> 16) & 0xFF);

byte b2 = (byte) ((value >> 8) & 0xFF);

byte b3 = (byte) (value & 0xFF);

byte[] bytes = { b0, b1, b2, b3 };

return bytes;

}

//打印字节数组

public void printDataHex(byte[] data) {

if(SENTLOG){

StringBuilder stringBuilder = new StringBuilder(data.length);

for(byte byteChar : data)

stringBuilder.append(String.format("0x%02X ", byteChar));

String log = stringBuilder.toString();

LogUtils.debug(TAG, "---发送到蓝牙的字节数组为="+ log);

}

}

//数组倒序

public byte[] reverse(byte[] rt){

for (int i = 0; i < rt.length / 2; i++) {

byte temp = rt[i];

rt[i] = rt[rt.length - 1 - i];

rt[rt.length - 1 - i] = temp;

}

return rt;

}

//java 合并两个byte数组

public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){

byte[] byte_3 = new byte[byte_1.length+byte_2.length];

System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);

System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);

return byte_3;

}

写的比较简单,但是关键代码都有了,大家可以参考下!~

android低耗能蓝牙开发,Android BLE低功耗蓝牙开发相关推荐

  1. Android BLE低功耗蓝牙开发

    啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂...总之刚开始查的很痛苦.所以要把自己的踩坑之路写下来记录下, ...

  2. 谈谈几个月以来开发android蓝牙4.0 BLE低功耗应用的感受

    谈谈几个月以来开发android蓝牙4.0 BLE低功耗应用的感受 谈谈几个月以来开发android蓝牙4.0 BLE低功耗应用的感受,注明下时间:2012-10-17写的博客,后期更新的也注明了时间 ...

  3. 开发android蓝牙4.0 BLE低功耗应用的感受

    文章转自: http://www.cnblogs.com/zdz8207/archive/2012/10/17/bluetooth_ble_android.html 谈谈几个月以来开发android蓝 ...

  4. Android 8.0 BLE 低功耗蓝牙开发记录

    Android 8.0 BLE 低功耗蓝牙开发记录(1-3)--------------(权限申请篇未完待续) 目的:开源博客,希望大家一起修改博客错误地方,共同完善并会鸣谢提供意见的朋友.为大家提供 ...

  5. android studio蓝牙低功耗,arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网

    arduino ESP32 AndroidStudio BLE低功耗蓝牙 物联网 nodered开发: esp32采用的蓝牙于普通的蓝牙不同,是低功耗蓝牙,手机用一般的蓝牙代码是连不上的.在本文中,不 ...

  6. android蓝牙4.0 BLE低功耗应用

    转自    http://www.cnblogs.com/zdz8207/archive/2012/10/17/bluetooth_ble_android.html 谈谈几个月以来开发android蓝 ...

  7. Android BLE(低功耗蓝牙)技术总结

    文章目录 前言 一.蓝牙介绍 1.什么是蓝牙? 2.蓝牙版本介绍 二.低功耗蓝牙(BLE) 1.BLE介绍 2.经典蓝牙(Classic Bluetooth)与低功耗蓝牙(BLE)的区别 3.低功耗蓝 ...

  8. 怎么查看蓝牙uuid_多设备低功耗蓝牙 Swarm BLE in Android and iOS

    Camellia Café 在这里讲述同时与多个低功耗蓝牙设备的连接及通迅,在Android和iOS中的开发,敬请点击观看视频: 多设备低功耗蓝牙Android和iOShttps://www.zhih ...

  9. c# 低功耗蓝牙_Android ble低功耗蓝牙开发-客户端

    什么是BLE(低功耗蓝牙) BLE(Bluetooth Low Energy,低功耗蓝牙)是对传统蓝牙BR/EDR技术的补充. 尽管BLE和传统蓝牙都称之为蓝牙标准,且共享射频,但是,BLE是一个完全 ...

  10. ble 低功耗蓝牙开发学习 嵌入式交流学习

    ble 低功耗蓝牙开发学习 嵌入式交流学习 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 这篇文章教你学会低功耗蓝牙开发,从0到深入,适合自学的学生.初级工程师 前言 随着疫情爆发 ...

最新文章

  1. 如何安装jdk_Java JDK下载与安装教程
  2. 修改title样式_css常见样式命名规则
  3. 一行Java代码竟能获取tomcat的绝对路径
  4. CodeForces - 1358D The Best Vacation(前缀和+尺取)
  5. openssl创建CA并签发证书
  6. 精讲23种设计模式-策略模式~聚合短信服务和聚合支付服务
  7. 应用id_科普贴:什么是OpenID、AppID 、用户ID等各种ID?
  8. CodeForces - 1013B And 与运算暴力
  9. linux执行多个命令_您必须知道的前50多个Linux命令
  10. 二选一数据选择器2-1 MUX
  11. NewLand手持设备上条码扫描
  12. 顶顶通软电话介绍-一个网络电话客户端(SIP软电话)
  13. 多个杀毒软件共存有什么影响。
  14. 100base-fx 单模/多模接口是什么意思
  15. 一个JS框架D3.js
  16. 平面设计中的简约设计到底指什么?
  17. 计算机视觉与深度学习(12)
  18. S3MTilesLayer模型图层显示
  19. 云计算介绍 tcp/ip协议介绍及配置
  20. CMake教程之构建Qt平台

热门文章

  1. Java调用Python的方法
  2. angular的run方法
  3. JavaScript——水仙花数
  4. linux配置互信权限问题,Linux互信及互信失效问题
  5. Fcitx下的Google拼音和云拼音
  6. 计算机开机硬盘扫描,每次启动系统进入前都要进行磁盘扫描硬盘的解决方法
  7. 分享几个常用的可以从外部攻击视角发现甲方公司安全问题的开源工具
  8. 蚂蚁金服上市了,“我对钱不感兴趣”的马爸爸王牌迭出
  9. windows怎么录制内部发出的声音
  10. 以“老师”命名的 Julia 语言,结合了 Python、R、C的优点,到底有多厉害!