header detail 1
header detail 2
机甲先锋活动站 - 科幻竞技游戏专属平台
机甲先锋活动站 - 科幻竞技游戏专属平台

DevecoStudio学习之权限申请

Home 2025-11-16 04:10:20 DevecoStudio学习之权限申请
机体改装研究院

一、鸿蒙 Next 权限申请概览

鸿蒙 Next 系统为了保护用户数据和系统资源,对应用的权限进行了细致的分类管理。其中,系统授权和用户授权是两种主要的授权方式,它们各自适用于不同类型的权限,开发者需要根据应用的具体功能需求来选择合适的授权方式。这就好比在建造一座大厦时,需要根据不同区域的功能需求选择合适的建筑材料和施工工艺,以确保大厦的稳固与安全。

1. 系统授权:直接配置文件配置申请 (不需要询问用户)

系统授权,正如其名,是由系统在应用安装过程中自动完成的权限授予操作。这种授权方式适用于那些对系统或其他应用影响较小、不涉及用户敏感信息的权限。

例如,应用获取网络信息、查询自身基本信息等操作所需的权限,通常都采用系统授权方式。

2. 用户授权:需要用户手动确认的权限(必须提示用户主动授权)

与系统授权不同,用户授权则更加注重用户的知情权和选择权。当应用需要访问用户的敏感信息或执行可能影响用户隐私的操作时,

如使用摄像头、麦克风、读取通讯录等,就必须通过用户授权方式获得用户的明确许可。这确保了用户始终对自己的数据拥有控制权,就像在自己的私人领地设置了一道道关卡,只有经过用户亲自授权的应用才能进入并使用相关资源。

二、鸿蒙 Next 授权流程解析

1. 系统授权流程解析

🐡 权限判断与申请准备

在进行系统授权之前,开发者首先要明确应用所需的权限,并判断这些权限是否属于系统授权类型。这需要开发者对鸿蒙 Next 的权限体系有深入的了解,熟悉各种权限的分类和适用场景。可以将其类比为航海前的航线规划,只有明确目的地和路线,才能确保航行的顺利进行。

🐡 系统自动授予权限的过程

一旦确定应用所需的权限为系统授权类型,开发者只需在应用的配置文件中正确声明这些权限。当用户安装应用时,系统会自动识别并授予相应的权限,整个过程无需用户进行额外的操作。这就像在一家自动化餐厅,顾客只需选择自己想要的菜品(声明权限),餐厅的自动化系统(鸿蒙 Next 系统)就会自动将菜品送到顾客面前(授予权限)。

🐡 系统授权权限列表展示

以下是一些常见的系统授权权限及其说明:

🐡 在配置文件中声明权限

配置文件的选择与定位

用户授权的第一步是在应用的配置文件中声明所需的权限。在鸿蒙 Next 项目中,通常使用“module.json5”配置文件来进行权限声明。这个配置文件就像是应用的“说明书”,告诉系统应用需要哪些权限才能正常运行。

权限声明的格式与规范在“module.json5”文件中,通过“requestPermissions”字段来声明权限。每个权限声明都包含“name”(权限名称)、“reason”(申请权限的原因)和“usedScene”(权限使用的场景)等属性。

🔊说明: 以下"ohos.permission.PERMISSION1"、"ohos.permission.PERMISSION2"仅为样例示意,不存在该权限。请开发者根据实际需要,参照上表要求填写对应属性。

{

"module" : {

// ...

"requestPermissions":[

{

"name" : "ohos.permission.PERMISSION1",

"reason": "$string:reason",

"usedScene": {

"abilities": [

"FormAbility"

],

"when":"inuse"

}

},

{

"name" : "ohos.permission.PERMISSION2",

"reason": "$string:reason",

"usedScene": {

"abilities": [

"FormAbility"

],

"when":"always"

}

}

]

}

}

其中,“name”必须是系统定义的有效权限名称,“reason”需要用简洁明了的语言向用户说明申请该权限的原因,并且要遵循一定的文案规范,如使用直白、具体、易理解的完整短句,避免使用被动语态,以句号结尾,同时要确保字符串长度适中,以适应多语言适配的需求。“usedScene”则用于指定权限使用的场景,包括使用权限的 UIAbility 或 ExtensionAbility 组件名称以及调用时机(“inuse”表示使用时,“always”表示始终)。

