手机系统蓝牙权限全梳理:iOS / Android 权限差异与适配要点
在BLE(低功耗蓝牙)开发中,蓝牙权限是所有功能落地的前提——无论是设备扫描、连接配对,还是数据读写,若权限配置不当,都会导致功能失效、崩溃,甚至无法通过应用商店审核。iOS与Android系统由于权限管理机制不同,蓝牙权限的配置、申请逻辑存在显著差异,而Flutter跨平台开发则需要兼顾两大系统的适配规则,成为很多开发者的“避坑难点”。
本文将从权限机制底层差异出发,全面梳理iOS、Android两大系统的蓝牙权限分类、配置方法、申请逻辑,配套Swift(iOS)、Kotlin(Android)、Dart(Flutter)三种主流语言的实战代码,结合开发中的常见问题,给出可直接落地的适配方案,帮你彻底搞定蓝牙权限适配,避免踩坑。
一、核心前提:iOS与Android蓝牙权限的底层差异
两大系统的蓝牙权限差异,本质源于权限管理理念不同:iOS注重用户隐私管控,权限分类更细致、申请时机更严格,需明确告知用户权限用途;Android则基于系统版本迭代,逐步细化权限颗粒度,从早期的“一刀切”权限,演进到如今的场景化权限,同时兼顾兼容性。
核心差异总结(表格清晰对比):
|
对比维度 |
iOS 系统 |
Android 系统 |
|---|---|---|
|
权限分类 |
分为蓝牙扫描/连接权限、蓝牙广告权限(广播端),按场景细分 |
按系统版本划分:Android 11及以下为基础权限,Android 12+拆分为扫描、连接、广告权限 |
|
申请方式 |
必须在Info.plist配置权限描述,代码中主动申请,用户手动授权 |
Android 12+需动态申请,11及以下无需动态申请(配置即可),部分场景需申请位置权限 |
|
隐私管控 |
严格,权限描述不明确会导致审核驳回,用户可随时在设置中关闭 |
相对宽松,不同厂商(华为、小米等)可能有额外权限管控,需适配 |
|
兼容性 |
版本差异小,iOS 13+权限逻辑基本统一,主要适配iOS 10+主流版本 |
版本差异大,需重点适配Android 10(API 29)、Android 12(API 31)两个关键版本 |
二、iOS 蓝牙权限梳理与Swift实战适配
1. iOS 蓝牙权限分类(按功能场景)
iOS的蓝牙权限主要分为两类,对应不同的BLE开发场景,需分别配置和申请,缺一不可:
-
蓝牙扫描/连接权限(中心设备模式):用于手机作为扫描者,扫描、连接外围BLE设备(如智能手环、传感器),核心权限键为
NSBluetoothAlwaysUsageDescription(iOS 13+)、NSBluetoothPeripheralUsageDescription(兼容iOS 10-12)。 -
蓝牙广告权限(外围设备模式):用于手机作为广播者,对外发送蓝牙广播(如模拟BLE设备),核心权限键为
NSBluetoothAdvertisingUsageDescription(iOS 13+)。
注意:iOS 13+ 已废弃 NSBluetoothPeripheralUsageDescription,但为了兼容低版本,建议同时配置两个权限描述,避免功能异常。
2. 权限配置步骤(Info.plist)
在Xcode中打开项目的Info.plist文件,添加以下键值对(描述需具体,明确告知用户蓝牙用途,否则会被App Store审核驳回):
<!-- 蓝牙扫描/连接权限(兼容所有iOS版本) -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要使用蓝牙连接智能设备,实现数据交互与设备控制</string>
<!-- iOS 13+ 蓝牙扫描/连接权限(必配) -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要持续使用蓝牙连接智能设备,实现数据实时同步与设备控制</string>
<!-- iOS 13+ 蓝牙广告权限(仅广播模式需配置) -->
<key>NSBluetoothAdvertisingUsageDescription</key>
<string>需要开启蓝牙广播,模拟BLE设备供其他设备扫描连接</string>
3. Swift 实战代码(权限申请+状态监听)
iOS中使用CoreBluetooth框架管理蓝牙权限,需先监听蓝牙状态,再主动申请权限,确保权限申请时机合理(建议在用户触发蓝牙功能时申请,提升授权率)。
import CoreBluetooth
class iOSBLEPermissionManager: NSObject, CBCentralManagerDelegate {
// 中心管理器(核心,用于扫描、连接设备)
private var centralManager: CBCentralManager!
// 权限申请结果回调
typealias PermissionCallback = (Bool, String) -> Void
private var permissionCallback: PermissionCallback?
override init() {
super.init()
// 初始化中心管理器,监听蓝牙状态
centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
}
// 主动申请蓝牙权限(在用户触发蓝牙功能时调用)
func requestBluetoothPermission(callback: @escaping PermissionCallback) {
self.permissionCallback = callback
checkBluetoothPermission()
}
// 检查蓝牙权限状态
private func checkBluetoothPermission() {
switch centralManager.authorization {
case .allowedAlways:
// 已授权,可正常使用蓝牙功能
permissionCallback?(true, "蓝牙权限已授权")
case .denied:
// 已拒绝,引导用户去设置开启
permissionCallback?(false, "蓝牙权限已拒绝,请前往设置开启")
case .notDetermined:
// 未申请过权限,主动申请
centralManager.requestAlwaysAuthorization()
case .restricted:
// 权限受限制(如家长控制),无法使用
permissionCallback?(false, "蓝牙权限受限制,无法使用")
@unknown default:
permissionCallback?(false, "蓝牙权限状态异常")
}
}
// 蓝牙状态变化监听(包括权限变化)
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
// 蓝牙已开启,检查权限
checkBluetoothPermission()
case .poweredOff:
permissionCallback?(false, "蓝牙已关闭,请开启蓝牙")
case .unauthorized:
permissionCallback?(false, "蓝牙权限未授权")
case .unsupported:
permissionCallback?(false, "设备不支持蓝牙")
default:
permissionCallback?(false, "蓝牙状态异常:\(central.state)")
}
}
// 权限申请结果回调(iOS 13+)
func centralManager(_ central: CBCentralManager, didUpdateAuthorization status: CBManagerAuthorization) {
checkBluetoothPermission()
}
}
// 使用示例
let blePermissionManager = iOSBLEPermissionManager()
// 在用户点击“连接设备”按钮时申请权限
blePermissionManager.requestBluetoothPermission { isGranted, message in
if isGranted {
print("权限授权成功,开始扫描设备")
// 执行扫描、连接等操作
} else {
print("权限授权失败:\(message)")
// 引导用户去设置开启权限
}
}
4. iOS 适配注意事项
-
权限描述必须具体,禁止使用“需要使用蓝牙”等模糊表述,建议结合应用场景(如“连接智能手环,同步运动数据”),否则会被App Store审核驳回。
-
iOS 13+ 仅支持“始终允许”权限,不再有“在使用期间允许”选项,需在权限描述中明确告知用户“持续使用蓝牙”的用途。
-
若应用仅使用蓝牙扫描/连接功能,无需配置广告权限;若涉及广播模式(如手机模拟BLE设备),必须配置
NSBluetoothAdvertisingUsageDescription。 -
权限被拒绝后,无法再次通过代码申请,需引导用户前往“设置-隐私与安全性-蓝牙”手动开启,建议在回调中添加跳转设置的逻辑。
三、Android 蓝牙权限梳理与Kotlin实战适配
1. Android 蓝牙权限分类(按系统版本)
Android的蓝牙权限迭代差异较大,核心分为三个阶段,需根据目标系统版本针对性适配,重点关注Android 12(API 31)的权限拆分:
-
Android 11及以下(API ≤ 30):仅需配置
BLUETOOTH(基础蓝牙权限)、BLUETOOTH_ADMIN(蓝牙管理权限),无需动态申请,配置后即可使用。 -
Android 12-12L(API 31-32):拆分出
BLUETOOTH_SCAN(扫描权限)、BLUETOOTH_CONNECT(连接权限),需动态申请;广播模式需额外配置BLUETOOTH_ADVERTISE权限。 -
Android 13及以上(API ≥ 33):新增
NEARBY_WIFI_DEVICES权限,若蓝牙扫描涉及Wi-Fi相关设备(如BLE+Wi-Fi双模设备),需额外申请该权限。
补充:Android 10(API 29)及以上,若使用BLE扫描功能,需申请 ACCESS_FINE_LOCATION(位置权限),否则无法扫描到BLE设备(系统限制,用于保护用户隐私)。
2. 权限配置步骤(AndroidManifest.xml)
在AndroidManifest.xml中添加以下权限,适配所有主流系统版本,兼顾兼容性:
<!-- 基础蓝牙权限(Android 11及以下) -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Android 12+ 蓝牙扫描权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<!-- Android 12+ 蓝牙连接权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Android 12+ 蓝牙广播权限(仅广播模式需配置) -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Android 10+ 位置权限(BLE扫描必需) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="32" />
<!-- Android 13+ 附近Wi-Fi设备权限(双模设备扫描必需) -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:minSdkVersion="33" /><!-- 声明设备支持蓝牙低功耗 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<!-- 声明应用使用蓝牙功能 -->
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" tools:ignore="ProtectedPermissions" />
说明:android:usesPermissionFlags="neverForLocation" 用于告知系统,蓝牙扫描不用于获取位置信息,避免强制申请位置权限(Android 12+ 支持)。
3. Kotlin 实战代码(权限申请+兼容性适配)
Android需根据系统版本,动态申请对应权限,同时监听蓝牙状态和权限申请结果,适配不同版本的权限差异,以下是完整适配代码(可直接集成到项目):
import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class AndroidBLEPermissionManager(private val context: Context) {
// 蓝牙适配器(核心)
private val bluetoothAdapter: BluetoothAdapter? by lazy {
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
// 权限申请请求码
private val REQUEST_BLE_PERMISSIONS = 1001
// 权限申请结果回调
typealias PermissionCallback = (Bool, String) -> Unit
private var permissionCallback: PermissionCallback? = null
// 检查并申请蓝牙权限
fun requestBLEPermissions(activity: AppCompatActivity, callback: @escaping PermissionCallback) {
this.permissionCallback = callback
// 检查蓝牙是否可用
if (bluetoothAdapter == null) {
callback(false, "设备不支持蓝牙")
return
}
// 检查蓝牙是否开启
if (!bluetoothAdapter!!.isEnabled) {
callback(false, "蓝牙已关闭,请开启蓝牙")
return
}
// 根据系统版本,获取需要申请的权限
val requiredPermissions = getRequiredPermissions()
// 检查权限是否已授予
if (checkPermissions(requiredPermissions)) {
callback(true, "蓝牙权限已授权")
} else {
// 动态申请权限
ActivityCompat.requestPermissions(activity, requiredPermissions, REQUEST_BLE_PERMISSIONS)
}
}
// 根据系统版本,获取需要申请的权限列表
private fun getRequiredPermissions(): Array<String> {
return when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
// Android 13+:扫描、连接、附近Wi-Fi设备权限(按需添加广播权限)
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.NEARBY_WIFI_DEVICES
)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
// Android 12-12L:扫描、连接权限(按需添加广播权限)
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
// Android 10-11:基础蓝牙权限+位置权限
arrayOf(
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.ACCESS_FINE_LOCATION
)
}
else -> {
// Android 9及以下:基础蓝牙权限
arrayOf(
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
}
// 检查权限是否已授予
private fun checkPermissions(permissions: Array<String>): Boolean {
return permissions.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
}
// 权限申请结果回调(需在Activity中重写onRequestPermissionsResult)
fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode != REQUEST_BLE_PERMISSIONS) return
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
permissionCallback?.invoke(true, "蓝牙权限授权成功")
} else {
permissionCallback?.invoke(false, "蓝牙权限授权失败,部分功能无法使用")
}
}
// 开启蓝牙(需权限)
fun enableBluetooth(): Boolean {
if (bluetoothAdapter == null) return false
if (!bluetoothAdapter!!.isEnabled) {
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
return false
}
return bluetoothAdapter!!.enable()
}
return true
}
}
// 使用示例(在Activity中)
class BLEActivity : AppCompatActivity() {
private lateinit var blePermissionManager: AndroidBLEPermissionManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ble)
blePermissionManager = AndroidBLEPermissionManager(this)
// 在用户点击“连接设备”时申请权限
findViewById<Button>(R.id.btn_connect).setOnClickListener {
blePermissionManager.requestBLEPermissions(this) { isGranted, message ->
if (isGranted) {
println("权限授权成功,开始扫描设备")
// 执行扫描、连接等操作
} else {
println("权限授权失败:$message")
// 引导用户开启权限
}
}
}
}
// 重写权限申请结果回调
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
blePermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
4. Android 适配注意事项
-
版本适配是核心:需严格区分Android 10、12、13三个关键版本,避免权限遗漏(如Android 12+未申请BLUETOOTH_SCAN,会导致扫描失败)。
-
位置权限适配:Android 10-12L,BLE扫描需申请ACCESS_FINE_LOCATION,Android 12+可通过设置usesPermissionFlags="neverForLocation"规避位置权限申请。
-
厂商适配:华为、小米、OPPO等厂商对蓝牙权限有额外管控,部分机型需在“设置-应用-权限”中手动开启“蓝牙”和“位置”权限,建议在权限拒绝后,引导用户跳转设置。
-
广播权限:仅当应用需要作为广播者(模拟BLE设备)时,才需申请BLUETOOTH_ADVERTISE权限,否则无需配置。
四、Flutter 蓝牙权限梳理与Dart实战适配
1. Flutter 蓝牙权限适配核心逻辑
Flutter跨平台开发的蓝牙权限适配,本质是“分别适配iOS和Android原生权限”——通过第三方插件(推荐flutter_blue_plus、permission_handler),统一调用原生权限申请接口,同时配置两大系统的原生权限描述,实现一次开发、两端适配。
核心要点:Flutter本身不提供蓝牙权限管理能力,需依赖插件调用原生API,因此必须同时完成iOS(Info.plist)和Android(AndroidManifest.xml)的权限配置,否则插件无法正常工作。
2. 插件选择与依赖配置
推荐使用两个核心插件,协同实现蓝牙权限申请和BLE功能开发:
-
permission_handler:用于统一申请iOS和Android的蓝牙权限,简化权限申请逻辑。
-
flutter_blue_plus:用于BLE功能开发(扫描、连接、读写特征值),兼容两端,且支持权限状态监听。
第一步:添加依赖(pubspec.yaml)
dependencies:
flutter:
sdk: flutter
permission_handler: ^11.0.1 # 权限申请插件(最新版本可在pub.dev查询)
flutter_blue_plus: ^1.13.3 # BLE开发插件(兼容iOS/Android)
第二步:原生权限配置(已在iOS、Android章节详细说明,此处仅汇总)
-
iOS:在Info.plist中添加NSBluetoothAlwaysUsageDescription、NSBluetoothPeripheralUsageDescription(可选)、NSBluetoothAdvertisingUsageDescription(可选)。
-
Android:在AndroidManifest.xml中添加对应系统版本的蓝牙权限、位置权限(按需)。
3. Dart 实战代码(权限申请+两端适配)
以下代码实现“权限申请→蓝牙状态监听→BLE扫描”的完整流程,兼顾iOS和Android的权限差异,可直接集成到Flutter项目中:
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
class FlutterBLEPermissionPage extends StatefulWidget {
const FlutterBLEPermissionPage({super.key});
@override
State<FlutterBLEPermissionPage> createState() => _FlutterBLEPermissionPageState();
}
class _FlutterBLEPermissionPageState extends State<FlutterBLEPermissionPage> {
// BLE核心实例
FlutterBluePlus flutterBlue = FlutterBluePlus.instance;
// 蓝牙状态
BluetoothState _bluetoothState = BluetoothState.unknown;
// 权限状态
PermissionStatus _blePermissionStatus = PermissionStatus.denied;
@override
void initState() {
super.initState();
// 监听蓝牙状态变化
_listenBluetoothState();
// 检查蓝牙权限
_checkBLEPermission();
}
// 监听蓝牙状态
void _listenBluetoothState() {
flutterBlue.state.listen((BluetoothState state) {
setState(() {
_bluetoothState = state;
});
// 蓝牙状态变化后,重新检查权限
if (state == BluetoothState.on) {
_checkBLEPermission();
}
});
}
// 检查蓝牙权限
Future<void> _checkBLEPermission() async {
// 根据平台,获取对应的蓝牙权限
Permission blePermission = Permission.bluetooth;
if (Theme.of(context).platform == TargetPlatform.android) {
// Android平台:根据系统版本,判断是否需要申请额外权限
if (await _isAndroid12Plus()) {
// Android 12+:申请扫描和连接权限
blePermission = Permission.bluetoothScan;
PermissionStatus connectStatus = await Permission.bluetoothConnect.status;
if (connectStatus != PermissionStatus.granted) {
await Permission.bluetoothConnect.request();
}
} else if (await _isAndroid10Plus()) {
// Android 10+:申请蓝牙+位置权限
blePermission = Permission.bluetooth;
PermissionStatus locationStatus = await Permission.location.status;
if (locationStatus != PermissionStatus.granted) {
await Permission.location.request();
}
}
} else if (Theme.of(context).platform == TargetPlatform.iOS) {
// iOS平台:申请蓝牙始终允许权限
blePermission = Permission.bluetoothAlways;
}
// 检查并申请蓝牙权限
_blePermissionStatus = await blePermission.status;
if (_blePermissionStatus != PermissionStatus.granted) {
_blePermissionStatus = await blePermission.request();
}
setState(() {});
}
// 判断是否为Android 10+(API ≥ 29)
Future<bool> _isAndroid10Plus() async {
return await flutterBlue.isAndroid && await flutterBlue.sdkInt >= 29;
}
// 判断是否为Android 12+(API ≥ 31)
Future<bool> _isAndroid12Plus() async {
return await flutterBlue.isAndroid && await flutterBlue.sdkInt >= 31;
}
// 开始扫描BLE设备(需权限和蓝牙开启)
void _startScan() async {
if (_bluetoothState != BluetoothState.on) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先开启蓝牙")),
);
return;
}
if (_blePermissionStatus != PermissionStatus.granted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先授予蓝牙权限")),
);
await _checkBLEPermission();
return;
}
// 停止之前的扫描,避免重复扫描
flutterBlue.stopScan();
// 开始扫描,扫描时长4秒
flutterBlue.startScan(timeout: const Duration(seconds: 4));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("开始扫描设备...")),
);
// 监听扫描结果
flutterBlue.scanResults.listen((List<ScanResult> results) {
for (ScanResult result in results) {
print("发现设备:${result.device.name ?? "未知设备"},RSSI:${result.rssi}");
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Flutter 蓝牙权限适配")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 蓝牙状态显示
Text("蓝牙状态:${_bluetoothState.toString().split('.').last}"),
const SizedBox(height: 10),
// 权限状态显示
Text("权限状态:${_blePermissionStatus.toString().split('.').last}"),
const SizedBox(height: 30),
// 申请权限按钮
ElevatedButton(
onPressed: () => _checkBLEPermission(),
child: const Text("申请蓝牙权限"),
),
const SizedBox(height: 10),
// 开启蓝牙按钮
ElevatedButton(
onPressed: () async {
if (_bluetoothState == BluetoothState.off) {
await flutterBlue.turnOn();
}
},
child: const Text("开启蓝牙"),
),
const SizedBox(height: 10),
// 扫描设备按钮
ElevatedButton(
onPressed: _startScan,
child: const Text("扫描BLE设备"),
),
],
),
),
);
}
@override
void dispose() {
// 停止扫描,释放资源
flutterBlue.stopScan();
super.dispose();
}
}
4. Flutter 适配注意事项
-
插件版本兼容:permission_handler和flutter_blue_plus的版本需匹配,避免出现兼容性问题(如权限申请无响应、扫描失败),建议使用pub.dev推荐的稳定版本。
-
两端原生配置不可遗漏:Flutter插件依赖原生权限配置,若未配置Info.plist或AndroidManifest.xml,会导致权限申请失败,甚至应用崩溃。
-
权限申请时机:建议在用户触发蓝牙功能(如点击“扫描设备”)时申请权限,避免启动应用就弹出权限弹窗,提升用户体验。
-
状态监听:需同时监听蓝牙状态和权限状态,避免出现“蓝牙已开启但权限未授权”“权限已授权但蓝牙未开启”的异常场景。
五、三大系统蓝牙权限适配总结与避坑指南
1. 核心适配总结
-
iOS:重点配置权限描述(Info.plist),申请“始终允许”权限,适配iOS 13+,避免审核驳回。
-
Android:按系统版本拆分权限,重点适配Android 10、12、13,兼顾位置权限和厂商适配。
-
Flutter:依赖第三方插件,统一调用原生权限接口,同时完成两端原生配置,实现跨平台适配。
2. 常见坑点与解决方案
-
坑点1:iOS权限申请无响应 → 解决方案:检查Info.plist是否配置正确的权限描述,确保权限键拼写无误(如NSBluetoothAlwaysUsageDescription)。
-
坑点2:Android 12+ 扫描不到设备 → 解决方案:确认已申请BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限,且配置了usesPermissionFlags="neverForLocation"。
-
坑点3:Flutter权限申请后仍无法使用蓝牙 → 解决方案:检查两端原生配置是否完整,插件版本是否兼容,重启应用重试。
-
坑点4:Android 10+ 扫描失败 → 解决方案:确认已申请ACCESS_FINE_LOCATION权限,且用户已授权。
3. 开发建议
1. 优先适配主流版本:iOS重点适配13+,Android重点适配10+,覆盖90%以上用户群体;
2. 权限申请引导:权限被拒绝后,添加清晰的引导文案,跳转系统设置开启权限,提升用户体验;
3. 测试覆盖:在不同机型(iOS不同版本、Android不同厂商机型)上测试权限申请和蓝牙功能,避免兼容性问题;
4. 权限释放:应用退出或蓝牙功能使用完毕后,及时停止扫描、断开连接,释放蓝牙资源,避免内存泄漏。
更多推荐

所有评论(0)