• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 向用户申请授权
2
3<!--Kit: Ability Kit-->
4<!--Subsystem: Security-->
5<!--Owner: @xia-bubai-->
6<!--Designer: @linshuqing; @hehehe-li-->
7<!--Tester: @leiyuqian-->
8<!--Adviser: @zengyawen-->
9
10当应用需要访问用户的隐私信息或使用系统能力时,如获取位置信息、访问日历、使用相机拍摄照片或录制视频等,应向用户申请授权。这些权限属于user_grant权限。
11
12当应用申请user_grant权限时,需完成以下步骤:
13
141. 在配置文件中,声明应用需要请求的权限。
15
162. 将应用中需要申请权限的目标对象与对应权限关联,确保用户明确哪些操作需授予应用指定权限。
17   以上两步请参考章节[声明权限](declare-permissions.md)完成。
18
193. 运行应用时,用户触发访问目标对象时应调用接口,精准触发动态授权弹框。接口内部会检查当前用户是否已授权所需权限,若未授权,将拉起动态授权弹框请求用户授权。
20
214. 检查用户的授权结果,确认用户已授权后,再进行下一步操作。
22
23本章节将详细介绍如何完成步骤3和4。
24
25## 约束与限制
26
27- user_grant权限授权要基于用户可知可控的原则,需要应用在运行时主动调用系统动态申请权限的接口,系统弹框由用户授权,用户结合应用运行场景的上下文,识别出应用申请相应敏感权限的合理性,从而做出正确的选择。
28
29- 系统不鼓励频繁弹窗打扰用户。如果用户拒绝授权,将无法再次弹窗,应用需引导用户在系统设置中手动授予权限。或是调用[requestPermissionOnSetting](request-user-authorization-second.md),拉起权限设置弹窗,引导用户授权。
30
31- 系统权限弹窗不可被遮挡。
32
33  系统权限弹窗不可被其他组件或控件遮挡,弹窗信息需完整展示,便于用户识别并完成授权。
34  如果系统权限弹窗与其他组件/控件同时在相同位置展示,系统权限弹窗将默认覆盖其他组件/控件。
35
36- 每次执行需要目标权限的操作时,应用都必须检查自己是否已经具有该权限。
37
38  如需检查用户是否已向您的应用授予特定权限,可以使用[checkAccessToken()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#checkaccesstoken9)函数。此方法会返回[PERMISSION_GRANTED](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#grantstatus)或[PERMISSION_DENIED](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#grantstatus)。具体示例可参考下文。
39
40- 每次访问受目标权限保护的接口之前,都需要使用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)接口请求相应的权限。
41
42  用户可能在动态授予权限后通过系统设置来取消应用的权限,因此不能将之前授予的授权状态持久化。
43
44- 应用在onWindowStageCreate()回调中申请授权时,需要等待异步接口loadContent()/setUIContent()执行结束后或在loadContent()/setUIContent()回调中调用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9),否则在Content加载完成前,requestPermissionsFromUser会调用失败。
45  <!--RP1--><!--RP1End-->
46
47## 开发步骤
48
49以申请使用位置权限为例进行说明。
50
51效果展示:
52
53<!--RP4-->
54![zh-cn_image_location](figures/zh-cn_image_location.png)
55<!--RP4End-->
56
571. 申请ohos.permission.LOCATIONohos.permission.APPROXIMATELY_LOCATION权限,配置方式请参见[声明权限](declare-permissions.md)。
58
592. 校验当前是否已经授权。
60
61   在进行权限申请之前,需要先检查当前应用程序是否已经被授予权限。可以通过调用[checkAccessToken()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#checkaccesstoken9)方法来校验当前是否已经授权。如果已经授权,则可以直接访问目标操作,否则需要进行下一步操作,即向用户申请授权。
62
63   ```ts
64   import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
65   import { BusinessError } from '@kit.BasicServicesKit';
66
67   async function checkPermissionGrant(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
68     let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
69     let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
70
71     // 获取应用程序的accessTokenID。
72     let tokenId: number = 0;
73     try {
74       let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
75       let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
76       tokenId = appInfo.accessTokenId;
77     } catch (error) {
78       const err: BusinessError = error as BusinessError;
79       console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
80     }
81
82     // 校验应用是否被授予权限。
83     try {
84       grantStatus = await atManager.checkAccessToken(tokenId, permission);
85     } catch (error) {
86       const err: BusinessError = error as BusinessError;
87       console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
88     }
89
90     return grantStatus;
91   }
92
93   async function checkPermissions(): Promise<void> {
94     let grantStatus1: boolean = await checkPermissionGrant('ohos.permission.LOCATION') === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;// 获取精确定位权限状态。
95     let grantStatus2: boolean = await checkPermissionGrant('ohos.permission.APPROXIMATELY_LOCATION') === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;// 获取模糊定位权限状态。
96     // 精确定位权限只能跟模糊定位权限一起申请,或者已经有模糊定位权限才能申请精确定位权限。
97     if (grantStatus2 && !grantStatus1) {
98        // 申请精确定位权限。
99     } else if (!grantStatus1 && !grantStatus2) {
100        // 申请模糊定位权限与精确定位权限或单独申请模糊定位权限。
101     } else {
102        // 已经授权,可以继续访问目标操作。
103     }
104   }
105   ```
106
1073. 动态向用户申请授权。
108
109   动态向用户申请权限是指在应用程序运行时向用户请求授权的过程。可以通过调用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法来实现。该方法接收一个权限列表参数,例如位置、日历、相机、麦克风等。用户可以选择授予权限或者拒绝授权。
110
111   可以在UIAbility的onWindowStageCreate()回调中调用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法动态请求授权,或根据业务需要在UI中请求授权。
112
113   应用在onWindowStageCreate()回调中申请授权时,需要等待异步接口loadContent()/setUIContent()执行结束后或在loadContent()/setUIContent()回调中调用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9),否则在Content加载完成前,requestPermissionsFromUser会调用失败。
114
115   <!--RP1--><!--RP1End-->
116
117   <!--RP2-->
118   - 在UIAbility中向用户申请授权。
119
120      ```ts
121      import { abilityAccessCtrl, common, Permissions, UIAbility } from '@kit.AbilityKit';
122      import { window } from '@kit.ArkUI';
123      import { BusinessError } from '@kit.BasicServicesKit';
124
125      const permissions: Array<Permissions> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
126      function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
127        let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
128        // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗。
129        atManager.requestPermissionsFromUser(context, permissions).then((data) => {
130          let grantStatus: Array<number> = data.authResults;
131          let length: number = grantStatus.length;
132          for (let i = 0; i < length; i++) {
133            if (grantStatus[i] === 0) {
134              // 用户授权,可以继续访问目标操作。
135            } else {
136              // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限。
137              return;
138            }
139          }
140          // 授权成功。
141        }).catch((err: BusinessError) => {
142          console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
143        })
144      }
145      export default class EntryAbility extends UIAbility {
146        onWindowStageCreate(windowStage: window.WindowStage): void {
147          // ...
148          windowStage.loadContent('pages/Index', (err, data) => {
149            reqPermissionsFromUser(permissions, this.context);
150          // ...
151          });
152        }
153
154        // ...
155      }
156      ```
157
158   - 在UI中向用户申请授权。
159
160      ```ts
161      import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
162      import { BusinessError } from '@kit.BasicServicesKit';
163
164      const permissions: Array<Permissions> = ['ohos.permission.LOCATION','ohos.permission.APPROXIMATELY_LOCATION'];
165      function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
166        let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
167        // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗。
168        atManager.requestPermissionsFromUser(context, permissions).then((data) => {
169          let grantStatus: Array<number> = data.authResults;
170          let length: number = grantStatus.length;
171          for (let i = 0; i < length; i++) {
172            if (grantStatus[i] === 0) {
173              // 用户授权,可以继续访问目标操作。
174            } else {
175              // 当用户拒绝授权时,系统应提示用户必须授予相应权限才能使用当前页面的功能,并指导用户前往系统设置开启所需权限。
176              return;
177            }
178          }
179          // 授权成功。
180        }).catch((err: BusinessError) => {
181          console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
182        })
183      }
184
185      @Entry
186      @Component
187      struct Index {
188        aboutToAppear() {
189          const context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
190          reqPermissionsFromUser(permissions, context);
191        }
192
193        build() {
194          // ...
195        }
196      }
197      ```
198   <!--RP2End-->
199
2004. 处理授权结果。
201
202   调用[requestPermissionsFromUser()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissionsfromuser9)方法后,应用程序将等待用户授权的结果。
203
204   如果用户授权,则可以继续访问目标操作。
205
206   如果用户拒绝授权,则需要提示用户必须授权才能访问当前页面的功能,并引导用户到系统应用“设置”中打开相应的权限;或是调用[requestPermissionOnSetting()](../../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#requestpermissiononsetting12),拉起权限设置弹框,引导用户授权。<!--RP3-->
207
208
209   路径:设置 \> 隐私 \> 权限管理 \> 应用 \> 目标应用<!--RP3End-->
210