首页 > 代码库 > Android BLE 蓝牙编程(三)

Android BLE 蓝牙编程(三)

上节我们已经可以连接上蓝牙设备了。

本节我们就要获取手环的电池电量和计步啦。

在介绍这个之前我们需要先了解下什么是 服务 什么是 UUID

我们记得上节中我们item监听事件的回调的返回值是BluetoothGatt 类型的,还记得么?嘿嘿。

返回的bluetoothgatt中包含一个或多个BluetoothGattService(服务)

每个service包含一个或多个characteristic(特征值)

每个特征值包含一个value 和多个 descriptor(注意看啊!是一个value)

这些对于本项目来说某个特征值的value中就包含了记录的步数。(很遗憾我折腾了很久也没找到电池电量,不得不舍弃展示电池电量的想法)

先熟悉下下面的图片吧~~

技术分享

(百度脑图)

在了解下UUID 上图中每个蓝牙设备都有自己的MAC 地址有了这个地址 我们就可以连接这个设备。

连接上设备后会的到设备的服务就是上图中的Gattservice 这每个service都有个固定的UUID以标识区分

每个service又包含多个的characteristic 这些特征值也有唯一的UUID 这些UUID就是我们编程需要的,

获取到characteristic对应的UUID就意味着获取到该characteristic提供的功能或者数据。

特征值对应的UUID所实现的功能是由硬件工程师决定的。

因为小米手环的硬件工程师我们没有联系方式,况且人家也肯定不会告诉我所有功能对应的UUID

因此我们只好自己对应数值来找了。

 

简单说 上图的每个characteristic 都对应一个UUID 这些UUID对应了设备的不同功能

手环为例:

控制手环震动的 UUID :00002a06-0000-1000-8000-00805f9b34fb   手机向该 UUID 写入 0x01 或者 0x02 时手环都会震动,01强度弱于 02

计步的     UUID :0000ff06-0000-1000-8000-00805f9b34fb     读取该UUID下的value数组 第0 个数据就是 步数

 

首先我们来获取下计步数吧

 经过一番折腾我终于找到了小米手环对应步数的 UUID :0000ff06-0000-1000-8000-00805f9b34fb

gattcallback 回调方法中找到 onServicesDiscovered

添加如下代码:

 @Override        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            super.onServicesDiscovered(gatt, status);            //寻找到服务时            if (status == bluetoothGatt.GATT_SUCCESS) {                final List<BluetoothGattService> services = bluetoothGatt.getServices();                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        //List<String> serlist = new ArrayList<>();                        for (final BluetoothGattService bluetoothGattService : services) {                            bluetoothGattServices = bluetoothGattService;                            Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid());                            List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics();                            for (BluetoothGattCharacteristic charac : charc) {                                Log.i(TAG, "run: " + charac.getUuid());                                //找到透传特征值                                // 00002a06-0000-1000-8000-00805f9b34fb 小米手环震动特征值 0x01震动 0x02强震                                if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) {                                    //设备 震动特征值                                    characteristic_zd = charac;                                } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) {                                    //设备 步数                                    characteristic_jb = charac;                                    bluetoothGatt.readCharacteristic(characteristic_jb);                                    Log.i(TAG, "run: 正在尝试读取步数");                                } else if (charac.getUuid().toString().equals("")) {                                    //设备 电量特征值                                }                            }                            serviceslist.add(bluetoothGattService.getUuid().toString());                        }                    }                });            }        }

注释写的很清楚

我用 characteristic_zd 记住震动的特征值

 用 characteristic_jb  记住计步的

记住计步特征值后使用 bluetoothGatt 提供的read方法并传人相应特征值。该方法为异步方法他的返回内容会由

回调中的 onCharacteristicRead 方法接收到

找到该方法添加如下代码:

if (status == bluetoothGatt.GATT_SUCCESS) {                final int sum = characteristic.getValue()[0];                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        jibu.setText("走了" + sum + "步");                    }                });                Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]);            }

方法的参数中status表示状态,为 bluetoothGatt.GATT_SUCCESS 时表示成功获取返回

因为在异步方法中,想要操作UI线程,于是就用了 runOnUiThread 方法。显示出来步数即可。

好了下面贴出完整主Activity代码:

MainActivity.java:

