BLE低功耗蓝牙与经典蓝牙(持续更新)

>蓝牙类别与简介

BLE设备分单模和双模两种,双模简称BR,商标为Bluetooth Smart Ready,单模简称BLE或者LE,商标为Bluetooth Smart。低功耗蓝牙是不能兼容经典蓝牙的,需要兼容,只能选择双模蓝牙。一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。

android Ble开发的那些事(一)

低功耗蓝牙(BLE):字如其名,第一特点就是低功耗,蓝牙4.0以上的;一个纽扣电池可以支持其运行数月至数年,至于怎么实现低功耗,看下文。它应用场景广,可以想想,现在的智能家居,智能音箱,智能手表等等物联网设备,大多数通过BLE进行配网和数据交互。(每次最大传输20byte字节)

经典蓝牙(BT):经典蓝牙,泛指蓝牙4.0以下的都是经典蓝牙,你还怀念通过蓝牙让音箱播放手机的音乐么?经典蓝牙常用在语音、音乐等较高数据量传输的应用场景上。(每次最大传输20kb字节)
经典蓝牙模块可再细分为:传统蓝牙模块和高速蓝牙模块。
传统蓝牙模块在2004年推出,主要代表是支持蓝牙2.1协议的模块,在智能手机爆发的时期得到广泛支持。
高速蓝牙模块在2009年推出,速率提高到约24Mbps,是传统蓝牙模块的八倍。
传统蓝牙有3个功率级别,Class1,Class2,Class3,分别支持100m,10m,1m的传输距离

双模蓝牙:即在蓝牙模块中兼容BLE和BT

Android 4.3及更高版本,Android 蓝牙堆栈可提供实现蓝牙低功耗 (BLE) 的功能,在 Android 8.0 中,原生蓝牙堆栈完全符合蓝牙 5.0 的要求。也就是说在Android 4.3以上,我们可以通过Android 原生API和蓝牙设备交互。

一、低功耗蓝牙介绍

开发步骤如下:

获取BluetoothAdapter,然后扫描,获取蓝牙驱动Device,然后连接蓝牙驱动,监听连接回调,获取一个驱动Device下的所有不同功能的service数组,通过service的uuid获取需要的service,拿到service后通过特征的uuid获取所要的特征Characteristic,每个特征都含有一个value和多个对value的描述Descriptor。通过操作特征可以读取和写入数据。

//1. Android 4.3以上,Android 5.0以下
mBluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback LeScanCallback)
//2. Android 5.0以上,扫描的结果在mScanCallback中进行处理
mBluetoothLeScanner=mBluetoothAdapter.getBluetoothLeScanner(); 
mBluetoothLeScanner.startScan(ScanCallback mScanCallback);

GATT协议:

1.一个蓝牙设备有多个Service->每个Service内部有多个characteristic属性->每个characteristic属性内有多个特征和携带的value值;蓝牙的读写都是通过characteristic属性来进行的,通过Gatt进行扫描蓝牙和连接。service和characteristic,都有一个唯一的uuid来标识。GATT协议

2.profile(数据配置文件):一个profile文件可以包含一个或者多个Service,一个profile文件包含需要的服务的信息或者为对等设备如何交互的配置文件的选项信息。ProfileProfile 并不是实际存在于 BLE 外设上的,它只是一个被 Bluetooth SIG 或者外设设计者预先定义的 Service 的集合。

BLE技术是基于GATT进行连接与通信的,GATT是一种属性传输协议,简单的讲可以认为是一种属性传输的应用层协议。结构图如下

image

3.UUID:“GATT层”中定义的所有属性都有一个UUID值,UUID是全球唯一的128bit的号码数字,它用来识别不同的特性。作用类似Soccket通信的端口。蓝牙核心规范制定了两种不同的UUID,一种是基本的UUID,一种是代替基本UUID的16位UUID。所有的蓝牙技术联盟定义UUID共用了一个基本的UUID:

0x0000xxxx-0000-1000-8000-00805F9B34FB

为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。例如,心率测量特性使用0X2A37作为它的16位UUID,因此它完整的128位UUID为:

0x00002A37-0000-1000-8000-00805F9B34FB

虽然蓝牙技术联盟使用相同的基本UUID,但是16位的UUID足够唯一地识别蓝牙技术联盟所定义的各种属性。蓝牙技术联盟所用的基本UUID不能用于任何定制的属性、服务和特性。对于定制的属性,必须使用另外完整的128位UUID。

每一个Service、属性特征characteristic、属性描述Descriptor都有一个专属的UUID做为标示。

4.主从设备

Center(中心设备,主动连接的一方)

Center主要可以分为 扫描->连接->通讯 三块内容. 通讯主要包含read,write,notify/indicate。read就是读取设备上的数据(如读取外设电量),write就是发送数据(如发送关闭命令关闭蓝牙灯),notify/indicate 字面意思就是通知/指示, 是用来接收设备主动上报的数据的(如手环可以每隔1秒就告诉APP心率值, 然后APP展现一个心率谱图),这样就达成了双向通讯。

Peripheral(外设设备,被动连接的一方)

