深入了解Android蓝牙Bluetooth【基础+进阶】

时间:2024-10-08 08:48:56

基础篇

什么是蓝牙?

也可以说是蓝牙技术。所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的。利用“蓝牙”技术,能够有效地简化掌上电脑、笔记本电脑和移动电话手机等移动通信终端设备之间的通信,也能够成功地简化以上这些设备与因特网Internet之间的通信,从而使这些现代通信设备与因特网之间的数据传输变得更加迅速高效,为[无线通信拓宽道路。

蓝牙版本的介绍

蓝牙发展至今经历了8个版本的更新。1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2、5.0。当然5.0的蓝牙模块目前Google虽已发布,但是市场上还未见到5.0的蓝牙设备。那么我们就尽请期待5.0蓝牙设备的到来!

那么在~3.0之间的我们称之为传统蓝牙,开始的蓝牙我们称之为低功耗蓝牙也就是蓝牙ble,当然版本的蓝牙也是向下兼容的。android手机必须系统版本4.3及以上才支持BLE API。

蓝牙2.0标准:

  • 蓝牙2.0标准2.0 是 1.2 的改良提升版,传输率约在
    1.8M/s~2.1M/s,
  • 开始支持双工模式——即一面作语音通讯,同时亦可以传输档案/高质素图片
  • 2.0 版本当然也支持 Stereo 运作。
  • 应用最为广泛的是Bluetooth 2.0+EDR标准,该标准在2004年已经推出,支持Bluetooth 2.0+EDR标准的产品也于2006年大量出现。
  • 虽然Bluetooth 2.0+EDR标准在技术上作了大量的改进,但从标准延续下来的配置流程复杂和设备功耗较大的问题依然存在。
优点:
  • 数据量可以大一些、手机不需要蓝牙4.0
缺点:
  • 需要MFI认证,认证后可以购买苹果指定的解密芯片,方可使用蓝牙传输数据。MFI认证约9.9万美元/款产品,认证周期约半年。
  • 蓝牙2.1+MFI认证芯片,可以支持苹果iPhone4、iPhone4S、iPhone5等具有蓝牙2.1以上功能的苹果IOS设备

蓝牙V2.1+EDR:

相比于2.0版本速度要更快,2.1+EDR 版本的理论传输速率能达到2.1Mbps。并且加入了“Sniff Subrating”技术。这个技术是透过设定在2个装置之间互相确认讯号的发送间隔来节省功耗。对于需要持续传输数据流的硬件设备而言,比如键盘、鼠标等,该技术可以将电池续航能力延长最多5倍。

蓝牙3.0标准:

  • 2009年4月21日,蓝牙技术联盟(Bluetooth SIG)正式颁布了新一代标准规范”Bluetooth Core Specification Version 3.0 High Speed”(蓝牙核心规范3.0版 )
  • 蓝牙3.0的核心是”Generic Alternate MAC/PHY”(AMP),这是一种全新的交替射频技术,允许蓝牙协议栈针对任一任务动态地选择正确射频。
  • 蓝牙3.0的数据传输率提高到了大约24Mbps(即可在需要的时候调用802.11 WI-FI用于实现高速数据传输)。
  • 在传输速度上,蓝牙3.0是蓝牙2.0的八倍,可以轻松用于录像机至高清电视、PC至PMP、UMPC至打印机之间的资料传输,但是需要双方都达到此标准才能实现功能。
优点
  • 在应用方面相比于V2.1+EDR版本,V3.0的数据传输速率理论已达24Mbps,可以用于高清电视、笔记本电脑、平板电脑和打印机之间的资料传输,
  • 同时相对于2.1+EDR,3.0又引入了增强电源控制机制,使空闲时功耗明显降低。

蓝牙4.0标准:

  • 蓝牙4.0规范于2010年7月7日正式发布,新版本的最大意义在于低功耗
  • 同时加强不同OEM厂商之间的设备兼容性,并且降低延迟,理论最高传输速度依然为24Mbps(即3MB/s),有效覆盖范围扩大到100米(之前的版本为10米)。
  • 该标准芯片被大量的手机、平板所采用,如苹果The New iPad平板电脑,以及苹果iPhone 5、魅族MX4、HTC One X等手机上带有蓝牙4.0功能。
优点:
  • 不需做苹果解密芯片,不需MFI苹果认证。
缺点:
  • 数据量不能太大、手机必须是蓝牙4.0的;(蓝牙4.0可以支持苹果
  • iPhone4S、iPhone5等具有蓝牙4.0功能的苹果IOS设备)
优点主要体现在:
  • 1、它拥有高出3.0蓝牙版本30%以上的续航时间。即是在同等电量下,当蓝牙3.0版本的用电量已经到达100%时,杰克的用电仅70%,甚至不到。
  • 2、高出3.0蓝牙版本4倍以上的降噪技术。其CVC6.0消噪技术,比3.0版本的CVC4.0消噪技术更上一层楼,更深度的降噪,让你的每一次通话、每一首歌曲都可以近在咫尺。
  • 3、4.0以上版本的真智能—80HZCPU,高出3.0蓝牙版本5倍以上的无线传输速率。更为快捷的传输速度,让你无论听歌、通话,或者是游戏都可以拥有更加顺畅的体验。
  • 目前4.0的蓝牙最好,传输率最大,距离也较远,待机时间最长,节约电池。
兼容性:

蓝牙4.0有几种模式,如果是蓝牙4.0低功耗模式单模的设备(常称为BLE模式),是不向下兼容的。

现在主流 4.0BLE蓝牙

BLE()低功耗蓝牙
    1. 低功耗蓝牙比传统蓝牙,传输速度更快,覆盖范围更广,安全性更高,延迟更短,耗电极低等等优点
    1. 传统的一般通过socket方式,而低功耗蓝牙是通过Gatt协议来实现。
  • ps: 若是之前没做过传统蓝牙开发,也是可以直接上手低功耗蓝牙开发的。因为它们在通信协议上都有所改变,关联不大。当然有兴趣的可以去下载些传统蓝牙开发的demo看看

现在我们所处在一个蓝牙的时代。在此之前如我们经常使用的蓝牙耳机就已经跨越了好多的版本 蓝牙耳机有v1.1 v1.2 v2.0 v2.1…等诸多版本,究竟有什么样的优势呢?当然是版本越高信号越好,2.0以上支持蓝牙立体声。

那么我们现在所处的的设备大多是属于主从模式的。

什么是主从模式

一个主设备比如手机,一个从设备(这里也成为子设备或从机)主动搜索从机 可以发送 也可以接收, 从机也可以发送和接收 但只能被搜索
主动搜索从机 可以发送 也可以接收 从机也可以发送和接收 但只能被搜索。

常见的蓝牙模块BLE工作模式

对于BLE单设备来讲常见的蓝牙模块的工作模有四种:

  • 主设备模式
  • 从设备模式
  • 广播模式
  • Mesh组网模式

那么这四个模式分别是什么样的情况呢,那么我们继续开车

1. 主设备模式

USR-BLE100支持主设备模式,可以与一个从设备进行连接。在此模式下可以对周围设备进行搜索并选择需要连接的从设备进行连接。同时可以设置默认连接从设备的MAC地址,这样模块上电之后就可以查找此模块并进行连接。并且支持白名单功能,用户只需要把需要连接的设备的MAC写入白名单中,模块搜索到符合白名单的设备时进行连接。

用户不需要关注串口数据与无线数据包之间的数据转换过程,只需通过简单的参数设置,即可实现主设备串口与从设备串口之间的数据透明通信。

主机连接从设备可以分为3种方式:

第一种采用搜索的方式,使用前需要设置如下参数:
  • (1)设置工作模式为主设备模式 AT+MODE=M

  • (2)开启搜索模式 AT+SCAN

  • (3)如果搜索到从设备,如果序号是1,可以使用快速连接命令进行连接。 AT+CONN=1

  • (4)完成设置后,等待指示灯常亮即可代表连接成功,此时两个串口可以进行数据的透明传输。

    第二种方式

    如果你知道要连接的从设备的MAC地址也可以采用下面的方式进行连接:

  • (1)使用 MAC 绑定AT指令设置模块上电默认连接从设备MAC地址 AT+CONNADD=FFFFFFFFFF11

  • (2)设置完成之后使用重启指令重启模块,模块重启之后连接设置的从设备的地址。
    AT+Z

    2. 从设备模式

    BLE支持从设备模式,在此模式下完全符合BLE4.1协议,用户可以根据协议自己开发APP。此模式下包含一个串口收发的Service,用户可以通过UUID找到它,里面有两个通道,分别是读和写。用户可以操作这两个通道进行数据的传输。

    如果用户使用USR-BLE100的主设备与该从设备相连接,那么就无需关注里面的协议,两个设备的串口直接就可以进行数据的透明传输,为用户建立一个简单的无线传输通道。

    在此模式下,用户需要将模块的工作模式设置为从设备模式。用户如果自己开发APP需要我们模块的UUID进行连接,UUID为:0x31,0x01,0x9b,0x5f,0x80,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0xd0,0xcd,0x03,0x00我们提供连接的示例程序。

    • (1)设置模块工作模式为从设备,指令为 AT+MODE=S
    • (2)用户可以通过下面指令查询模块的连接情况 AT+LINK
    • (3)用户也可以使用下面指令将现在连接断开 AT+DISCONN
    • (4)用户如果不想模块被发现和连接,可以使用下面指令关闭广播数据 AT+ADP=OFF

3. 广播模式

比如说USR-BLE100支持广播模式,在这种模式下模块可以一对多进行广播。用户可以通过AT指令设置模块广播的数据,模块可以在低功耗的模式下持续的进行广播,应用于极低功耗,小数据量,单向传输的应用场合,比如无线抄表,室内定位等功能。

常见的蓝牙模块的工作模式
在此模式下,用户可以设置模块进行小数据量广播,用户需要在APP开发时调用BLE标准的接口进行获取,数据需要使用AT指令进行设置
(1) 首先将模块模式设置到广播模式 AT+MODE=B
(2)使用AT指令设置模块要发送的数据,数据位16进制长度不超过30字节,广播格式请参考BLE 协议。 AT+ADVDATA=0201041Aff4c000215B9407F30F5F8466EAFF925556B57FE6D0001000251
(3)通过蓝牙监听软件可以获取到监听的数据包
[

4. Mesh组网模式

USR-BLE100支持Mesh组网模式,在这种模式下模块可以实现简单的自组网络,每个模块只需要设置相同的通讯密码就可以加入到同一网络当中,每一个模块都可以发起数据,每个模块可以收到数据并且进行回复。并且不需要网关,即使某一个设备出现故障也会跳过并选择最近的设备进行传输。

USR-BLE100支持Mesh组网模式,可以简单的将多个模块加入到网络中来,利用星型网络和中继技术,每个网络可以连接超过65000个节点,网络和网络还可以互连,最终可将无数蓝牙模块通过手机、平板电脑或PC进行互联或直接操控。并且不需要网关,即使某一个设备出现故障也会跳过并选择最近的设备进行传输。整个联网过程只需要设备上电并设置通讯密码就可以自动组网,真正实现简单互联。
- (1)首先我们需要将模块模式切换到Mesh组网模式
AT+MODE=F
- (2)设置通讯密码,模块间联网靠密码进行区分 AT+PASS=123456
- (3)重启模块,模块进入组网模式 AT+Z
- (4)此时我们将多个模块按照这种方式进行设置,当一个模块串口发送数据时,周围靠近的模块就会收到, 然后将其输出到串口,并且将数据再发送给周围未收到数据的模块,依次类推。
- (5)当收到数据的设备需要回复时直接串口发送,最终第一次发送的模块会收到回复,完成网络内部通讯。

更多Android进阶学习资料 请点击免费领取

进阶篇

蓝牙

BLE分为三部分:
  • Service

  • Characteristic

  • Descriptor

    这三部分都用UUID作为唯一标识符。UUID为这种格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3个Service,那么就有三个不同的UUID与Service对应。这些UUID都写在硬件里,我们通过BLE提供的API可以读取到。

  • 一个BLE终端可以包含多个Service, 一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个Value。Characteristic是比较重要的,是手机与BLE终端交换数据的关键,读取设置数据等操作都是操作Characteristic的相关属性。

API相关介绍

  • 1.先介绍一下关于蓝牙4.0中的一些名词吧: (1)GATT(Gneric Attibute Profile)

    通过ble连接,读写属性类小数据Profile通用的规范。现在所有的ble应用Profile 都是基于GATT

    • (2)ATT(Attribute Protocal) GATT是基于ATT Potocal的ATT针对BLE设备专门做的具体就是传输过程中使用尽量少的数据,每个属性都有个唯一的UUID,属性chartcteristics and Service的形式传输。
    • (3)Service是Characteristic的集合。
    • (4).Characteristic 特征类型。

比如。有个蓝牙ble的血压计。他可能包括多个Servvice,每个Service有包括多个Characteristic

注意:蓝牙ble只能支持Android 4.3以上的系统 SDK>=18
  • 1
  • 2.以下是开发的步骤:

  • 2.1首先获取BluetoothManager

  • 2.2获取BluetoothAdapter

  • 2.3创建

  • 2.4.开始搜索设备。

  • 2. 描述了一个蓝牙设备 提供了getAddress()设备Mac地址,getName()设备的名称。

  • 2.6开始连接设备

  • 2.7连接到设备之后获取设备的服务(Service)和服务对应的Characteristic。

  • 2.8获取到特征之后,找到服务中可以向下位机写指令的特征,向该特征写入指令。

  • 2.9写入成功之后,开始读取设备返回来的数据。

  • 2.10、断开连接

  • 2.11、数据的转换方法

大概整体就是如上的步骤。但是也是要具体根据厂家的协议来实现通信的过程。

那么具体要怎么使用呢?我们据需开车往下走。

一.添加权限

和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:

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

  • 1
  • 2
  • 3

除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:

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

  • 1
  • 2

按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:

// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, .ble_not_supported, Toast.LENGTH_SHORT).show();
    finish();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
第一步:开启蓝牙:
  • 1.首先获取有BluetoothAdapter两种方式:
private BluetoothManager bluetoothManager;

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

  • 1
  • 2
  • 3
  • 4
  • 5

或者是:

mBluetoothAdapter = ();

  • 1
  • 2

两行方式都是可以的。

注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。

  • 2.判断手机设备是否有蓝牙模块
// 检查设备上是否支持蓝牙
        if (mBluetoothAdapter == null) {
            showToast("没有发现蓝牙模块");
            return;
        }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 3.开启蓝牙设备

    开启蓝牙设备有两种方式:

    • 第一种直接简单暴力不给用户进行提示:
if (!()) {
            mBluetoothAdapter.enable();
}

  • 1
  • 2
  • 3
  • 4
  • 第二种直优雅的践行开启并且有弹框进行提示,隐式启动Intent:
if (mBluetoothAdapter == null || !()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 4.扫描蓝牙设备

    我这里是把扫描到的BLE地址存放到List集合中去。这里我们可以写一个方法进行封装一下。

/***********
     * 扫描设备
     ********/
    private void scanLeDevice(final boolean enable) {
        if (.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            if (enable) {
                devices.clear();//清空集合
                // Stops scanning after a pre-defined scan period.
                (new Runnable() {
                    @Override
                    public void run() {
                        if (.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                            mBluetoothAdapter.stopLeScan(mLeScanCallback);
                        }
                    }
                }, INTERVAL_TIME);
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                try {
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                } catch (Exception e) {
                }
            }
        }
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这个扫描方法中,我们在AndroidStudio或者是Eclipse中会看到startLeScan方法会有横线,表明这个方式显示过期的方法,那么

如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], )方法。 其中UUID数组指定你的应用程序所支持的GATT Services的UUID。

那么LeScanCallback的初始化代码如下:

private void initCallBack(){
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (device != null) {
                                if (!TextUtils.isEmpty(device.getName())) {
                                   // (device);
                                    String name = device.getName();
                                    if (name.contains(BluetoothDeviceAttr.OYGEN_DEVICE_NAME)) {
                                        if (!devices.contains(device)) {
                                            devices.add(device);
                                        }
                                    }
                                }
                            }
                        }
                    });
                }
            };
        } else {
            getToast("设备蓝牙版本过低");
            return;
        }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

