BluetoothAdapter — Android 的系统类,代表设备的本地蓝牙适配器。BluetoothAdapter 是 Android 中所有蓝牙操作的入口点:开启无线电 (enable)、扫描设备、管理可见性 (setScanMode)、获取适配器信息 (getName, getAddress, getState)。该类可通过 BluetoothManager.getAdapter() (API 18+) 或 BluetoothAdapter.getDefaultAdapter() 获取。在没有蓝牙模块的设备上,getDefaultAdapter() 返回 null。根据 Android Developers, 2026,BluetoothAdapter 是从 API 5 开始 Android 上任何 BLE 应用程序的必需组件。
要点
BluetoothAdapter 代表 Android 设备的物理蓝牙适配器。每个设备恰好有一个适配器(例外 — 具有多个蓝牙芯片的 Android Automotive,其中使用 BluetoothManager.getAdapterList())。BluetoothAdapter 封装了无线电状态:STATE_OFF (0)、STATE_TURNING_ON (1)、STATE_ON (2)、STATE_TURNING_OFF (3)。状态通过 BroadcastReceiver 在 ACTION_STATE_CHANGED 上跟踪。
获取 BluetoothAdapter 实例是 Android 上任何 BLE 应用程序的第一步。推荐的方法 — 通过 BluetoothManager.getAdapter() 从 API 18+ 开始。替代方法 — BluetoothAdapter.getDefaultAdapter() 静态方法,从 API 5 开始工作,但灵活性较差。如果设备没有蓝牙模块(仅 Wi-Fi 的平板电脑、模拟器),两种方法都返回 null。null 检查是强制性的:应用程序必须正确终止或禁用 BLE 功能。
// 获取 BluetoothAdapter(推荐)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// 方法 1:通过 BluetoothManager (API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// 方法 2:通过静态方法 (API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// 空值检查
if (bluetoothAdapter == null) {
// 设备不支持蓝牙
}
}
// 检查蓝牙状态
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// 获取适配器信息
fun getAdapterInfo(): Map<String, String> {
return mapOf(
"name" to (bluetoothAdapter?.name ?: "N/A"),
"address" to (bluetoothAdapter?.address ?: "N/A"),
"state" to (bluetoothAdapter?.state?.toString() ?: "N/A"),
"scanMode" to (bluetoothAdapter?.scanMode?.toString() ?: "N/A")
)
}
}
BluetoothHelper 类演示了通过 BluetoothManager 获取 BluetoothAdapter 并进行后续的 null 检查。isBluetoothEnabled 检查 isEnabled — 在任何 BLE 操作之前的强制条件。getAdapterInfo 返回设备名称、MAC 地址、状态和可见性模式。重要:在 Android 10+ (API 29+) 上,如果应用程序没有 BLUETOOTH_ADMIN 和 ACCESS_FINE_LOCATION 权限,系统服务将返回虚假的 MAC 地址 (02:00:00:00:00:00)。
BluetoothAdapter 提供了管理蓝牙无线电的方法。enable() 和 disable() 开启和关闭蓝牙。这两种方法都需要 BLUETOOTH_ADMIN 权限并异步执行:调用 enable() 后,系统启动无线电开启过程,状态通过 BroadcastReceiver 以 BluetoothAdapter.ACTION_STATE_CHANGED 动作跟踪。从 Android 10+ 开始,enable() 和 disable() 需要额外的系统权限 — 普通应用程序在没有用户对话框的情况下无法以编程方式管理蓝牙。
getState() 返回适配器的当前状态:STATE_OFF (10)、STATE_TURNING_ON (11)、STATE_ON (12)、STATE_TURNING_OFF (13)。getAddress() 返回蓝牙适配器的 MAC 地址。在 Android 6+ 上,请求 MAC 地址需要 ACCESS_FINE_LOCATION(或 API 31+ 的 ACCESS_COARSE_LOCATION)。在 Android 10+ 上,getAddress() 返回常量地址 02:00:00:00:00:00 — 真实地址无法通过公共 API 获取。
getScanMode() 确定适配器的可见性模式:SCAN_MODE_NONE(不可见)、SCAN_MODE_CONNECTABLE(对已连接设备可见)、SCAN_MODE_CONNECTABLE_DISCOVERABLE(对所有设备可见)。可见性模式出于安全原因有时间限制(通常为 60-300 秒)。通过 setScanMode() 设置模式需要 BLUETOOTH_ADMIN 和 Android 10+ 上的系统权限。
| 方法 | 描述 | 所需权限 |
|---|---|---|
| enable() | 开启蓝牙无线电 | BLUETOOTH_ADMIN |
| disable() | 关闭蓝牙无线电 | BLUETOOTH_ADMIN |
| getState() | 适配器的当前状态 | BLUETOOTH |
| getAddress() | 适配器的 MAC 地址 | BLUETOOTH + ACCESS_FINE_LOCATION (API 23+) |
| getScanMode() | 设备的可见性模式 | BLUETOOTH |
| setScanMode() | 设置可见性模式 | BLUETOOTH_ADMIN |
BluetoothAdapter 支持两种类型的扫描。经典蓝牙扫描 (BR/EDR) 通过 startDiscovery() 启动 — 检测所有类型的蓝牙设备,包括手机和耳机。结果通过 BroadcastReceiver 以 BluetoothDevice.ACTION_FOUND 动作返回。startDiscovery() 工作 12 秒,可以通过调用 cancelDiscovery() 取消。此方法已弃用于 BLE — 请使用 BluetoothLeScanner。
通过 BluetoothAdapter 进行 BLE 扫描使用已弃用的方法 startLeScan(LeScanCallback)。从 API 21 开始,Google 建议使用 BluetoothLeScanner,通过 BluetoothAdapter.getBluetoothLeScanner() 获取。BluetoothLeScanner 提供了更灵活的 API:通过 ScanSettings 进行扫描配置(模式、回调类型、匹配模式),通过 ScanFilter 进行过滤(按服务 UUID、设备名称、MAC 地址)以及支持 PendingIntent 进行后台扫描。
// 旧的(已弃用)与新的 BLE 扫描 API
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// 已弃用:startLeScan (API 18+, API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// 新的:BluetoothLeScanner (API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// 扫描设置
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// 按服务过滤(心率 UUID)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// 开始扫描
scanner.startScan(filters, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
val rssi = result.rssi
print("Found (BLE Scanner): ${device.name}, RSSI: $rssi, address: ${device.address}")
}
override fun onScanFailed(errorCode: Int) {
print("Scan error: $errorCode")
}
})
}
}
BLEScanner 类比较已弃用的 startLeScan 和现代的 BluetoothLeScanner。在 legacyScan 中,LeScanCallback 回调接收 BluetoothDevice、RSSI 和原始 scanRecord。在 modernScan 中,使用带有 LOW_LATENCY 模式(最大检测速度)的 ScanSettings 和用于按心率服务 UUID (Heart Rate Service 0x180D) 过滤的 ScanFilter。ScanCallback 提供带有 ScanResult 对象的 onScanResult,该对象包含扩展信息:名称、RSSI、广播数据、连接类型。
BluetoothManager — Android 系统服务,在 API 18 (Android 4.3) 中引入,用于管理蓝牙操作。在 API 18 之前,获取 BluetoothAdapter 的唯一方法是 getDefaultAdapter() 静态方法。BluetoothManager 提供:adapter — BluetoothAdapter 实例,getConnectedDevices() — 已连接设备的列表,getDevicesMatchingConnectionStates() — 按状态过滤。BluetoothManager 也用于在旧 API 上获取 BluetoothLeScanner。
BluetoothManager 的优势 相对于直接调用 BluetoothAdapter.getDefaultAdapter():应用程序不依赖于静态单例,管理器考虑上下文 (Activity/Application),这对 Android Enterprise 的多账户场景很重要。在具有多个蓝牙芯片的 Android Automotive 上,BluetoothManager.getAdapterList() 返回所有可用的适配器 — BluetoothAdapter.getDefaultAdapter() 只返回第一个。
// 使用 BluetoothManager 进行 BLE
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// 获取已连接的 BLE 设备列表
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// 按状态过滤设备
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// 检查设备上的 BLE 支持
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// 通过系统对话框请求开启蓝牙
fun requestEnableBluetooth(activity: MainActivity) {
if (adapter?.isEnabled == false) {
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
activity.startActivityForResult(intent, REQUEST_ENABLE_BT)
}
}
companion object {
const val REQUEST_ENABLE_BT = 1001
}
}
BLEConnection 类使用 BluetoothManager 来访问 BluetoothAdapter 并获取已连接 GATT 设备的列表。isBLESupported 通过 PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) 检查 BLE 无线电的存在 — 这对于具有蓝牙经典但没有 BLE 的设备来说是很重要的检查。requestEnableBluetooth 显示用于开启蓝牙的系统对话框 (ACTION_REQUEST_ENABLE),无需 BLUETOOTH_ADMIN 权限 — 这是在 Android 10+ 上没有系统应用程序的情况下开启蓝牙的唯一合法方式。
权限 对于 BluetoothAdapter 随着每个 Android 版本而演变。在 Android 6-11 (API 23-30) 上,BLE 扫描需要 BLUETOOTH、BLUETOOTH_ADMIN 和 ACCESS_FINE_LOCATION。在 Android 12+ (API 31+) 上,Google 划分了权限:ACCESS_FINE_LOCATION 被 BLUETOOTH_SCAN(扫描)、BLUETOOTH_CONNECT(连接)、BLUETOOTH_ADVERTISE(广播)取代。搜索 BLE 设备时,BLUETOOTH_SCAN 就足够了,不需要位置信息。
权限表 按 Android 版本:
| 操作 | API 23-30 | API 31+ |
|---|---|---|
| BLE 扫描 | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN(无需位置) |
| 连接 BLE | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| BLE 广播 | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| 开启/关闭 | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN(系统) |
| 获取 MAC 地址 | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT(虚假地址) |
在 Android 12+ 上,所有蓝牙权限都是运行时权限 — 必须通过 ActivityResultContracts.RequestMultiplePermissions 在运行时请求。BLUETOOTH_SCAN 和 BLUETOOTH_ADVERTISE 属于 NEARBY_DEVICES 组,BLUETOOTH_CONNECT — 属于同一组。BLUETOOTH 和 BLUETOOTH_ADMIN 权限保留在清单中以便与 API < 31 兼容,但对于 API 31+,它们被忽略 — Google 要求明确指定新权限。
// 在 Android 12+ 上请求蓝牙权限
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
class PermissionHelper(context: Context) {
fun getRequiredPermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+: BLE 扫描
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// Android 6-11: BLE 扫描
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// 检查所有权限
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
PermissionHelper 类根据 API 级别返回正确的权限集。在 Android 12+ 上,使用 BLUETOOTH_SCAN、BLUETOOTH_CONNECT、BLUETOOTH_ADVERTISE 无需位置信息。在 Android 6-11 上,BLE 扫描仍需要 ACCESS_FINE_LOCATION。开发人员在通过 ActivityResultContracts 或 RxPermissions 请求权限时必须考虑这两种情况。
完整示例 — 在 Kotlin 中使用 BluetoothAdapter 进行扫描、连接和读取 BLE 设备数据的 BLE 应用程序。该示例涵盖了权限检查、获取适配器、通过 BluetoothLeScanner 进行扫描以及通过 BluetoothDevice.connectGatt 进行连接。
// Kotlin 中的完整 BLE 管理器
class BLEManager(private val context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
private var scanner: BluetoothLeScanner? = adapter?.bluetoothLeScanner
private var gatt: BluetoothGatt? = null
// 1. 服务发现
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. 带过滤器的扫描
fun startScanning(callback: (BluetoothDevice, Int) -> Unit) {
if (!canScan()) return
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build()
scanner?.startScan(null, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
callback(result.device, result.rssi)
}
})
}
// 3. 停止扫描
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. 连接到 BLE 设备
fun connectToDevice(device: BluetoothDevice) {
if (adapter?.isEnabled != true) return
gatt = device.connectGatt(
context,
false,
object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
// 已找到服务,可以读取特征
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. 释放资源
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
BLEManager 管理器在 Android 上整合了完整的 BLE 循环:适配器和权限检查 (canScan)、通过 BluetoothLeScanner 使用 ScanSettings 进行扫描 (startScanning)、通过 BluetoothDevice.connectGatt 使用 TRANSPORT_LE 进行连接 (connectToDevice)、释放资源 (disconnect)。所有 BLE 操作都在 UI 线程上执行 — Android 在主线程上调用 BluetoothGattCallback 回调。对于高性能的 BLE 任务,建议将 GATT 操作转移到后台 HandlerThread。
常见问题
BluetoothAdapter — 代表 Android 设备本地蓝牙适配器的类。通过 BluetoothManager.getAdapter() (API 18+) 或 BluetoothAdapter.getDefaultAdapter() 获取。提供开启/关闭蓝牙、扫描设备、管理可见性和获取适配器信息的方法。在没有蓝牙模块的设备上返回 null。
原因 — 设备上没有蓝牙无线电。常见于仅 Wi-Fi 的平板电脑、Android 模拟器和没有蓝牙的 Android TV。在应用程序启动时检查 getDefaultAdapter() 是否为 null,如果适配器不存在,请禁用 BLE 功能。替代方法 — 通过 PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) 进行检查以更精确地确定。
BluetoothLeScanner (API 21+) — 用于 BLE 扫描的现代 API,支持 ScanFilter、ScanSettings 和 PendingIntent。startLeScan (API 18+) — BluetoothAdapter 的已弃用方法,接受带有有限数据集的 LeScanCallback。Google 推荐所有新项目使用 BluetoothLeScanner,它允许按 UUID 过滤、配置功耗模式以及通过 PendingIntent 在后台工作。
在 Android 12+ (API 31) 上,BLE 扫描需要 BLUETOOTH_SCAN,连接需要 BLUETOOTH_CONNECT,广播需要 BLUETOOTH_ADVERTISE。位置权限 ACCESS_FINE_LOCATION 不再是 BLE 所必需的。在 Android 6-11 上需要 ACCESS_FINE_LOCATION。所有权限都通过 ActivityResultContracts 在运行时请求。
从 Android 10+ 开始,没有系统对话框的编程式蓝牙开启仅适用于具有 BLUETOOTH_PRIVILEGED 权限的系统应用程序。普通应用程序必须使用 Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) 和 startActivityForResult — 用户在系统对话框中确认开启。清单中的 BLUETOOTH_ADMIN 在 Android 10+ 上不提供 enable() 权限。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。