技术分享
package com.wbnq.shouhuan;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothGatt;import android.bluetooth.BluetoothGattCallback;import android.bluetooth.BluetoothGattCharacteristic;import android.bluetooth.BluetoothGattDescriptor;import android.bluetooth.BluetoothGattService;import android.bluetooth.BluetoothManager;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;import java.util.UUID;public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button saomiao, duanzhen, changzhen, buting, tingxia;    private TextView jibu, dianliang, lianjiezhuangtai;    private ListView list;    public static String TAG = "shouhuan-MainActivity";    BluetoothAdapter bluetoothAdapter;    BluetoothGatt bluetoothGatt;    List<BluetoothDevice> deviceList = new ArrayList<>();    List<String> serviceslist = new ArrayList<String>();    BluetoothDevice bluetoothDevice;    BluetoothGattService bluetoothGattServices;    BluetoothGattCharacteristic characteristic_zd, characteristic_jb;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        //蓝牙管理,这是系统服务可以通过getSystemService(BLUETOOTH_SERVICE)的方法获取实例        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);        //通过蓝牙管理实例获取适配器,然后通过扫描方法(scan)获取设备(device)        bluetoothAdapter = bluetoothManager.getAdapter();    }    private void initView() {        saomiao = (Button) findViewById(R.id.saomiao);        duanzhen = (Button) findViewById(R.id.zhendong);        changzhen = (Button) findViewById(R.id.changzhen);        buting = (Button) findViewById(R.id.buting);        tingxia = (Button) findViewById(R.id.tingxia);        list = (ListView) findViewById(R.id.list);        jibu = (TextView) findViewById(R.id.jibu);        dianliang = (TextView) findViewById(R.id.dianliang);        lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai);        saomiao.setOnClickListener(this);        duanzhen.setOnClickListener(this);        changzhen.setOnClickListener(this);        buting.setOnClickListener(this);        tingxia.setOnClickListener(this);        //item 监听事件        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {                bluetoothDevice = deviceList.get(i);                //连接设备的方法,返回值为bluetoothgatt类型                bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback);                lianjiezhuangtai.setText("连接" + bluetoothDevice.getName() + "中...");            }        });    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.saomiao:                //开始扫描前开启蓝牙                Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);                startActivityForResult(turn_on, 0);                Toast.makeText(MainActivity.this, "蓝牙已经开启", Toast.LENGTH_SHORT).show();                Thread scanThread = new Thread(new Runnable() {                    @Override                    public void run() {                        Log.i("TAG", "run: saomiao ...");                        saomiao();                    }                });                scanThread.start();                lianjiezhuangtai.setText("正在扫描");                break;            case R.id.zhendong:                break;            case R.id.changzhen:                break;            case R.id.buting:                break;            case R.id.tingxia:                break;            case R.id.list:                break;        }    }    public void saomiao() {        deviceList.clear();        bluetoothAdapter.startLeScan(callback);    }    //扫描回调    public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() {        @Override        public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) {            Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState());            //重复过滤方法,列表中包含不该设备才加入列表中,并刷新列表            if (!deviceList.contains(bluetoothDevice)) {                //将设备加入列表数据中                deviceList.add(bluetoothDevice);                list.setAdapter(new MyAdapter(MainActivity.this, deviceList));            }        }    };    private BluetoothGattCallback gattcallback = new BluetoothGattCallback() {        @Override        public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) {            super.onConnectionStateChange(gatt, status, newState);            runOnUiThread(new Runnable() {                @Override                public void run() {                    String status;                    switch (newState) {                        //已经连接                        case BluetoothGatt.STATE_CONNECTED:                            lianjiezhuangtai.setText("已连接");                            bluetoothAdapter.stopLeScan(callback);                            //该方法用于获取设备的服务,寻找服务                            bluetoothGatt.discoverServices();                            break;                        //正在连接                        case BluetoothGatt.STATE_CONNECTING:                            lianjiezhuangtai.setText("正在连接");                            break;                        //连接断开                        case BluetoothGatt.STATE_DISCONNECTED:                            lianjiezhuangtai.setText("已断开");                            break;                        //正在断开                        case BluetoothGatt.STATE_DISCONNECTING:                            lianjiezhuangtai.setText("断开中");                            break;                    }                    //pd.dismiss();                }            });        }        @Override        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            super.onServicesDiscovered(gatt, status);            //寻找到服务时            if (status == bluetoothGatt.GATT_SUCCESS) {                final List<BluetoothGattService> services = bluetoothGatt.getServices();                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        //List<String> serlist = new ArrayList<>();                        for (final BluetoothGattService bluetoothGattService : services) {                            bluetoothGattServices = bluetoothGattService;                            Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid());                            List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics();                            for (BluetoothGattCharacteristic charac : charc) {                                Log.i(TAG, "run: " + charac.getUuid());                                //找到透传特征值                                // 00002a06-0000-1000-8000-00805f9b34fb 小米手环震动特征值 0x01震动 0x02强震                                if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) {                                    //设备 震动特征值                                    characteristic_zd = charac;                                } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) {                                    //设备 步数                                    characteristic_jb = charac;                                    bluetoothGatt.readCharacteristic(characteristic_jb);                                    Log.i(TAG, "run: 正在尝试读取步数");                                } else if (charac.getUuid().toString().equals("")) {                                    //设备 电量特征值                                }                            }                            serviceslist.add(bluetoothGattService.getUuid().toString());                        }//                        ArrayAdapter<String> adapter = new ArrayAdapter<String>(//                                MainActivity.this, android.R.layout.simple_expandable_list_item_1, serviceslist);                        //list.setAdapter(adapter);                    }                });            }        }        @Override        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {            super.onCharacteristicRead(gatt, characteristic, status);            if (status == bluetoothGatt.GATT_SUCCESS) {                final int sum = characteristic.getValue()[0];                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        jibu.setText("走了" + sum + "步");                    }                });                Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]);            }        }        @Override        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {            super.onCharacteristicWrite(gatt, characteristic, status);        }        //获取返回 数据        @Override        public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {            super.onCharacteristicChanged(gatt, characteristic);            Log.i(TAG, "onCharacteristicChanged: 获取回调方法");            Log.e("", "命令:" + HexUtil.encodeHexStr(characteristic.getValue()));            final byte[] values = characteristic.getValue();            runOnUiThread(new Runnable() {                @Override                public void run() {                    Toast.makeText(MainActivity.this, HexUtil.encodeHexStr(values), Toast.LENGTH_SHORT).show();                }            });        }    };    private boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) {        if (bluetoothGatt == null || characteristic == null)            return false;        if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable))            return false;        BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));        if (clientConfig == null)            return false;        if (enable) {            clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);        } else {            clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);        }        return bluetoothGatt.writeDescriptor(clientConfig);    }}
View Code

今天就写这些,下次要实现震动方法咯!是不是很激动呢~~

嘿嘿嘿~

大家加油啦~~

 

Android BLE 蓝牙编程(三)