那么如果在设备多的情况下我们讲搜出很多的设备。我们可以选择我们所需要的地址进行链接。但是这类要注意的是:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索.

  • 5.进行链接设备
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);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这里调用的是device的connectGatt方法

/**
     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
     * The callback is used to deliver results to Caller, such as connection status as well
     * as any further GATT client operations.
     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
     * GATT client operations.
     * @param callback GATT callback handler that will receive asynchronous callbacks.
     * @param autoConnect Whether to directly connect to the remote device (false)
     *                    or to automatically connect as soon as the remote
     *                    device becomes available (true).
     * @throws IllegalArgumentException if callback is null
     */
    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
                                     BluetoothGattCallback callback) {
        return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

api中阐述的是第一个参数是上下文对象Context,第二个参数是是否自动连接,第三个是蓝牙的GattCallback回调。

private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
    // 这里有9个要实现的方法,看情况要实现那些,用到那些就实现那些
    //当连接状态发生改变的时候
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){
        
    };
    //回调响应特征写操作的结果。
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
        
    };
    //回调响应特征读操作的结果。
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    }
    //当服务被发现的时候回调的结果
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    }
    当连接能被被读的操作
    @Override
   public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            
            (gatt, descriptor, status);
      }  
    ......
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

连接的过程我们一个通过service来进行连接,也可以在activity中进行操作。 好,到此为止,一个BLE蓝牙连接设备的整个流程我们已经清楚完毕。

