Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一步一步实现Android低功耗蓝牙(BLE)基本开发

一步一步实现Android低功耗蓝牙(BLE)基本开发

作者头像
coderZhen
发布于 2018-10-08 03:02:16
发布于 2018-10-08 03:02:16
2.4K00
代码可运行
举报
文章被收录于专栏:Android开发经验Android开发经验
运行总次数:0
代码可运行

项目需要接入两个低功耗蓝牙设备(BLE),并且与之交互(读/写)数据,所以看了下官方对于这块儿的介绍,总结了一下BLE开发中一些需要注意的地方以及基本流程。

BLE开发需要Android 4.3 (API level 18) 及以上

一.添加权限 为了能正常使用蓝牙相关功能(扫描等),首先需要添加以下权限:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

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

在Android6.0及以上系统中,我们需要动态申请权限,这里推荐使用RxPermissions

简单介绍下RxPermissions如何引入。

1.在根build文件中添加代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
...

2.在对应moudle的build文件中添加依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...
dependencies {
    implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
}
...

3.使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
RxPermissions rxPermissions=new RxPermissions(this);
rxPermissions.request(Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(granted -> {
                    if (granted) {
                        //权限允许成功
                    }
                });

如果想了解RxPermissions更多用法,戳这里

二.判断设备是否支持蓝牙 这里有两种处理方式:

  • 如果你想让只有支持BLE的手机才能安装你的应用程序的话,可以在清单文件中添加如下内容,这样的话如果设备不支持BLE的话你的应用都装不上,当然这种方式不太友好:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
  • 在代码中判断当前设备是否支持BLE,以对用户做出反馈。 首先,在清单文件中声明需要使用BLE特性,不过required这里设置为false,然后在app运行时通过 PackageManager.hasSystemFeature()来判断设备是否支持ble:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
    finish();
}

三.扫描蓝牙设备 BLE设备的扫描由BluetoothManager对象提供方法来实现,有两个扫描方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public boolean startLeScan(BluetoothAdapter.LeScanCallback callback) {
        throw new RuntimeException("Stub!");
    }

    public boolean startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) {
        throw new RuntimeException("Stub!");
    }

第二个方法允许我们提供特定的UUID,来扫描特定的设备,扫描结果通过BluetoothAdapter.LeScanCallback接口回调给我们:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public interface LeScanCallback {
        /**
         * Callback reporting an LE device found during a device scan initiated
         * by the {@link BluetoothAdapter#startLeScan} function.
         *
         * @param device Identifies the remote device
         * @param rssi The RSSI value for the remote device as reported by the
         *             Bluetooth hardware. 0 if no RSSI value is available.
         * @param scanRecord The content of the advertisement record offered by
         *                   the remote device.
         */
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
    }

四.获取远程BLE设备 在扫描出设备以后,我们一般会选择某个扫描出来的设备,通过其地址获取一个远程的蓝牙设备对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address)

五.连接BLE设备的GATT服务 与BLE设备交互的第一步是连接到它,更具体地说,连接到设备上的GATT服务。要在BLE设备上连接到GATT服务,可以使用connectGatt()方法。该方法接受三个参数:一个上下文对象、autoConnect(布尔值表示是否在BLE设备可用时自动连接到该设备),以及对BluetoothGattCallback的引用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mBluetoothGatt = device.connectGatt(context, true, mGattCallback);

以上代码可以连接到由BLE设备托管的GATT服务,并返回一个BluetoothGatt实例,然后可以使用它来执行GATT客户端操作,例如写数据等。呼叫者(Android应用程序)是GATT客户端。连接状态,以及GATT的数据变化等通过BluetoothGattCallback接口回调给客户端(APP)。

一般使用BluetoothGattCallback的这些回调方法:

1.获取连接状态,在连接成功时扫描设备服务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                if (connectChangedListener != null) {
                    connectChangedListener.onConnected();
                }
                mConnectionState = STATE_CONNECTED;
                mBluetoothGatt.discoverServices();

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                if (connectChangedListener != null) {
                    connectChangedListener.onDisconnected();
                }
                mConnectionState = STATE_DISCONNECTED;
            }
        }

2.获取服务,特性等 一个BLE设备可能有多个服务BluetoothGattService,同样每个服务可以有多个BluetoothGattCharacteristic特性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                List<BluetoothGattService> services = mBluetoothGatt.getServices();
                for (int i = 0; i < services.size(); i++) {
                    HashMap<String, BluetoothGattCharacteristic> charMap = new HashMap<>();
                    BluetoothGattService bluetoothGattService = services.get(i);
                    String serviceUuid = bluetoothGattService.getUuid().toString();
                    List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics();
                    for (int j = 0; j < characteristics.size(); j++) {
                        charMap.put(characteristics.get(j).getUuid().toString(), characteristics.get(j));
                    }
                    servicesMap.put(serviceUuid, charMap);
                }
                BluetoothGattCharacteristic bluetoothGattCharacteristic = getBluetoothGattCharacteristic(UUID_SERVICE, UUID_CHARACTERISTIC);
                if (bluetoothGattCharacteristic == null)
                    return;
                enableGattServicesNotification(bluetoothGattCharacteristic);
            } else {
                Log.w(TAG, " --------- onServicesDiscovered received: " + status);
            }
        }

在上面的代码中,我们将BLE设备的所有BluetoothGattServiceBluetoothGattCharacteristic全部保存下来,但是在实际需求中,我们一般只会与某个特定BluetoothGattService中的某个特性BluetoothGattCharacteristic进行数据读写。判断条件就是这里的UUID_SERVICEUUID_CHARACTERISTIC,这两个UUID一般提供BLE设备的时候会一并提供给我们。

找到这个特定的BluetoothGattCharacteristic后,我们希望它发生改变时可以得到通知,可以使用setCharacteristicNotification()方法为特性设置通知:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(UUID_DESCRIPTOR));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);

3.监听数据变化 经过以上设置,我们就可以在onCharacteristicChanged回调方法中获取BLE设备发过来的数据了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            //解析数据
            parseData(characteristic);
        }

当然,我们也可以用第五步中获取的mBluetoothGatt来向BLE设备发送数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mBleGattCharacteristic.setValue(HexUtil.hexStringToBytes(value));
boolean b=mBluetoothGatt.writeCharacteristic(mBleGattCharacteristic);

以上,就是Android端与BLE设备通信的基本开发流程,这里我抽成了一个Demo,项目目录如下:

几点说明:

  • 因为我这里需求是接入两个BLE设备,所以我抽取了一个BluetoothLeDeviceBase,代表基类设备,将一些通用的属性和操作封装在了这里
  • BluetoothLeDeviceA,BluetoothLeDeviceB代表具体的某个BLE设备,每个设备可能有不同之处,例如数据解析方式等。

完整代码地址:https://github.com/SolveBugs/BlogPracticeDems,目前只是基本的封装,后续会继续完善。