2. 用户授权流程详解

🐡 用户授权权限列表展示

以下是一些常见的用户授权权限及其说明:

🐡 在配置文件中声明权限

与“系统授权”一样,“用户授权”,在动态请求用户授权之前,应用应该先检查当前是否已经获得了所需的权限。在“module.json5”文件中,通过“requestPermissions”字段来声明权限。每个权限声明都包含“name”(权限名称)、“reason”(申请权限的原因)和“usedScene”(权限使用的场景)等属性。例如:

🔊说明: 以下"ohos.permission.PERMISSION1"、"ohos.permission.PERMISSION2"仅为样例示意,不存在该权限。请开发者根据实际需要,参照上表要求填写对应属性。

{

"module" : {

// ...

"requestPermissions":[

{

"name" : "ohos.permission.PERMISSION1",

"reason": "$string:reason",

"usedScene": {

"abilities": [

"FormAbility"

],

"when":"inuse"

}

},

{

"name" : "ohos.permission.PERMISSION2",

"reason": "$string:reason",

"usedScene": {

"abilities": [

"FormAbility"

],

"when":"always"

}

}

]

}

}

🐡 使用 API 动态请求用户授权

权限检查与准备

在动态请求用户授权之前,应用应该先检查当前是否已经获得了所需的权限。这可以通过调用“checkAccessToken()”函数来实现,该函数会返回“PERMISSION_GRANTED”或“PERMISSION_DENIED”,以指示当前权限的授予状态。这就好比在进入一个需要门票的场所之前,先检查自己是否已经购买了门票。

import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';

import { BusinessError } from '@kit.BasicServicesKit';

const permissions: Array = ['ohos.permission.MICROPHONE'];

async function checkPermissionGrant(permission: Permissions): Promise {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

// 获取应用程序的accessTokenID

let tokenId: number = 0;

try {

let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);

let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;

tokenId = appInfo.accessTokenId;

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);

}

// 校验应用是否被授予权限

try {

grantStatus = await atManager.checkAccessToken(tokenId, permission);

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);

}

return grantStatus;

}

async function checkPermissions(): Promise {

let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant(permissions[0]);

if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {

// 已经授权,可以继续访问目标操作

} else {

// 申请麦克风权限

}

}

动态请求授权的 API 调用

动态向用户申请权限是指在应用程序运行时向用户请求授权的过程。可以通过调用requestPermissionsFromUser()方法来实现。该方法接收一个权限列表参数,例如位置、日历、相机、麦克风等。用户可以选择授予权限或者拒绝授权。

可以在UIAbility的onWindowStageCreate()回调中调用requestPermissionsFromUser()方法来动态申请权限,也可以根据业务需要在UI中向用户申请授权。

应用在onWindowStageCreate()回调中申请授权时,需要等待异步接口loadContent()/setUIContent()执行结束后或在loadContent()/setUIContent()回调中调用requestPermissionsFromUser(),否则在Content加载完成前,requestPermissionsFromUser会调用失败。

应用在UIExtensionAbility申请授权时,需要在onWindowStageCreate函数执行结束后或在onWindowStageCreate函数回调中调用requestPermissionsFromUser(),否则在ability加载完成前,requestPermissionsFromUser会调用失败。

🐹:在UIAbility中向用户申请授权

// 使用UIExtensionAbility:将import { UIAbility } from '@kit.AbilityKit' 替换为import { UIExtensionAbility } from '@kit.AbilityKit';

import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';

import { window } from '@kit.ArkUI';

import { BusinessError } from '@kit.BasicServicesKit';

const permissions: Array = ['ohos.permission.MICROPHONE'];

// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext

function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗

atManager.requestPermissionsFromUser(context, permissions).then((data) => {

let grantStatus: Array = data.authResults;

let length: number = grantStatus.length;

for (let i = 0; i < length; i++) {

if (grantStatus[i] === 0) {

// 用户授权,可以继续访问目标操作

} else {

// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限

return;

}

}

// 授权成功

}).catch((err: BusinessError) => {

console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);

})

}

// 使用UIExtensionAbility:将 UIAbility 替换为UIExtensionAbility

export default class EntryAbility extends UIAbility {

onWindowStageCreate(windowStage: window.WindowStage): void {

// ...

windowStage.loadContent('pages/Index', (err, data) => {

reqPermissionsFromUser(permissions, this.context);

// ...

});

}

// ...

}

