zoukankan      html  css  js  c++  java
  • 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

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

    嘿嘿嘿~

    大家加油啦~~

  • 相关阅读:
    通过AOP引入Log4j
    Spring和Spring MVC框架进行单元测试
    JAVA异常基本知识及异常在Spring框架中的整体解决方案
    JAVA基础之重载,覆盖/重写,多态
    JAVA基础之内存
    JAVA基础之数组
    软件设计模式的原则
    ecstore 新增模块(页面)
    gitstack 密码重置
    thinkphp3.2整合workerman 多入口模式(windows)
  • 原文地址:https://www.cnblogs.com/wobeinianqing/p/5883135.html
Copyright © 2011-2022 走看看