鸿蒙 Flutter 权限管理进阶:动态权限、权限组、兼容处理与用户引导
摘要:本文深入探讨鸿蒙(HarmonyOS)与Flutter开发中的权限管理问题,针对鸿蒙独特的权限机制与Flutter生态的适配挑战,提出一套完整的解决方案。文章从动态权限申请、权限组管理、跨版本兼容和用户引导四个核心维度展开,详细讲解如何通过permission_handler_harmony插件实现权限管理,并提供了实战代码示例。特别强调了鸿蒙与Android权限体系的差异、权限申请时机优化
一、引言:为什么权限管理是鸿蒙 Flutter 开发的「必修课」?
在鸿蒙(HarmonyOS)生态日益成熟的今天,Flutter 作为跨平台开发的主流框架,与鸿蒙的结合越来越紧密。但权限管理一直是跨平台开发的「老大难」问题 —— 鸿蒙的权限机制与 Android/iOS 存在本质差异,且 Flutter 生态对鸿蒙的权限支持尚处于完善阶段,新手很容易踩坑:
- 直接复用 Android 端的权限申请逻辑,导致鸿蒙设备上申请失败;
- 忽略权限组的依赖关系,单独申请某权限被系统拒绝;
- 未处理鸿蒙不同版本(API 9/10/11)的权限差异,出现兼容性崩溃;
- 权限申请时机不当,导致用户频繁拒绝,应用上架被打回。
本文将从「动态权限申请」「权限组管理」「跨版本兼容」「用户引导」四个核心维度,结合实战代码和官方最佳实践,打造一套可直接落地的鸿蒙 Flutter 权限管理方案。无论你是开发工具类、媒体类还是定位类应用,都能从中找到解决方案。
前置知识:熟悉 Flutter 基础语法、了解鸿蒙应用开发流程(如 config.json 配置)。环境要求:Flutter 3.10+、HarmonyOS SDK 3.0+、DevEco Studio 4.0+
二、核心基础:鸿蒙权限体系与 Flutter 适配原理
在深入进阶内容前,必须先理清鸿蒙的权限机制与 Flutter 的适配逻辑,避免「知其然不知其所以然」。
2.1 鸿蒙权限的核心特性
鸿蒙的权限体系遵循「最小权限原则」,分为三大类(官方文档):
- 系统基础权限:如网络、蓝牙、震动等,大部分无需动态申请,在 config.json 声明即可;
- 敏感权限:如相机、麦克风、存储、定位等,需要动态申请 + 用户授权;
- 特殊权限:如后台定位、悬浮窗、安装未知来源应用等,需跳转系统设置页面授权。
关键差异点(与 Android 对比):
| 特性 | 鸿蒙(HarmonyOS) | Android |
|---|---|---|
| 权限声明文件 | config.json(module -> reqPermissions) | AndroidManifest.xml |
| 动态申请 API | ohos.security.permission.PermissionManager | Context.checkSelfPermission + requestPermissions |
| 权限组依赖 | 部分权限必须先申请组权限(如 WRITE_EXTERNAL_STORAGE 依赖 READ_EXTERNAL_STORAGE) | 权限组自动关联,申请子权限即包含组权限 |
| 拒绝后处理 | 第二次拒绝后默认不再弹出授权弹窗,需引导用户手动开启 | 多次拒绝后才会隐藏弹窗 |
2.2 Flutter 适配鸿蒙权限的两种方案
Flutter 本身不直接提供鸿蒙权限 API,需通过以下两种方式实现:
- 原生插件桥接:通过 MethodChannel 调用鸿蒙原生权限 API(适合需要深度定制的场景);
- 第三方插件:使用已适配鸿蒙的 Flutter 权限插件(推荐,效率更高)。
本文重点讲解第二种方案 ——permission_handler_harmony 插件(GitHub 地址),这是目前最成熟的鸿蒙 Flutter 权限插件,支持 20+ 常见权限,适配鸿蒙 3.0+ 全版本。
2.3 环境配置步骤(必看)
步骤 1:添加依赖
在 pubspec.yaml 中添加插件依赖:
yaml
dependencies:
flutter:
sdk: flutter
# 鸿蒙权限处理插件(适配 API 9+)
permission_handler_harmony: ^1.2.0
# 状态管理(可选,用于管理权限申请状态)
provider: ^6.1.1
执行 flutter pub get 安装依赖。
步骤 2:在 config.json 中声明权限
所有需要动态申请的权限,必须先在 config.json 的 reqPermissions 中声明(官方要求),否则申请会直接失败。
示例(声明相机、存储、定位权限):
json
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.CAMERA", // 相机权限
"reason": "用于拍摄照片上传头像", // 权限申请理由(将显示在授权弹窗中)
"usedScene": {
"ability": ["com.example.myapp.MainAbility"],
"when": "inuse" // 仅在应用使用时申请
}
},
{
"name": "ohos.permission.READ_EXTERNAL_STORAGE", // 读取存储权限
"reason": "用于读取本地照片",
"usedScene": {"ability": ["com.example.myapp.MainAbility"], "when": "inuse"}
},
{
"name": "ohos.permission.WRITE_EXTERNAL_STORAGE", // 写入存储权限
"reason": "用于保存照片到本地",
"usedScene": {"ability": ["com.example.myapp.MainAbility"], "when": "inuse"}
},
{
"name": "ohos.permission.LOCATION", // 定位权限
"reason": "用于获取当前位置推荐附近服务",
"usedScene": {"ability": ["com.example.myapp.MainAbility"], "when": "inuse"}
}
]
}
}
注意:
reason字段必须真实准确,否则应用上架时可能被鸿蒙应用市场拒绝。
三、进阶实战一:动态权限申请的最佳实践
动态权限申请是基础,但如何做到「申请时机合理、用户体验友好、申请结果处理完善」,是进阶的关键。
3.1 权限申请的核心流程
鸿蒙 Flutter 权限申请的标准流程:
- 检查权限状态 → 2. 已授权:直接执行功能;
- 未授权:判断是否为第一次申请 → 是:发起申请;
- 否(用户已拒绝过):显示权限说明弹窗 → 引导用户同意申请;
- 申请结果处理:授权成功(执行功能)/ 授权失败(引导手动开启)。
3.2 权限状态监听与申请(实战代码)
使用 permission_handler_harmony 插件实现相机权限申请的完整逻辑:
步骤 1:定义权限申请工具类
dart
import 'package:permission_handler_harmony/permission_handler_harmony.dart';
import 'package:flutter/material.dart';
class HarmonyPermissionUtil {
/// 检查并申请单个权限
/// [permission]:权限类型(如 Permission.camera)
/// [rationale]:权限说明(用户拒绝后显示)
static Future<bool> requestPermission(
Permission permission, {
required String rationale,
required BuildContext context,
}) async {
// 1. 检查权限状态
final PermissionStatus status = await permission.status;
if (status.isGranted) {
// 2. 已授权:返回 true
return true;
} else if (status.isDenied) {
// 3. 未授权(第一次申请):发起申请
final PermissionStatus result = await permission.request();
return result.isGranted;
} else if (status.isPermanentlyDenied) {
// 4. 永久拒绝:显示说明弹窗,引导用户手动开启
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("权限申请必要说明"),
content: Text(rationale),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("取消"),
),
TextButton(
onPressed: () {
// 跳转到应用权限设置页面
PermissionHandlerHarmony.openAppSettings();
Navigator.pop(context);
},
child: const Text("去设置"),
),
],
),
);
return false;
} else {
// 其他状态(如受限):直接返回 false
return false;
}
}
/// 检查权限状态(返回中文描述)
static String getPermissionStatusDesc(PermissionStatus status) {
switch (status) {
case PermissionStatus.granted:
return "已授权";
case PermissionStatus.denied:
return "未授权(可再次申请)";
case PermissionStatus.permanentlyDenied:
return "已拒绝(需手动开启)";
case PermissionStatus.restricted:
return "权限受限";
default:
return "未知状态";
}
}
}
步骤 2:在页面中使用权限工具类
dart
import 'package:flutter/material.dart';
import 'package:permission_handler_harmony/permission_handler_harmony.dart';
class CameraPage extends StatelessWidget {
const CameraPage({super.key});
/// 打开相机(需先申请权限)
Future<void> _openCamera(BuildContext context) async {
// 申请相机权限
final bool hasPermission = await HarmonyPermissionUtil.requestPermission(
Permission.camera,
rationale: "为了正常拍摄照片上传头像,请允许相机权限。你可以在设置中随时关闭该权限。",
context: context,
);
if (hasPermission) {
// 权限已授权:执行打开相机逻辑
debugPrint("相机权限已授权,开始打开相机...");
// TODO: 调用相机相关 API(如 camera 插件)
} else {
// 权限未授权:提示用户
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("相机权限未开启,无法使用拍摄功能")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("相机功能")),
body: Center(
child: ElevatedButton(
onPressed: () => _openCamera(context),
child: const Text("打开相机"),
),
),
);
}
}
3.3 关键注意点
- 申请时机:不要在应用启动时一次性申请所有权限,应遵循「按需申请」(即用户点击某个功能时再申请对应权限);
- 权限说明:
rationale字段要明确告知用户「为什么需要该权限」,避免用户因困惑而拒绝; - 跳转设置:当用户永久拒绝后,必须提供「去设置」按钮,否则用户无法再次开启权限,功能完全不可用;
- 错误处理:权限申请是异步操作,需处理网络异常、系统版本不兼容等异常情况。
四、进阶实战二:权限组管理与批量申请
鸿蒙中部分权限属于「权限组」,必须先申请组内的基础权限,才能申请其他权限(如存储权限组:READ_EXTERNAL_STORAGE 是基础权限,WRITE_EXTERNAL_STORAGE 依赖于它)。此外,在某些场景下(如媒体编辑应用),需要同时申请多个权限,这就需要批量申请逻辑。
4.1 鸿蒙常见权限组分类(官方文档)
| 权限组 | 包含权限 | 基础权限(必须先申请) |
|---|---|---|
| 存储权限组 | READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE | READ_EXTERNAL_STORAGE |
| 定位权限组 | LOCATION、LOCATION_BACKGROUND | LOCATION |
| 媒体权限组 | CAMERA、MICROPHONE | 无(可单独申请,但建议一起申请) |
4.2 批量申请权限(实战代码)
实现「存储 + 相机」权限的批量申请,适用于照片上传场景:
步骤 1:扩展权限工具类,添加批量申请方法
dart
extension HarmonyPermissionBatch on HarmonyPermissionUtil {
/// 批量申请权限
/// [permissions]:权限列表(需按权限组顺序排列,先基础后依赖)
static Future<Map<Permission, bool>> requestPermissions(
List<Permission> permissions, {
required String rationale,
required BuildContext context,
}) async {
final Map<Permission, bool> result = {};
// 检查是否有权限组依赖,调整申请顺序(示例:先申请 READ_EXTERNAL_STORAGE,再申请 WRITE_EXTERNAL_STORAGE)
permissions = _sortPermissionsByGroup(permissions);
for (final permission in permissions) {
final bool granted = await requestPermission(
permission,
rationale: rationale,
context: context,
);
result[permission] = granted;
// 如果基础权限申请失败,后续依赖权限无需申请
if (!granted && _isBasePermission(permission)) {
break;
}
}
return result;
}
/// 按权限组排序:基础权限在前,依赖权限在后
static List<Permission> _sortPermissionsByGroup(List<Permission> permissions) {
final List<Permission> basePermissions = [];
final List<Permission> dependentPermissions = [];
for (final permission in permissions) {
if (_isBasePermission(permission)) {
basePermissions.add(permission);
} else {
dependentPermissions.add(permission);
}
}
return [...basePermissions, ...dependentPermissions];
}
/// 判断是否为权限组的基础权限
static bool _isBasePermission(Permission permission) {
switch (permission) {
case Permission.storage: // READ_EXTERNAL_STORAGE 对应 Permission.storage
case Permission.location:
return true;
default:
return false;
}
}
}
步骤 2:批量申请权限的使用场景
dart
class PhotoUploadPage extends StatelessWidget {
const PhotoUploadPage({super.key});
Future<void> _uploadPhoto(BuildContext context) async {
// 批量申请:存储(读取)+ 相机权限
final Map<Permission, bool> result = await HarmonyPermissionUtil.requestPermissions(
[Permission.storage, Permission.camera],
rationale: "为了正常上传照片,需要获取存储权限(读取本地照片)和相机权限(拍摄新照片)。你可以在设置中随时关闭这些权限。",
context: context,
);
// 检查所有权限是否都已授权
final bool allGranted = result.values.every((granted) => granted);
if (allGranted) {
// 所有权限已授权:执行上传逻辑
debugPrint("存储和相机权限已授权,开始上传照片...");
// TODO: 打开相册或相机选择照片
} else {
// 部分权限未授权:提示用户缺失的权限
final String deniedPermissions = result.entries
.where((entry) => !entry.value)
.map((entry) => _getPermissionName(entry.key))
.join("、");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("缺少 $deniedPermissions,无法上传照片")),
);
}
}
/// 将 Permission 转换为中文名称
String _getPermissionName(Permission permission) {
switch (permission) {
case Permission.storage:
return "存储权限";
case Permission.camera:
return "相机权限";
case Permission.location:
return "定位权限";
default:
return "未知权限";
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("照片上传")),
body: Center(
child: ElevatedButton(
onPressed: () => _uploadPhoto(context),
child: const Text("选择并上传照片"),
),
),
);
}
}
4.3 权限组管理的核心原则
- 顺序优先:批量申请时,必须先申请权限组的基础权限,再申请依赖权限;
- 最小必要:不要申请无关的权限(如仅需读取照片,就不要申请写入存储权限);
- 统一说明:批量申请时,权限说明要涵盖所有申请的权限,避免用户多次看到授权弹窗。
五、进阶实战三:跨版本兼容处理(适配鸿蒙 3.0-4.0)
鸿蒙系统版本迭代较快,不同 API 版本的权限机制存在差异(如 API 10 新增了 LOCATION_BACKGROUND 权限,API 11 优化了权限申请弹窗交互)。如果不做兼容处理,应用在低版本鸿蒙设备上可能崩溃,在高版本设备上体验不佳。
5.1 鸿蒙各版本权限差异(关键要点)
| 鸿蒙版本 | API 级别 | 权限差异点 |
|---|---|---|
| 3.0 | 9 | 不支持后台定位权限;存储权限无需区分读写(但需声明两个权限) |
| 3.1 | 10 | 新增 LOCATION_BACKGROUND 权限;支持权限申请弹窗自定义 |
| 4.0 | 11 | 优化敏感权限授权逻辑;新增「一次性权限」(如单次定位) |
5.2 跨版本兼容方案(实战代码)
步骤 1:添加版本判断工具类
dart
import 'package:ohos_ability_base/ohos_ability_base.dart';
class HarmonyVersionUtil {
/// 获取当前鸿蒙系统 API 级别
static int getSystemApiLevel() {
final AbilityInfo abilityInfo = AbilityBase.getContext().abilityInfo;
return abilityInfo.apiTargetVersion;
}
/// 是否支持后台定位权限(API 10+)
static bool supportBackgroundLocation() {
return getSystemApiLevel() >= 10;
}
/// 是否支持一次性权限(API 11+)
static bool supportOneTimePermission() {
return getSystemApiLevel() >= 11;
}
}
步骤 2:适配后台定位权限(API 10+)
dart
Future<void> _requestLocationPermission(BuildContext context) async {
List<Permission> permissions = [Permission.location];
// API 10+ 支持后台定位权限,需额外申请
if (HarmonyVersionUtil.supportBackgroundLocation()) {
permissions.add(Permission.locationAlways); // LOCATION_BACKGROUND 对应 Permission.locationAlways
}
final Map<Permission, bool> result = await HarmonyPermissionUtil.requestPermissions(
permissions,
rationale: "为了在后台持续获取你的位置信息,提供实时导航服务,请允许定位权限和后台定位权限(仅在 API 10+ 设备显示)。",
context: context,
);
final bool hasForegroundPermission = result[Permission.location] ?? false;
final bool hasBackgroundPermission = HarmonyVersionUtil.supportBackgroundLocation()
? (result[Permission.locationAlways] ?? false)
: true; // 低版本无需后台权限,默认视为已授权
if (hasForegroundPermission && hasBackgroundPermission) {
debugPrint("定位权限(前台+后台)已授权,开始导航...");
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("定位权限未完全开启,无法提供完整导航服务")),
);
}
}
步骤 3:适配一次性权限(API 11+)
dart
Future<void> _requestOneTimeLocationPermission(BuildContext context) async {
Permission permission;
if (HarmonyVersionUtil.supportOneTimePermission()) {
// API 11+ 支持一次性定位权限(用户无需永久授权)
permission = Permission.locationWhenInUse;
} else {
// 低版本使用普通定位权限
permission = Permission.location;
}
final bool hasPermission = await HarmonyPermissionUtil.requestPermission(
permission,
rationale: "为了获取当前位置推荐附近服务,仅本次使用你的位置信息,无需永久授权。",
context: context,
);
if (hasPermission) {
debugPrint("一次性定位权限已授权,获取当前位置...");
}
}
5.3 兼容处理的核心技巧
- API 级别判断:通过
apiTargetVersion判断系统版本,针对性处理权限差异; - 权限降级:高版本特有的权限(如后台定位),在低版本设备上需降级为普通权限,避免申请不存在的权限导致崩溃;
- 测试覆盖:至少在鸿蒙 3.0(API 9)、3.1(API 10)、4.0(API 11)设备上测试权限申请逻辑。
六、进阶实战四:用户引导与权限体验优化
权限申请的用户体验直接影响应用的留存率 —— 频繁弹窗、说明不清、拒绝后无法操作,都会导致用户流失。以下是企业级应用的权限引导最佳实践。
6.1 权限申请时机优化
| 场景 | 推荐时机 | 反例 |
|---|---|---|
| 核心功能(如相机) | 用户点击「拍照」按钮时申请 | 应用启动时立即申请 |
| 非核心功能(如推送) | 用户首次进入相关页面(如消息中心)时申请 | 应用启动时批量申请所有非核心权限 |
| 后台功能(如后台定位) | 用户开启「持续导航」功能时申请 | 应用启动时默认申请后台定位权限 |
6.2 拒绝后引导策略(实战代码)
当用户拒绝权限后,不要直接阻断功能,应提供「二次引导」,说明权限的必要性:
dart
// 扩展权限工具类,添加二次引导逻辑
extension HarmonyPermissionGuide on HarmonyPermissionUtil {
static Future<bool> requestPermissionWithGuide(
Permission permission, {
required String firstRationale, // 第一次申请说明
required String secondRationale, // 拒绝后二次说明(更详细)
required BuildContext context,
}) async {
final PermissionStatus status = await permission.status;
if (status.isGranted) {
return true;
} else if (status.isDenied) {
// 第一次拒绝:显示二次说明
final bool shouldRequestAgain = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("权限申请必要说明"),
content: Text(secondRationale),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text("暂不开启"),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text("去授权"),
),
],
),
);
if (shouldRequestAgain) {
final PermissionStatus result = await permission.request();
return result.isGranted;
} else {
return false;
}
} else if (status.isPermanentlyDenied) {
// 永久拒绝:引导到设置页面
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("权限已被拒绝"),
content: Text("$secondRationale\n\n请前往系统设置中手动开启权限。"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("取消"),
),
TextButton(
onPressed: () {
PermissionHandlerHarmony.openAppSettings();
Navigator.pop(context);
},
child: const Text("去设置"),
),
],
),
);
return false;
} else {
return false;
}
}
}
6.3 UI 层面的体验优化
- 权限申请弹窗美化:使用自定义弹窗替代系统默认弹窗,提升视觉一致性(示例使用
flutter_smart_dialog插件); - 加载状态提示:权限申请过程中显示加载动画,避免用户重复点击;
- 权限状态可视化:在设置页面显示当前权限状态(已授权 / 未授权),并提供快速跳转设置的入口。
示例:权限状态展示页面
dart
class PermissionSettingPage extends StatelessWidget {
const PermissionSettingPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("权限设置")),
body: ListView(
children: [
_buildPermissionItem(
context,
icon: Icons.camera_alt,
title: "相机权限",
permission: Permission.camera,
description: "用于拍摄照片和视频",
),
_buildPermissionItem(
context,
icon: Icons.storage,
title: "存储权限",
permission: Permission.storage,
description: "用于读取和保存本地文件",
),
_buildPermissionItem(
context,
icon: Icons.location_on,
title: "定位权限",
permission: Permission.location,
description: "用于获取当前位置信息",
),
],
),
);
}
Widget _buildPermissionItem(
BuildContext context, {
required IconData icon,
required String title,
required Permission permission,
required String description,
}) {
return FutureBuilder<PermissionStatus>(
future: permission.status,
builder: (context, snapshot) {
final status = snapshot.data ?? PermissionStatus.denied;
return ListTile(
leading: Icon(icon, color: status.isGranted ? Colors.green : Colors.grey),
title: Text(title),
subtitle: Text(description),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
HarmonyPermissionUtil.getPermissionStatusDesc(status),
style: TextStyle(
color: status.isGranted ? Colors.green : Colors.red,
),
),
const SizedBox(width: 8),
Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey),
],
),
onTap: () {
if (status.isPermanentlyDenied) {
PermissionHandlerHarmony.openAppSettings();
} else {
HarmonyPermissionUtil.requestPermission(
permission,
rationale: "为了正常使用 $title 相关功能,请允许该权限。",
context: context,
);
}
},
);
},
);
}
}
七、常见问题与避坑指南
7.1 权限申请失败,返回 denied 但未弹出弹窗?
- 原因 1:未在
config.json中声明权限(必现); - 原因 2:用户已永久拒绝该权限(鸿蒙第二次拒绝后默认隐藏弹窗);
- 原因 3:权限名称错误(如鸿蒙相机权限是
ohos.permission.CAMERA,而非 Android 的android.permission.CAMERA); - 解决方案:检查
config.json权限声明,通过status.isPermanentlyDenied判断是否永久拒绝,引导用户手动开启。
7.2 批量申请时,部分权限申请失败?
- 原因:权限组依赖顺序错误(如先申请
WRITE_EXTERNAL_STORAGE,再申请READ_EXTERNAL_STORAGE); - 解决方案:使用
_sortPermissionsByGroup方法排序,确保基础权限先申请。
7.3 鸿蒙 3.0 设备上申请后台定位权限崩溃?
- 原因:鸿蒙 3.0(API 9)不支持
LOCATION_BACKGROUND权限; - 解决方案:通过
HarmonyVersionUtil.supportBackgroundLocation()判断系统版本,低版本设备不申请该权限。
7.4 应用上架鸿蒙市场时,权限申请被打回?
- 原因 1:
reason字段不明确(如仅写「用于功能使用」,未说明具体用途); - 原因 2:申请了无关权限(如工具类应用申请定位权限);
- 原因 3:未提供权限关闭入口(需在应用内添加权限设置页面);
- 解决方案:按官方要求优化
config.json权限说明,移除无关权限,添加权限设置页面。
八、总结与扩展学习
本文从「动态权限申请」「权限组管理」「跨版本兼容」「用户引导」四个维度,构建了一套完整的鸿蒙 Flutter 权限管理方案,核心要点:
- 权限申请必须先在
config.json中声明,遵循「按需申请」原则; - 权限组管理需注意基础权限与依赖权限的申请顺序;
- 跨版本兼容的核心是通过 API 级别判断,实现权限降级或升级;
- 良好的用户引导能显著提升权限授权率,避免用户流失。
扩展学习资源
- 鸿蒙官方权限文档:权限概述
- permission_handler_harmony 插件:GitHub 仓库
- 鸿蒙应用上架权限要求:应用市场审核指南
- Flutter 跨平台权限处理最佳实践:Flutter 官方文档
如果你在实际开发中遇到其他权限相关问题,欢迎在评论区留言交流!后续将推出「鸿蒙 Flutter 原生插件开发(权限模块)」进阶文章,敬请关注~
本文原创,转载请注明出处。如果对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
模板
更多推荐






所有评论(0)