的蓝牙不太成熟性

但是在实际操作过程中难免会出现一些比较坑人的问题。比如我用一个地址进行蓝牙设备连接,偶尔会出现蓝牙连接不上或者是说连接上设备后不返回数据等问题。那么此时我们可能会重启一下蓝牙或手机就立马有成功了。此时我们千万不能蒙蔽,也不要怀疑自己的人生。这是因为的蓝牙还是不太成熟。目前可以来说是个测试阶段。

  • 手机可能会搜索不到蓝牙设备
  • 有时候会在广播中接收不到数据
  • 出现异常需要重新启动手机或者是重启才能恢复正常

这个时候我们怎么办呢?如何去优化呢?那么我们就应该从UI界面,用户体验上进行操作来实现

  • 做一个定时器,如果在在确定蓝牙设备一打开并且存在的情况系,可以在手机搜索5s内没有搜索到蓝牙设备时重启蓝牙,并且在广播中接收到蓝牙开启后再次搜索

  • 可以在UI上进行对用户进行相对应的提示

    • 当蓝牙为启动时,提示用户去开启器蓝牙
    • 当蓝牙开启后,在处在开启状态后,提示用户蓝牙正在开启…
    • 蓝牙已开启,设备并没有连接上,提示用户去进行连接
    • 设备正在连接上手机,提示用户,正在连接,请等待…
    • 蓝牙设备连接上手机,正在读取,提示数据正在读取中…

我们不能子在Android系统上来操作什么,我们在体验上做到了我们能做的就可以的。

手机蓝牙连接BLE设备要求
  • 手机Android 4.3以上的系统 SDK>=18
  • 蓝牙版本>=4.0