android蓝牙4.0的知识要点

蓝牙4.0

这次主要讲解蓝牙4.0的基本要点,作为自己的备忘录记录下来吧。首先普及一下蓝牙4.0基于Gatt协议来实现。而蓝牙4.0以下的是传统蓝牙,基于socket方式来实现。所以4.0以上的蓝牙具有传输速度更快,覆盖范围更广,安全性更高,延迟更短,耗电极低等等优点。

一个BLE终端可以包含多个Service, 一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个Value。Characteristic是比较重要的,是手机与BLE终端交换数据的关键,读取设置数据等操作都是操作Characteristic的相关属性。
接下来就是代码部分:
1.首先是声明权限:

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

如果你想声明你的应用程序只能在支持BLE的设备上运行,可以将下面声明包含进你的应用程序manifest文件中:

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

2.其次获取蓝牙适配器:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();也可以用

 BluetoothManager  mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
 BluetoothAdapter  mBluetoothAdapter = mBluetoothManager.getAdapter();

当mBluetoothAdapter==null的时候就说明手机没有开蓝牙,此时我们可以通过调用系统的蓝牙打开窗口打开蓝牙,如下

Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);```
再通过
 ``` @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        
    }```
回调看时候开启成功。
3.接着就是查找蓝牙了。查找蓝牙很简单,首先就是定义蓝牙查找获取设备的回调接口,如下:

private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
//device.getName();获取蓝牙设备名字
//device.getAddress();获取蓝牙设备mac地址
}
};然后使用mBluetoothAdapter .startLeScan(mLeScanCallback);开始搜索设备,每当有设备即通过回调onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)方法来输出设备数据信息。当你不想再搜索是可以使用mBluetoothAdapter.stopLeScan(mLeScanCallback);```来停止搜索。

4.有蓝牙设备信息了,下一步我们当然要连接蓝牙了,不然要这些信息也没用了。连接蓝牙也是很简单。建议蓝牙连接最好在后台service进行。假如你保存上面回调方法的BluetoothDevice对象,就直接可以运行BluetoothGatt mBluetoothGatt= device.connectGatt(this, false, mGattCallback);这代码进行连接,至于mGattCallback是什么下文会介绍。而BluetoothGatt这对象也很重要,后面发现服务读写设备等操作都是通过该对象。假如没有BluetoothDevice 对象只有蓝牙设备的mac地址也可以连接,这个可以先像上面那样首先获取BluetoothAdapter蓝牙适配对象,BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(intent.getStringExtra("mac"));再通过getRemoteDevice()方法也可以BluetoothDevice 对象然后再像上面那样连接也可以。
上面连接代码中出现的mGattCallback对象,这个是什么呢?它是蓝牙连接,读取设备,往设备里写数据及设备发出通知等都会回调该接口方法,具体如下:

private final BluetoothGattCallback mGattCallback=new BluetoothGattCallback() {
       
        //当连接上设备或者失去连接时会回调该函数
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if(newState== BluetoothProfile.STATE_CONNECTED){
                Log.e("log_state","连接成功");
                mBluetoothGatt.discoverServices();
            }else if(newState==BluetoothProfile.STATE_DISCONNECTED){
                Log.e("log_state","连接失败");
            }
            super.onConnectionStateChange(gatt, status, newState);
        }
        
        //当设备是否找到服务时,会回调该函数
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {   //找到服务了
                //在这里可以对服务进行解析,寻找到你需要的服务
            } 
        }

         //设备发出通知时会调用到该接口
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.e("log_change","发送通知");
        }

       //当读取设备时会回调该函数
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //读取成功
                Log.e("log_read",characteristic.getValue()[0]+"");
            }else{
              //读取失败
            }

        }
        
      //当向Characteristic写数据时会回调该函数
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            if(status == BluetoothGatt.GATT_SUCCESS){
              //写入成功
            }else{
              //写入失败
            }
        }

      @Override //当向设备Descriptor中写数据时,会回调该函数
    public void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {
          super.onDescriptorRead(gatt, descriptor, status);
    }

    };

