Appearance
权限适配最佳实践
鸿蒙权限适配:动态申请、优雅降级、用户体验优化。
1. 权限申请策略
1.1 渐进式申请
❌ 错误:应用启动时申请所有权限
✅ 正确:在用户需要功能时申请对应权限
用户点击拍照 → 申请相机权限
用户点击定位 → 申请位置权限
用户点击上传 → 申请存储权限1.2 代码实现
typescript
class PermissionAdapter {
// 渐进式申请权限
async requestPermissionForAction(
action: string,
permission: string,
actionCallback: () => Promise<void>
): Promise<void> {
// 1. 检查权限
let status = securityAccessToken.verifyAccessToken({
permissionName: permission
})
if (status === securityAccessToken.GrantStatus.PERMISSION_GRANTED) {
// 已有权限,直接执行
await actionCallback()
return
}
// 2. 向用户解释为什么需要权限
let reason = this.getPermissionReason(permission)
await this.showPermissionDialog(reason, action)
// 3. 请求权限
let granted = await bundleManager.requestPermission({
permission: permission
})
if (granted) {
// 用户授权,执行操作
await actionCallback()
} else {
// 用户拒绝,降级处理
this.handlePermissionDenied(permission, action)
}
}
private getPermissionReason(permission: string): string {
const reasons: Record<string, string> = {
'ohos.permission.CAMERA': '需要相机权限来拍摄照片',
'ohos.permission.LOCATION': '需要位置权限来推荐附近的内容',
'ohos.permission.READ_MEDIA': '需要读取相册来选择图片'
}
return reasons[permission] || '需要此权限来完成操作'
}
private handlePermissionDenied(permission: string, action: string): void {
// 降级处理
switch (permission) {
case 'ohos.permission.CAMERA':
// 无法拍照,提供从相册选择
this.showAlbumPicker()
break
case 'ohos.permission.LOCATION':
// 无法获取位置,让用户手动选择城市
this.showCityPicker()
break
case 'ohos.permission.READ_MEDIA':
// 无法读取相册,提示用户去设置页授权
this.showSettingsGuide()
break
}
}
}2. 权限被拒处理
2.1 引导用户授权
typescript
@Component
struct PermissionDeniedDialog {
@State showDialog: boolean = false
@State permission: string = ''
build() {
if (this.showDialog) {
AlertDialog({
title: '权限被拒绝',
message: `${this.getPermissionName(this.permission)}已被拒绝\n\n` +
'请在设置中手动开启此权限,以继续使用此功能',
primaryButton: {
value: '去设置',
action: () => {
this.openSettings()
}
},
secondaryButton: {
value: '取消',
action: () => {
this.showDialog = false
}
}
})
}
}
private openSettings(): void {
// 跳转到应用设置页
router.pushUrl({
url: 'pages/SettingsPage'
})
}
private getPermissionName(permission: string): string {
const names: Record<string, string> = {
'ohos.permission.CAMERA': '相机',
'ohos.permission.LOCATION': '位置',
'ohos.permission.MICROPHONE': '麦克风'
}
return names[permission] || permission
}
}3. 权限检查工具类
typescript
class PermissionUtils {
// 检查多个权限
static async checkPermissions(permissions: string[]): Promise<Map<string, boolean>> {
let results = new Map<string, boolean>()
for (let perm of permissions) {
let status = securityAccessToken.verifyAccessToken({
permissionName: perm
})
results.set(perm, status === securityAccessToken.GrantStatus.PERMISSION_GRANTED)
}
return results
}
// 请求多个权限
static async requestPermissions(permissions: string[]): Promise<Map<string, boolean>> {
let results = new Map<string, boolean>()
for (let perm of permissions) {
let granted = await bundleManager.requestPermission({
permission: perm
})
results.set(perm, granted)
}
return results
}
// 是否有任一权限
static hasAnyPermission(permissions: string[]): boolean {
for (let perm of permissions) {
let status = securityAccessToken.verifyAccessToken({
permissionName: perm
})
if (status === securityAccessToken.GrantStatus.PERMISSION_GRANTED) {
return true
}
}
return false
}
// 是否所有权限都有
static hasAllPermissions(permissions: string[]): boolean {
for (let perm of permissions) {
let status = securityAccessToken.verifyAccessToken({
permissionName: perm
})
if (status !== securityAccessToken.GrantStatus.PERMISSION_GRANTED) {
return false
}
}
return true
}
}4. 面试高频考点
Q1: 权限申请最佳实践?
回答:渐进式申请(用时再申请)、向用户解释原因、权限被拒后优雅降级、引导用户去设置页。
Q2: 如何处理权限被拒?
回答:显示友好提示、提供降级方案、引导用户去设置页手动授权。
🐱 小猫提示:权限适配记住 "渐进式申请、解释原因、优雅降级、引导设置"。