🐹:在UI中向用户申请授权

import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';

import { BusinessError } from '@kit.BasicServicesKit';

const permissions: Array = ['ohos.permission.MICROPHONE'];

// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext

function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗

atManager.requestPermissionsFromUser(context, permissions).then((data) => {

let grantStatus: Array = data.authResults;

let length: number = grantStatus.length;

for (let i = 0; i < length; i++) {

if (grantStatus[i] === 0) {

// 用户授权,可以继续访问目标操作

} else {

// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限

return;

}

}

// 授权成功

}).catch((err: BusinessError) => {

console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);

})

}

@Entry

@Component

struct Index {

aboutToAppear() {

// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext

const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;

reqPermissionsFromUser(permissions, context);

}

build() {

// ...

}

}

!!!注意,如果用户拒绝了,再此调用requestPermissionsFromUser是不会再此弹出来的。如果还需要选项,就需要引导用户去设置里面授权。

二次向用户申请授权

requestPermissionOnSetting打开应用设置权限界面,可以参考打开应用设置权限界面。此节不详细说明。第一次被拒绝后,那么需要引导用户去设置中,授权。

const secondAuthResults = await atManager.requestPermissionOnSetting(context, permissions)

const isSecondAuth = secondAuthResults.every(s => s == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)

!!!注意,在这里设置会有三种情况。

设置中授权界面一般会有三个选项:1、仅使用期间允许;2、每次使用询问;3、禁止;

只有第一个选项,结果会返回授权了。第三个选项,好理解,就是不授权。但是要注意了,第二个选项也是返回不授权。但是我们明显是知道用户是授权了的。所以上面的代码返回false之后,还需要再次调用第一次授权的代码,再次询问用户是否授权了。

下面是完整二次授权代码

const secondAuthResults = await atManager.requestPermissionOnSetting(context, permissions)

const isSecondAuth = secondAuthResults.every(s => s == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)

if (!isSecondAuth) {

const isAuth = await firstReqPermissionFormUser(permissions, context)

resolve(isAuth)

} else {

resolve(true)

}

完整请求权限工具类代

import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';

import { UIContext } from '@kit.ArkUI';

import { BusinessError } from '@kit.BasicServicesKit';

async function checkPermissionGrant(permission: Permissions): Promise {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

// 获取应用程序的accessTokenID

let tokenId: number = 0;

try {

let bundleInfo: bundleManager.BundleInfo =

await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);

let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;

tokenId = appInfo.accessTokenId;

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);

}

// 校验应用是否被授予权限

try {

grantStatus = await atManager.checkAccessToken(tokenId, permission);

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);

}

return grantStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;

}

async function firstReqPermissionFormUser(permissions: Array, context: common.UIAbilityContext) {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

const data = await atManager.requestPermissionsFromUser(context, permissions)

let grantStatus: Array = data.authResults;

return grantStatus.every(s => s == 0)

}

async function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext,

uiContext: UIContext) {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

try {

// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗

const isAuth = await firstReqPermissionFormUser(permissions, context)

if (isAuth) {

return true

}

return await new Promise((resolve, reject) => {

uiContext.showAlertDialog({

title: "系统提示",

message: "必须要授权才能使用,是否前往应用进行授权",

autoCancel: false,

primaryButton: {

value: "取消",

action: () => {

resolve(false)

}

},

secondaryButton: {

value: "前往授权",

action: async () => {

const secondAuthResults = await atManager.requestPermissionOnSetting(context, permissions)

const isSecondAuth =

secondAuthResults.every(s => s == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)

if (!isSecondAuth) {

const isAuth = await firstReqPermissionFormUser(permissions, context)

resolve(isAuth)

} else {

resolve(true)

}

}

}

})

})

} catch (err) {

const error = err as BusinessError

console.error(`Failed to request permissions from user. Code is ${error.code}, message is ${error.message}`);

}

return true

}