这是整个蓝牙核心的回调方法,因为你所有的蓝牙操作都离不开这个方法。当我们调用connectGatt()方法进行连接,首先会回到onConnectionStateChange(BluetoothGatt gatt, int status, int newState);方法看是否已经连接成功,接入成功newState==BluetoothProfile.STATE_CONNECTED;此时我们就可以用 mBluetoothGatt.discoverServices();方法找出该设备中的服务了。当蓝牙设备服务查找完之后就会回调
onServicesDiscovered(BluetoothGatt gatt, int status);方法此时你就可以遍历出蓝牙设备的所有服务,例如方法如下:

private void displayGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null)
            return;
        for (BluetoothGattService gattService : gattServices) {
           // 遍历出gattServices里面的所有服务
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { 
            // 遍历每条服务里的所有Characteristic 
               if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(需要通信的UUID)) {
                    // 有哪些UUID,每个UUID有什么属性及作用,一般硬件工程师都会给相应的文档。我们程序也可以读取其属性判断其属性。
                    // 此处可以可根据UUID的类型对设备进行读操作,写操作,设置notification等操作
                    // BluetoothGattCharacteristic gattNoticCharacteristic 假设是可设置通知的Characteristic
                    // BluetoothGattCharacteristic gattWriteCharacteristic 假设是可读的Characteristic
                    // BluetoothGattCharacteristic gattReadCharacteristic  假设是可写的Characteristic
               }
            }
        }
    }

到这一步,你就需要硬件工程师给你提供关于这个蓝牙设备的UUID文档,每个UUID的功能和操作都需要文档提供,不然你也不知道这些UUID具体代表什么功能和怎么用。当你知道UUID的意思,你就可以通过BluetoothGattCharacteristic 这个类进行各种读写操作。

5.当你从文档看到遍历出来的UUID有接送通知的功能。这时你就可以设置可以接收通知。代码如下:

public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
        if (descriptor != null) {
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
}

通过拿到对应通知UUID的BluetoothGattCharacteristic,调用setCharacteristicNotification().其中00002902-0000-1000-8000-00805f9b34fb是系统提供接受通知自带的UUID,通过设置BluetoothGattDescriptor相当于设置BluetoothGattCharacteristic的Descriptor属性来实现通知,这样只要蓝牙设备发送通知信号,就会回调onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) 方法,这你就可以在这方法做相应的逻辑处理。

6。还是当你遍历的UUID服务中关于写数据到设备已达到控制设备的UUID是,你可以保存对应的BluetoothGattCharacteristic对象。然后向BluetoothGattCharacteristic对象写入数据,在通过
BluetoothGatt调用writeCharacteristic()方法即可向硬件写入数据,例如下代码:

sendCharacteristic.setValue(new byte[] {0x00});
mBluetoothGatt.writeCharacteristic(sendCharacteristic);

其中一般硬件里读出写入的数据为二进制类型,所以要熟悉整型,字符串,二进制,十六进制等它们之间的转换。至于写什么数据看硬件工程师的文档。

7.有写就有读,从蓝牙设备读数据也不难。首先还是从遍历的UUID中找到关于读取蓝牙设备数据的UUID,具体哪个UUID还是要看硬件文档。然后还是保存对应的BluetoothGattCharacteristic对象。当要读取时直接用运行BluetoothGatt的readCharacteristic(BluetoothGattCharacteristic characteristic);参数里的characteristic就是你保存的BluetoothGattCharacteristic对象,如mBluetoothGatt.readCharacteristic(getCharacteristic);然后就会回调上面的onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status);方法,最后当status == BluetoothGatt.GATT_SUCCESS时,即可通过characteristic.getValue();方法获取蓝牙设备返回的数据,你拿到数据剩下就是你的逻辑处理了。

至此,蓝牙4.0的关键知识就写完了,你掌握这些就可以连接蓝牙设备做很多事了,当然前提是要有蓝牙的硬件文档,不然你也不知道那些UUID是什么意思要怎么用。如果对你有帮助就请给我给喜欢吧,谢谢。

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

推荐阅读更多精彩内容