选择bluetoothbledemo这个moudle运行即可,界面如下:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.09.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【最佳实践】巡检项:云数据库(Redis)跨可用区部署
相比于单可用区集群来说,腾讯云支持的多可用区集群提供更高的容灾能力,可有效的抵御可用区中断或者机房级别的故障。针对存量实例巡检发现的单可用区Redis集群,推荐升级至多可用区集群部署。
邵聪 SHAO CONG
2022/04/13
1.3K0
腾讯云数据库(Redis)监控最佳指南
简介 云数据库 Redis(TencentDB for Redis)是由腾讯云提供的兼容 Redis 协议的缓存数据库,具备高可用、高可靠、高弹性等特征。云数据库 Redis 服务兼容 Redis 2.8、Redis 4.0、Redis 5.0 版本协议,提供标准和集群两大架构版本。最大支持 4TB 的存储容量,千万级的并发请求,可满足业务在缓存、存储、计算等不同场景中的需求。 云数据库 Redis 的优势: 主从热备:提供主从热备,宕机自动监测,自动容灾。 数据备份:标准和集群架构数据持久化存储,可提供
腾讯云可观测平台
2021/01/08
5.2K0
【最佳实践】巡检项:云数据库(Redis)副本数达到上限 5 个
针对读多写少的业务场景,为解决热点数据的集中读需求,腾讯云Redis支持读写分离功能,最大1主5从模式,即最大5倍的读能力扩展。当集群中的副本数量已经达到5个上限时,不能再通过简单增加副本的方式来扩展读能力,因此建议通过分片数量扩展的方式来提升集群总体的读写能力,应对可能发生的业务请求增加。
邵聪 SHAO CONG
2022/04/18
1.1K0
【最佳实践】巡检项:云数据库(MongoDB)CPU 使用率
检查腾讯云数据库 MySQL 实例的 CPU 使用率情况,如果MongoDB实例的CPU使⽤率过⾼,会导致MonogoDB响应缓慢,甚⾄业务不可⽤。
ivesjiang@DBA
2022/04/07
1K0
【最佳实践】巡检项:云数据库(Redis)利用率不足
检查到云数据库Redis的资源利用率较低,如果业务生命周期已经稳定,并且没有增长的计划,可以适当调整实例的规格配置,降低成本。
邵聪 SHAO CONG
2022/04/21
1.7K1
Redis案例:热key导致实例CPU 100%
在Redis世界里,热key指的是那些在一段时间内访问频率特别高的键值,具体到业务场景,包括热点新闻、热门直播、秒杀活动等等。
brightdeng@DBA
2020/08/27
2.4K1
Redis案例:热key导致实例CPU 100%
史上最全腾讯云数据库(MongoDB)监控最佳实践
文章旨在通过对 MongoDB 监控指标的梳理和架构的分解,帮助广大的腾讯云 MongoDB 用户更好的通过监控告警及时发现业务异常,实时监控数据趋势。内容将会包括三个部分:
腾讯云可观测平台
2020/11/12
3.1K0
邹鹏:Redis数据库云端最佳技术实践
这次过来主要是和大家分享一下,腾讯云上个月正式上线的Redis4.0集群版的相关内容,跟大家分享我们在做集群版的时候有哪些思考,我们怎么去设计整个系统架构,最终我们做了哪些东西。大概会有三个点,第一个点是说Redis的使命,我们看Redis是什么产品,为什么这么火,第二块就是腾讯云Redis4.0集群设计经历了哪些思考,最终做成什么样子,最后是2018年年初,登录到腾讯云的自研兼容Redis协议的CKV引擎,他是怎么样的一个架构设计。
腾讯云开发者社区技术沙龙
2018/11/05
1.5K0
【最佳实践】巡检项:云数据库(MySQL)CPU 使用率
检查腾讯云数据库 MySQL 实例的 CPU 使用率情况,若使用率过高,可能会出现业务请求延迟增加,甚至无响应等风险。
王文安@DBA
2022/04/06
1K0
【最佳实践】巡检项:云数据库(MySQL)CPU 使用率
Redis最佳实践:7个维度+43条使用规范,带你彻底玩转Redis | 附实践清单
你的项目或许已经使用 Redis 很长时间了,但在使用过程中,你可能还会或多或少地遇到以下问题:
CSDN技术头条
2021/03/22
6.5K0
Redis最佳实践:7个维度+43条使用规范,带你彻底玩转Redis | 附实践清单
打开思路,数据库的全场景高可用性架构长什么样?
数据库是企业核心业务运行的重要组成部分,数据是企业的生命线,如果数据库出现宕机、数据丢失或不可用等问题,将会对企业的生产、营销和决策产生难以预估的影响,因此,一套高可用的数据库架构对于企业来说至关重要,可以最大化保证业务稳定性和数据可靠性。腾讯云MySQL推出全场景高可用性架构(All-Scenario High Availability Architecture,AS-HAA),用户可根据实际业务需求、业务类型自行配置。
腾讯云数据库 TencentDB
2023/07/25
4710
打开思路,数据库的全场景高可用性架构长什么样?
Redis数据库云端最佳技术实践
邹鹏,腾讯高级工程师,腾讯云数据库Redis负责人,多年数据库、网络安全研发经验。在网络、计算、存储、安全等领域有深入的研究和丰富的产品化经验。 在Redis、MySQL等数据库的高可用、高可靠和中间件方面有丰富的实践经验。
腾讯云数据库 TencentDB
2018/11/06
1.5K0
Redis数据库云端最佳技术实践
Redis - 高并发场景下的Redis最佳实践_翻过6座大山
在高并发系统中,Redis缓存通常被视为数据在存入数据库之前的重要中间层,其设计专注于缓存功能,性能往往比传统数据库高出一个数量级以上。以Redis单实例而言,其读取并发能力可达到10万QPS(官方理论值)。
小小工匠
2024/05/26
1.5K0
Redis - 高并发场景下的Redis最佳实践_翻过6座大山
Redis 生产架构选型解决方案
采用主从(master-replica)模式搭建。主节点提供日常服务访问,备节点提供HA高可用,当主节点发生故障,系统会自动在30秒内切换至备节点,保证业务平稳运行。
玄姐谈AGI
2021/07/29
3720
用Redis构建缓存集群的最佳实践有哪些?
Redis 从 3.0 版本开始,提供了官方的集群支持,也就是 Redis Cluser。Redis Cluster 相比于单个节点的 Redis,能保存更多的数据,支持更多的并发,并且可以做到高可用,在单个节点故障的情况下,继续提供服务。
码农架构
2020/10/26
1.2K0
用Redis构建缓存集群的最佳实践有哪些?
相比原生,腾讯云数据库MySQL 8.0带来了哪些新的极致体验?
官方MySQL 8.0 是非常大的版本,以前的版本号是 5.6、5.7,现在一下飞跃到 8.0,对于 Oracle MySQL官方来说也是非常大的版本,有很多的更新。
腾讯云开发者
2020/08/20
5.6K2
得物 Redis 设计与实践
自建 Redis 系统是得物 DBA 团队自研高性能分布式 KV 缓存系统,目前管理的 ECS 内存总容量超过数十TB,数百多个 Redis 缓存集群实例,数万多个 Redis 数据节点,其中内存规格超过 1T 的大容量集群多个。
得物技术
2023/10/27
8K2
得物 Redis 设计与实践
Redis认知-分布式系统中的单主怎么组建一个集群来抗高并发
1、Redis-Server:Redis服务端,用于存储用户数据的,此处就一个master节点【IP: 100.100.100.1:6379】
Janesong
2024/07/07
2140
Redis进阶学习10---redis最佳实践
当key可以转换为数字时,即key由数字组成,底层会编码为int,如果key长度小于44字节,采用embstr编码类型,否则采用非连续空间存储,为raw编码类型
大忽悠爱学习
2022/05/14
5840
Redis进阶学习10---redis最佳实践
Redis集群方案对比:Codis、Twemproxy、Redis Cluster
数据持久化本质上是为了做数据备份,有了数据持久化,当Redis宕机时,我们可以把数据从磁盘上恢复回来,但在数据恢复之前,服务是不可用的,而且数据恢复的时间取决于实例的大小,数据量越大,恢复起来越慢。Redis的持久化过程可以参考《Redis持久化是如何做的?》。
Java技术栈
2020/09/22
5.4K1
Redis集群方案对比:Codis、Twemproxy、Redis Cluster
推荐阅读
相关推荐
【最佳实践】巡检项:云数据库(Redis)跨可用区部署
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验