export async function requestPermissions(uiAbilityContext: common.UIAbilityContext, uiContext: UIContext,

permissions: Permissions[]) {

const ps = permissions.map((s) => {

return checkPermissionGrant(s).then(isSuccess => {

if (isSuccess) {

return true

}

return Promise.reject(s)

})

})

const s = await Promise.allSettled(ps)

const rejectedPs =

s.filter(item => item.status == "rejected").map((item: PromiseRejectedResult) => item.reason as Permissions)

if (rejectedPs.length == 0) {

return true

}

return await reqPermissionsFromUser(rejectedPs, uiAbilityContext, uiContext)

}

🐡 处理用户授权结果

授权成功后的操作

当用户授权成功后,应用可以继续执行需要该权限的操作。例如,如果应用申请了相机权限并获得授权,就可以打开相机进行拍照或录像操作。这就像获得了进入宝库的钥匙,可以顺利取出宝藏(执行相应功能)。

授权失败后的应对策略

如果用户拒绝授权,应用需要友好地提示用户授权的必要性,并引导用户前往系统设置中手动授予权限。同时,应用应该确保在用户未授权的情况下,不会影响其他无关功能的正常使用。这就好比在一扇紧闭的门前,向用户解释门后的精彩内容,并引导用户找到打开门的正确方法,而不是强行推门或影响周围环境的正常秩序。

3. 不同权限类型申请方式总结

为了更清晰地展示不同权限类型的申请方式,我们通过以下表格进行总结:

三、示例代码:请求麦克风权限

以下是一个完整的示例代码,演示了如何在鸿蒙 Next 应用中请求麦克风权限:

import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';

import { BusinessError } from '@kit.BasicServicesKit';

// 定义需要申请的权限列表,这里仅包含麦克风权限

const permissions: Array = ['ohos.permission.MICROPHONE'];

// 检查当前应用是否已被授予指定权限

async function checkPermissionGrant(permission: Permissions): Promise {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

// 获取应用程序的 accessTokenID

let tokenId: number = 0;

try {

let bundleInfo: bundleManager.BundleInfo =

await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);

let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;

tokenId = appInfo.accessTokenId;

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);

}

// 校验应用是否被授予权限

try {

grantStatus = await atManager.checkAccessToken(tokenId, permission);

} catch (error) {

const err: BusinessError = error as BusinessError;

console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);

}

return grantStatus;

}

// 检查权限并根据结果进行相应操作

async function checkPermissions(): Promise {

let grantStatus: abilityAccessCtrl.GrantStatus = await checkPermissionGrant(permissions[0]);

if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {

// 已经授权,可以继续访问目标操作,这里可以添加使用麦克风的相关代码

console.log('已获得麦克风权限,可以进行录音等操作。');

} else {

// 申请麦克风权限

reqPermissionsFromUser(permissions);

}

}

// 使用 API 动态请求用户授权

function reqPermissionsFromUser(permissions: Array): void {

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

atManager.requestPermissionsFromUser(globalThis.context as common.UIAbilityContext, permissions).then((data) => {

let grantStatus: Array = data.authResults;

let length: number = grantStatus.length;

for (let i = 0; i < length; i++) {

if (grantStatus[i] === 0) {

// 用户授权,可以继续访问目标操作,这里可以添加使用麦克风的相关代码

console.log('用户已授权麦克风权限,可以进行录音等操作。');

} else {

// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限

console.log('用户拒绝授权麦克风权限,请前往系统设置中手动授予权限。');

return;

}

}

// 授权成功

}).catch((err: BusinessError) => {

console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);

});

}

// 在应用启动或需要使用麦克风的地方调用 checkPermissions() 函数来检查和申请权限

checkPermissions();

在上述代码中,首先定义了需要申请的麦克风权限。然后,通过“checkPermissionGrant()”函数检查应用当前是否已获得该权限。如果未获得权限,则调用“reqPermissionsFromUser()”函数向用户发起授权请求。根据用户的授权结果,应用会在控制台输出相应的提示信息,并在授权成功后可以继续执行使用麦克风的相关操作。

总之,在鸿蒙 Next 应用开发中,正确处理权限申请是至关重要的。开发者需要深入理解系统授权和用户授权的机制与流程,根据应用的实际需求合理选择授权方式,并严格按照规范进行权限声明和请求操作。只有这样,才能确保应用在保障用户数据安全的前提下,提供稳定、优质的服务。

Post navigation

  • Prev Post 鬼州的解释
Copyright © 2088 机甲先锋活动站 - 科幻竞技游戏专属平台 All Rights Reserved.
友情链接