• 【Android应用开发】Android 蓝牙低功耗 (BLE) ( 第一篇 . 概述 . 蓝牙低功耗文档 翻译)


    转载请注明出处 http://blog.csdn.net/shulianghan/article/details/50515359


    參考 : 

    -- 官方文档 : https://developer.android.com/guide/topics/connectivity/bluetooth-le.html;






    1. 概述


    BLE 概述

    -- 版本号支持Android 4.3 (API Level 18) 内置框架引入了 蓝牙低功耗方案 (Bluetooth Low Energy, BLE) 支持; 

    -- 角色支持 : Android 手机仅仅能作为 主设备 (central role), 开发人员开发的 APP 能够使用其提供的 API 接口, 用于 发现设备, 遍历服务 (services),  读写服务中的特性 (characteristics). 

    -- 传统蓝牙对照 : 与传统的蓝牙对照, 蓝牙低功耗方案 (Bluetooth Low Energy) 是出于更低的电量消耗考虑而设计的. 这能够使 Android 应用能够与 BLE 设备进行交流, 这些设备须要非常低的电量, 如 近距离传感器, 心率測量设备, 健康设备 等等.



    2. 关键术语 和 概念



    (1) Generic Attribute Profile (GATT) 通用属性规范


    Generic Attribute Profile (GATT) 通用属性规范 : 

    -- GATT 作用 : GATT 规范是一个针对 在 BLE 连接上的, 发送 和 接收 少量数据的一个规范, 全部的现有的低功耗应用的规范都是基于这个 GATT 规范制定的.

    -- 制定者 : 蓝牙技术联盟 (Bluetooth SIG) 为低功耗设备定义了很多规范, 一个 规范 (Profile) 就是 设备怎样在特定的应用中工作的详述. 

    -- 设备规范相应关系 : 此外, 一个设备能够实现多个规范, 如 : 一个设备能够包括一个心率检測器, 和 电量检測器.



    (2) Attribute Protocol (ATT) 属性协议


    Attribute Protocol (ATT) 属性协议

    -- ATT 与 GATT 关系 : GATT 规范是建立在 ATT 的上一层的, 这套改改通常被称为 GATT/ATT. 

    -- ATT 作用 : ATT 被用于优化 BLE 设备的执行, 为了这个目的, ATT (属性协议) 使用尽可能少的字节. 

    -- ATT 唯一标识 : ATT 中的每一个属性都被 一个 UUID (Universally Unique Identifier) 独一无二的进行标识, UUID 是一个 128 比特的标准的字符串 ID, 用于信息的唯一标识. 

    -- ATT 属性 : ATT 中定义的属性就是 Charicteristics (特性) 和 Services (服务);



    (3) Characteristic 特性


    Characteristic 特性

    -- Characteristic 概念 : 一个 Characteristic 特性包括了一个值 和 多个 Descriptor (描写叙述符) 用于描写叙述这个特性的值. 

    -- 本质 : 一个特性能够被觉得是一个类型, 相似于一个类.



    (4) Descriptor 描写叙述符


    Descriptor 描写叙述符

    -- 作用 : 描写叙述符 被定义为一些属性, 这些属性用于描写叙述 Characteristic (特性) 的值. 

    -- 演示样例 : 比如, 一个 描写叙述符 能够说明一个 可读的描写叙述, 一个 特性值的可接受范围, 或者 一个特性值的測量单元.



    (5) Service 服务


    Service 服务

    -- 服务本质 : 服务是 Characteristic (特性) 的集合. 

    -- 演示样例 : 如, 你能够有一个 名称为 "Heart Rate Monitor (心率监控)" 的服务, 包括了特性 "Heart Rate Measurement (心率測量)". 

    -- 參考资料 : 你能够在 bluetooth.org 官网查询到一个基于 GATT 服务 和 规范的列表.



    3. 角色 和 职责



    (1) 四种角色


    Android 设备 与 BLE 设备互动时, 设备的角色 和 职责

    -- 中心设备 和 外围设备 : 这个角色体系适用于 BLE 连接. 中心设备角色 能够扫描, 查找广播. 外围设备角色 发送广播.

    -- GATT server 和 GATT client : 这个决定了两个设备之间, 一旦建议连接后, 怎样进行互相通信.



    (2) 中心设备 和 外围设备


    BLE 连接须要两种设备都存在 : 为了理解当中的差别, 想象一下 你有一个 Android 设备 和 一个激活的 智能腕表 蓝牙设备. 手机支持作为 中心设备 角色, 智能腕表 蓝牙设备支持作为外围设备角色, 为了建立 BLE 连接, 仅仅有外围设备 或者 仅仅有 中心设备 都不能建立 BLE 连接.



    (3) GATT server 和 GATT client


    GATT server 和 GATT client 简单介绍

    -- GATT server 和 GATT client 角色不是固定的 : 一旦手机 和 智能腕表 设备建立了 BLE 连接, 它们開始互相交换 GATT 元数据. 依据它们之间传输的数据类型, 当中的一个会扮演 GATT server的角色. 

    -- 角色改变演示样例 : 假设 智能腕表 设备想要向手机报告传感器数据, 那么智能腕表必须当做 GATT server. 假设智能腕表 想要从手机上接受更新数据, 那么 Android 手机就是 GATT server.

    -- 手机 和 设备 都能够作为 GATT server 和 client : 在本文档中使用的演示样例代码, 在 Android 设备上执行的 Android APP 就是 GATT client, BLE 外围设备 就是 GATT server. Android APP 从 GATT server上获取数据, server的 BLE "heart rate monitor (心率监測)" 支持 "Heart Rate Profile (心率规范 - 一种 BLE 蓝牙标准规范)". Android APP 也能够作为 GATT server;



    4. BLE 权限


    (1) 蓝牙权限简单介绍


    Android 蓝牙权限简单介绍

    -- 权限作用 : 为了在应用中使用蓝牙功能, 必须在 AndroidManifest.xml 中 声明蓝牙权限. 全部的蓝牙通信操作都须要 蓝牙权限 来同意执行, 比如 搜索蓝牙, 蓝牙连接, 数据交互等操作.

    -- 搜索设置蓝牙权限 : 假设 APP 要发起设备搜索 或者 管理 蓝牙设置, 须要 提前声明 BLUETOOTH_ADMIN 权限. 

    -- 注意 : 使用 BLUETOOTH_ADMIN 权限的前提是 必须声明 BLUETOOTH 权限.



    (2) 蓝牙权限简单介绍


    蓝牙权限演示样例

    -- AndroidManifest.xml 声明蓝牙权限演示样例

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

    -- 充当 BLE 设备权限 : 假设你的 APP 仅仅须要胜任 BLE 设备的工作, 仅仅须要例如以下配置 : 

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



    (3) 动态控制 BLE 功能是否使用


    动态控制 BLE 是否可用 : 无论怎样, 假设你想要让你的 APP 能够当做 BLE 设备, 可是手机不支持这个操作, 你仍然能够进行例如以下配置, 仅仅是将当中的 android:required 设置成 false. 此时在执行时, 你能够使用 "PackageManager.hasSystemFeature()" 方法决定 BLE 是否可用.

    //使用以下的函数决定 设备上的 BLE 功能 是否可用
    //此时你能够选择性的关闭 BLE 相关的功能
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
        finish();
    }



    5. 创建 BLE


    (1) 创建 BLE 简单介绍


    创建 BLE 简单介绍

    -- 验证 BLE 功能 : 在应用能够通过 BLE 交互之前, 你须要验证设备是否支持 BLE 功能, 假设支持, 确定它是能够使用的. 

    -- 注意 : 这个检查仅仅有在 以下的配置 设置为 false 时才是必须的;

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

    -- 不支持 BLE 关闭相关功能 : 假设 Android 手机不支持 BLE 功能, 你应该优雅的 关闭 BLE 相关功能. 

    -- 支持 BLE 打开蓝牙 : 假设 BLE 支持 BLE 功能, 可是设备的蓝牙是关闭的, 你能够在应用中请求打开设备的蓝牙模块. 

    -- 步骤总结 : 创建 BLE 蓝牙的过程分成两个步骤, 1. 获取 BluetoothAdapter, 2. 打开 设备的蓝牙模块.



    (2) 获取 BluetoothAdapter (蓝牙适配器)


    获取 BluetoothAdapter 蓝牙适配器

    -- BluetoothAdapter 类作用 : 全部的蓝牙活动都须要 BluetoothAdapter, BluetoothAdapter 代表了设备本身的蓝牙适配器 (蓝牙无线设备). 整个系统中仅仅有一个 蓝牙适配器, 应用能够使用 BluetoothAdapter 对象与 蓝牙适配器硬件进行交互. 

    -- 获取 BluetoothAdapter 代码演示样例

    // 初始化蓝牙适配器
    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();

    -- 注意 : 这种方法使用了 getSystemService() 方法, 返回了一个 BluetoothManager 实例对象, 从 BluetoothManager 实例对象中能够获取 BluetoothAdapter 对象;



    (3) 打开蓝牙功能


    打开蓝牙

    -- 检查是否可用 : 为了保证 蓝牙功能是打开的, 调用 BluetoothAdapter 的 isEnable() 方法, 检查蓝牙在当前是否可用. 假设返回 false, 说明当前蓝牙不可用. 

    -- 演示样例代码

    private BluetoothAdapter mBluetoothAdapter;
    ...
    // 确认当前设备的蓝牙是否可用, 
    // 假设不可用, 弹出一个对话框, 请求打开设备的蓝牙模块
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }



    6. 查找 BLE 设备


    (1) 查找全部的 BLE 设备


    查找 BLE 设备

    -- 查找方法參数 : 为了搜索到 BLE 设备, 调用 BluetoothAdapter 的 startLeScan() 方法, 该方法须要一个 BluetoothAdapter.LeScanCallback 类型的參数. 你必须实现这个 LeScanCallback 接口, 由于 BLE 蓝牙设备扫描结果在这个接口中返回. 

    -- 查找策略 : 蓝牙搜索是非常耗电的, 你须要遵守以下的 中断策略 和 不循环策略.

    -- 中断策略 : 仅仅要一发现蓝牙设备, 立即中断扫描.

    -- 不循环策略 : 不要循环扫描, 设置一个扫描的最大时间限制. 一个设备在之前可用, 继续扫描可能会使设备不可用, 此外继续扫描会持续浪费电池电量.

    -- 源代码演示样例

    /**
     * 搜索 和 展示 可用的蓝牙设备 的 Activity 界面
     */
    public class DeviceScanActivity extends ListActivity {
    
        private BluetoothAdapter mBluetoothAdapter;
        private boolean mScanning;
        private Handler mHandler;
    
        // 10 秒后停止搜索
        private static final long SCAN_PERIOD = 10000;
        ...
        private void scanLeDevice(final boolean enable) {
            if (enable) {
                // 在一个预先定义的时间段后停止扫描.
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mScanning = false;
    					//開始扫描
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    }
                }, SCAN_PERIOD);
    
                mScanning = true;
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
            ...
        }
    ...
    }


    (2) 查找特定 BLE 设备


    查找特定 BLE 设备

    -- 方法调用 : 查找特定类型的外围设备, 能够调用以下的方法, 这种方法须要提供一个 UUID 对象数组, 这个 UUID 数组是 APP 支持的 GATT 服务的特殊标识.

    -- 演示样例

    startLeScan(UUID[], BluetoothAdapter.LeScanCallback)



    (3) BluetoothAdapter.LeScanCallback 回调接口


    扫描回调接口

    -- 接口作用 : BluetoothAdapter.LeScanCallback 实现类, 在这个实现类的接口中返回 BLE 设备扫描结果;

    -- 源代码演示样例

    private LeDeviceListAdapter mLeDeviceListAdapter;
    ...
    // 设备扫描回调接口
    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi,
                byte[] scanRecord) {
            runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   mLeDeviceListAdapter.addDevice(device);
                   mLeDeviceListAdapter.notifyDataSetChanged();
               }
           });
       }
    };


    (4) 设备扫描类型


    设备扫描类型 : 蓝牙设备扫描 在同一个时间扫描时, 仅仅能扫描 BLE 设备 或者 SPP 设备中的一种, 不能同一时候扫描两种设备.




    7. 连接到 GATT 服务


    (1) 连接指定 BluetoothDevice 蓝牙设备


    连接指定设备

    -- 连接到 GATT 服务 : 与 BLE 设备交互的第一步是 连接到 BLE 设备中的 GATT 服务. 

    -- 实现方法 : 调用 BluetoothDevice 的 connectGatt() 方法能够连接到 BLE 设备的 GATT 服务. 

    -- 參数解析 : connectGatt() 方法须要三个參数, 參数一 Context 上下文对象, 參数二 boolean autoConnect 是否自己主动连接扫描到的蓝牙设备, 參数三 BluetoothGattCallback 接口实现类. 

    -- 使用方法演示样例

    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

    -- 获取 BluetoothGatt 对象 : 调用 connectGatt() 方法能够连接到 BLE 设备上的 GATT 服务, 返回一个 BluetoothGatt 实例对象, 你能够使用这个对象去 管理 GATT client操作. 

    -- GATT client操作 : Android APP 能够调用 GATT Client (client). BluetoothGattCallback 能够用于传递结果到 GATT client, 如 连接状态 和 更进一步的 GATT Client 操作.



    (2) GATT 数据交互演示样例


    BLE 蓝牙数据交互

    -- 界面 : 在以下的演示样例中, BLE 应用提供了一个 Activity 界面, 该 Activity 界面用于 连接, 展示数据, 展示 GATT 服务 和 设备支持的特性. 

    -- BLE 蓝牙服务类 : 基于用户的输入, 这个 Activity 界面能够与一个 BluetoothLeService 的服务进行交流, 该交流的本质就是 BLE 设备的 GATT 服务 与 Android 的 BLE API 进行交流.

    -- BLE 蓝牙服务类 演示样例代码

    // BLE 设备能够通过该服务 与 Android 的 BLE API 进行互动
    public class BluetoothLeService extends Service {
        private final static String TAG = BluetoothLeService.class.getSimpleName();
    
        private BluetoothManager mBluetoothManager;
        private BluetoothAdapter mBluetoothAdapter;
        private String mBluetoothDeviceAddress;
        private BluetoothGatt mBluetoothGatt;
        private int mConnectionState = STATE_DISCONNECTED;
    
        private static final int STATE_DISCONNECTED = 0;
        private static final int STATE_CONNECTING = 1;
        private static final int STATE_CONNECTED = 2;
    
        public final static String ACTION_GATT_CONNECTED =
                "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
        public final static String ACTION_GATT_DISCONNECTED =
                "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
        public final static String ACTION_GATT_SERVICES_DISCOVERED =
                "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
        public final static String ACTION_DATA_AVAILABLE =
                "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
        public final static String EXTRA_DATA =
                "com.example.bluetooth.le.EXTRA_DATA";
    
        public final static UUID UUID_HEART_RATE_MEASUREMENT =
                UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
    
        // BLE API 中定义的不同的回调方法.
        private final BluetoothGattCallback mGattCallback =
                new BluetoothGattCallback() {
            @Override
    		// BLE 设备的状态改变 连接 断开
            public void onConnectionStateChange(BluetoothGatt gatt, int status,
                    int newState) {
                String intentAction;
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    intentAction = ACTION_GATT_CONNECTED;
                    mConnectionState = STATE_CONNECTED;
                    broadcastUpdate(intentAction);
                    Log.i(TAG, "连接到了 GATT 服务.");
                    Log.i(TAG, "尝试搜索服务:" +
                            mBluetoothGatt.discoverServices());
    
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    intentAction = ACTION_GATT_DISCONNECTED;
                    mConnectionState = STATE_DISCONNECTED;
                    Log.i(TAG, "于 GATT 服务断开连接.");
                    broadcastUpdate(intentAction);
                }
            }
    
            @Override
            // BLE 设备中 新的 GATT 服务被发现
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
                } else {
                    Log.w(TAG, "发现 GATT 服务 : " + status);
                }
            }
    
            @Override
            // 特性读取操作返回的数据
            public void onCharacteristicRead(BluetoothGatt gatt,
                    BluetoothGattCharacteristic characteristic,
                    int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                }
            }
         ...
        };
    ...
    }

    -- 广播发送 : 当一个特定的回调被触发, 它调用适当的 broadcastUpdate() 帮助方法, 将其当做一个 Action 操作传递出去. 

    -- 注意蓝牙心率 : 这部分的数据解析 与 蓝牙心率測量 是一起被执行的.

    -- 广播发送 演示样例代码

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }
    
    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
    
        // This is special handling for the Heart Rate Measurement profile. Data
        // parsing is carried out as per profile specifications.
    	// 心率监測规范的特殊处理
    	// 数据解析在每一个规范中完毕
        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
            int flag = characteristic.getProperties();
            int format = -1;
            if ((flag & 0x01) != 0) {
                format = BluetoothGattCharacteristic.FORMAT_UINT16;
                Log.d(TAG, "心率格式 UINT16.");
            } else {
                format = BluetoothGattCharacteristic.FORMAT_UINT8;
                Log.d(TAG, "心率格式 UINT8.");
            }
            final int heartRate = characteristic.getIntValue(format, 1);
            Log.d(TAG, String.format("接收到心跳检測 : %d", heartRate));
            intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
        } else {
    		// 对于其他的规范, 写出 HEX 十六进制格式的数据
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for(byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                intent.putExtra(EXTRA_DATA, new String(data) + "
    " +
                        stringBuilder.toString());
            }
        }
        sendBroadcast(intent);
    }

    -- 处理广播事件 : 在 DeviceControlActivity 中处理广播事件, 演示样例代码 : 

    // 处理 Service 发起的的不同事件
    // ACTION_GATT_CONNECTED: 连接到 GATT 服务.
    // ACTION_GATT_DISCONNECTED: 与 GATT 服务断开.
    // ACTION_GATT_SERVICES_DISCOVERED: 发现 GATT 服务.
    // ACTION_DATA_AVAILABLE: 从 BLE 设备中接收数据, 数据能够是 read 或者 notification 操作的结果.
    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)) {
                mConnected = true;
                updateConnectionState(R.string.connected);
                invalidateOptionsMenu();
            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                mConnected = false;
                updateConnectionState(R.string.disconnected);
                invalidateOptionsMenu();
                clearUI();
            } else if (BluetoothLeService.
                    ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                // 在用户界面 显示全部支持的服务 和 特性. 
                displayGattServices(mBluetoothLeService.getSupportedGattServices());
            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
            }
        }
    };



    8. 读取 BLE 属性


    读写属性简单介绍

    -- 读写属性前提 : Android 应用连接到了 设备中的 GATT 服务, 而且发现了 各种服务 (特性集合), 能够读写当中的属性. 

    -- 读写属性代码演示样例 : 遍历服务 (特性集合) 和 特性, 将其展示在 UI 界面中.

    public class DeviceControlActivity extends Activity {
        ...
        // 示范怎样通过其所支持的 GATT 遍历 服务 (Services) 和 特性 (Characteristics)
        // 在这个演示样例中, 我们将查询出的数据填充到 UI 界面中的 ExpandableListView 中
        private void displayGattServices(List<BluetoothGattService> gattServices) {
            if (gattServices == null) return;
            String uuid = null;
            String unknownServiceString = getResources().
                    getString(R.string.unknown_service);
            String unknownCharaString = getResources().
                    getString(R.string.unknown_characteristic);
            ArrayList<HashMap<String, String>> gattServiceData =
                    new ArrayList<HashMap<String, String>>();
            ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
                    = new ArrayList<ArrayList<HashMap<String, String>>>();
            mGattCharacteristics =
                    new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
    
            // 遍历 GATT 服务
            for (BluetoothGattService gattService : gattServices) {
                HashMap<String, String> currentServiceData =
                        new HashMap<String, String>();
                uuid = gattService.getUuid().toString();
                currentServiceData.put(
                        LIST_NAME, SampleGattAttributes.
                                lookup(uuid, unknownServiceString));
                currentServiceData.put(LIST_UUID, uuid);
                gattServiceData.add(currentServiceData);
    
                ArrayList<HashMap<String, String>> gattCharacteristicGroupData =
                        new ArrayList<HashMap<String, String>>();
    					
    			// 获取服务中的特性集合
                List<BluetoothGattCharacteristic> gattCharacteristics =
                        gattService.getCharacteristics();
                ArrayList<BluetoothGattCharacteristic> charas =
                        new ArrayList<BluetoothGattCharacteristic>();
    					
               // 循环遍历特性集合
                for (BluetoothGattCharacteristic gattCharacteristic :
                        gattCharacteristics) {
                    charas.add(gattCharacteristic);
                    HashMap<String, String> currentCharaData =
                            new HashMap<String, String>();
                    uuid = gattCharacteristic.getUuid().toString();
                    currentCharaData.put(
                            LIST_NAME, SampleGattAttributes.lookup(uuid,
                                    unknownCharaString));
                    currentCharaData.put(LIST_UUID, uuid);
                    gattCharacteristicGroupData.add(currentCharaData);
                }
                mGattCharacteristics.add(charas);
                gattCharacteristicData.add(gattCharacteristicGroupData);
             }
        ...
        }
    ...
    }




    9. 接收 GATT 通知


    GATT 通知简单介绍

    -- 特性改变通知 : 当 BLE 设备中的一些特殊的特性改变, 须要通知与之连接的 Android BLE 应用.

    -- 代码演示样例 : 使用 setCharacteristicNotification() 方法为特性设置通知.

    private BluetoothGatt mBluetoothGatt;
    BluetoothGattCharacteristic characteristic;
    boolean enabled;
    ...
    // 设置是否监听某个特性改变
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    ...
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
            UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    mBluetoothGatt.writeDescriptor(descriptor);

    -- 特性改变回调 : 一但特性开启了改变通知监听, 假设特性发生了改变, 就会回调 BluetoothGattCallback 接口中的 onCharacteristicChanged() 方法.

    @Override
    // 特性通知
    public void onCharacteristicChanged(BluetoothGatt gatt,
            BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }



    10. 关闭 APP 中的 BLE 连接



    关闭 BLE 设备连接

    -- 关闭方法 : 一旦结束了 BLE 设备的使用, 调用 BluetoothGatt 的 close() 方法, 关闭 BLE 连接, 释放相关的资源.

    -- 关闭演示样例

    public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }




    转载请注明出处 http://blog.csdn.net/shulianghan/article/details/50515359

  • 相关阅读:
    路由器链接
    quartz cron表达式demo
    mybatis xml中常见配置demo
    PLSQL启动很慢的问题
    oracle触发器--if else demo
    去掉redhat linux提示注册
    linux 关闭电子邮件传输服务
    max(length()) oracle字段最长长度
    事件tou
    事件
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7143356.html
Copyright © 2020-2023  润新知