Peripheral主要理解为硬件外设,提供数据用的。在开发APP时很少关心这个,因为大家都是直接拿着硬件来调试的。在android5.0时,增加了Peripheral相关的API, 意味着可以让android设备模拟成外设,作为Peripheral来提供数据。这样,当我们没有硬件设备的时候,可以拿2台手机进行BLE开发,很方便。还可以扩展很多其他功能,比如使用BLE实现蓝牙聊天(google sample里面有经典蓝牙的聊天demo),还可以把手机模拟成iBeacon等等。

5、数据发送接收
BLE蓝牙Cline端,最多一次性发送20byte长度的数据,所以往往我们开发中是不够用的,这时候可以采用分包发送。

  • 设置MTU,即ATT最大传输单元,MTU默认是23字节(可用20个字节),Android5.0及以上可以自定义最大传输单元,Android5.0以下无法设置,所以Android5.0以下机型上传输数据大于20个字节,请分包传输。MTU设置建议在BLE设备连接成功时进行设置mBluetoothGatt.requestMtu(requiredMtu)

  • 接收和发送数据的格式多种多样有ASCII码 ,十六进制,字符串,甚至还有Json,只要能读取到数据就没什么问题。characteristic.setValue( )值可以是byte[]、String、int

  • 解决方案如下:具体的核心理论就是分包,也就是把一条命令分成多次来发送,而后最后组装一下即可。


    分包发送

    如上图所示,模拟命令分成15个包传输过来,每个包大小固定位最大20个字符,第1-14包为模拟命令数据,第十五个包只发送了一个EOM字符串,接收端每接收到一个包则把这个数据追加到上一个包数据上,直到收到EOM标识也就是一个包的结束标识,则把当前收到的所有数据进行解析,解析完成就可以进行下一步业务处理了。

ble读和写:

蓝牙BLE(BlueTooth BLE)入门及爬坑指南
BLE传输大数据

分包发送代码示例:

private void writeData(){
        BluetoothGattService service=mBluetoothGatt.getService(write_UUID_service);
        BluetoothGattCharacteristic charaWrite=service.getCharacteristic(write_UUID_chara);
        byte[] data=HexUtil.hexStringToBytes(hex);
        if (data.length>20){//数据大于个字节 分批次写入
            Log.e(TAG, "writeData: length="+data.length);
            int num=0;
            if (data.length%20!=0){
                num=data.length/20+1;
            }else{
                num=data.length/20;
            }
            //分包发送
            for (int i=0;i<num;i++){
                byte[] tempArr;
                if (i==num-1){
                    tempArr=new byte[data.length-i*20];
                    System.arraycopy(data,i*20,tempArr,0,data.length-i*20);
                }else{
                    tempArr=new byte[20];
                    System.arraycopy(data,i*20,tempArr,0,20);
                }
                charaWrite.setValue(tempArr);
                mBluetoothGatt.writeCharacteristic(charaWrite);
            }
        }else{
            charaWrite.setValue(data);
            mBluetoothGatt.writeCharacteristic(charaWrite);
        }
    }

开启订阅

//订阅通知
    mBluetoothGatt.setCharacteristicNotification(mBluetoothGatt
                    .getService(notify_UUID_service).getCharacteristic(notify_UUID_chara),true);

注意在写入之前要先开启订阅,要不然就收不到写入的数据,我一般都是在发现服务之后就订阅。关于订阅收不到这里,需要注意一下,首先你写入的和订阅的Characteristic对象一定要属于同一个Service对象,另外就是保证你写入的数据没问题,否则就可能收不到订阅回调。

二、经典蓝牙开发
Android-经典蓝牙(BT)-建立长连接传输短消息和文件
1、经典蓝牙的开发类似一个Socket连接。Clinet端需要创建一个BluetoothSocket,服务端需要创建一个BluetoothServerSocket监听待连接的uuid的clinet,这个监听uuid类似Socket的端口监听。数据操作采用输入流与输出流写入和读取。

SPP_UUID是同一个UUID,也就是类似Scoket的端口
——Clinet端——

//BluetoothSocket socketC = dev.createRfcommSocketToServiceRecord(SPP_UUID); //加密传输,Android系统强制配对,弹窗显示配对码
BluetoothSocket socketC = dev.createInsecureRfcommSocketToServiceRecord(SPP_UUID); //明文传输(不安全),无需配对

——Service端——

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
//BluetoothServerSocket mSSocket = adapter.listenUsingRfcommWithServiceRecord(TAG, SPP_UUID); //加密传输,Android强制执行配对,弹窗显示配对码
BluetoothServerSocket mSSocket = adapter.listenUsingInsecureRfcommWithServiceRecord(TAG, SPP_UUID); //明文传输(不安全),无需配对

BluetoothSocket socketC = mSSocket.accept(); // 监听连接
mSSocket.close(); // 关闭监听,只连接一个设备
服务端和客户端都可获取输入流与输出流,然后读取数据与发送数据信息
//发送信息用输出流
DataOutputStream mOut = new DataOutputStream(socketC.getOutputStream());
//读取信息用输入流
DataInputStream mIn= new DataInputStream(socketC.getInputStream());

GitHub上不错的项目推荐
1.一款非常棒的经典蓝牙与BLE含Service+Clinet端demo
2.FastBle一款非常棒的BLE框架
3.Android-BluetoothKit蓝牙框架

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352