第一章 BLE基础与开发环境搭建
各位同学,咱们今天聊聊蓝牙低功耗(BLE)开发的第一步。说实话,我刚开始接触BLE时也是一头雾水——蓝牙不是蓝牙吗?怎么还分经典和低功耗?后来踩了不少坑,才慢慢理清脉络。这一章,我就把最核心的基础知识掰开揉碎讲给你听。
1.1 蓝牙技术演进:从经典到低功耗
蓝牙技术从1994年诞生到现在,经历了几个重要阶段。我个人习惯把蓝牙分为两个时代:经典蓝牙(Classic Bluetooth)和低功耗蓝牙(BLE)。
经典蓝牙(BR/EDR):主要用于音频传输、文件传输等场景。功耗高,但吞吐量大。你想想看,蓝牙耳机、蓝牙音箱,用的就是它。
低功耗蓝牙(BLE):从蓝牙4.0开始引入。专门为物联网、可穿戴设备设计。功耗极低,一颗纽扣电池能跑几个月甚至几年。
为什么会这样?因为BLE的设计哲学完全不同——它不追求持续传输,而是「睡一会儿,醒一下,传完继续睡」。我在项目中遇到过一位客户,非要让BLE设备实时传输传感器数据,结果电池两天就耗光了。嗯,这里要注意:BLE不适合高频率、大数据量的场景。
核心区别速览:
- 经典蓝牙:持续连接,高功耗,适合音频/文件
- BLE:间歇连接,极低功耗,适合传感器/控制
- 蓝牙5.0+:BLE速度提升到2Mbps,增加了广播扩展
1.2 BLE协议栈架构:分层拆解
BLE协议栈,说白了就是一套通信规则。我刚开始看协议栈文档时,密密麻麻的术语差点劝退。后来我总结了一个方法:从下往上,逐层理解。
下面这张图是我自己画的,帮你快速建立整体认知:
这张图里,我最想让你记住的是GATT和GAP这两个概念。GAP负责设备发现和连接,GATT负责连接后的数据交换。我刚开始做项目时,总把这两个搞混,后来记住一句话:GAP是「找设备」,GATT是「读数据」。
我的经验:实际开发中,你90%的时间都在和GATT打交道。GAP的配置通常在初始化阶段一次搞定,而GATT的Service、Characteristic操作贯穿整个项目生命周期。
1.3 Android BLE权限配置
Android的权限管理,嗯,这里是个大坑。从Android 6.0到12.0,权限要求一直在变。我曾经因为权限配置不全,导致App在用户手机上直接崩溃——那场面,别提多尴尬了。
下面这张表是我整理的权限清单,建议你直接复制到项目中:
| Android版本 | 所需权限 | 说明 |
|---|---|---|
| Android 4.3 - 5.x | BLUETOOTH, BLUETOOTH_ADMIN | 普通权限,直接声明即可 |
| Android 6.0 - 9.0 | BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION | 位置权限需运行时申请 |
| Android 10.0 - 11.0 | BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION | 扫描BLE仍需位置权限 |
| Android 12.0+ | BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE | 新增细粒度权限,不再需要位置权限 |
避坑指南:我曾经在Android 12上只声明了BLUETOOTH_SCAN,结果发现无法连接设备。后来才意识到,连接操作需要BLUETOOTH_CONNECT权限。记住:扫描和连接是两个不同的权限!
在AndroidManifest.xml中,你需要这样声明:
<!-- Android 12+ 推荐方式 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- 兼容旧版本 -->
<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-feature android:name="android.hardware.bluetooth_le" android:required="true" />
注意最后一行uses-feature。如果你把required设为true,没有BLE硬件的设备将无法安装你的App。我个人习惯设为false,然后在代码中做运行时检测,这样兼容性更好。
1.4 Kotlin项目初始化
好了,理论说完了,咱们动手建项目。我推荐使用Android Studio Arctic Fox或更高版本,Kotlin版本建议1.8+。
第一步:创建项目
打开Android Studio,选择「Empty Activity」,语言选Kotlin,最低SDK选21(覆盖99%的设备)。
第二步:添加依赖
在build.gradle.kts(Module级别)中添加:
dependencies {
// Kotlin协程(推荐用于异步操作)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// 如果你需要更高级的BLE封装,可以考虑:
// implementation("com.jakewharton.rxbinding4:rxbinding-bluetooth:4.0.0")
}
第三步:初始化BLE适配器
在Application或Activity中初始化:
class MyApplication : Application() {
lateinit var bluetoothAdapter: BluetoothAdapter
override fun onCreate() {
super.onCreate()
// 获取蓝牙适配器
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothAdapter = bluetoothManager.adapter
// 检查BLE支持
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
// 处理不支持BLE的情况
Log.w("BLE", "设备不支持BLE")
}
}
}
我的习惯:我会把BluetoothAdapter封装成一个单例对象,配合Kotlin的object关键字。这样在整个App生命周期内,只需要初始化一次,避免重复获取。
第四步:运行时权限申请
使用Kotlin协程封装权限请求,代码更简洁:
suspend fun requestBlePermissions(activity: Activity): Boolean {
return suspendCancellableCoroutine { continuation ->
val permissions = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
)
}
else -> {
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION
)
}
}
// 使用ActivityResultLauncher或传统方式请求
// 这里省略具体实现,后续章节会详细讲解
}
}
嗯,这里要注意:权限请求是异步的,千万不要在主线程中阻塞等待。我见过有人用Thread.sleep()等权限结果,结果导致ANR——这绝对是反面教材。
本章小结
这一章我们覆盖了三个核心内容:
- 蓝牙技术演进:经典蓝牙 vs BLE,记住BLE是为低功耗而生的
- 协议栈架构:从硬件到应用的四层结构,重点掌握GAP和GATT
- 环境搭建:权限配置和项目初始化,这是后续开发的基础
说实话,BLE开发的门槛不在代码本身,而在于对协议的理解。你只要把这一章的基础打牢,后面写代码会顺畅很多。下一章,我们会真正开始写扫描和连接的代码——那才是实战的开始。
公众号:蓝海资料掘金营,微信deep3321