在鸿蒙元服务开发中,ASCF 把权限申请收口到一个方法:has.authorize。无论是访问位置、通讯录、日历等用户数据,还是调用相机、麦克风、蓝牙等系统能力,都要先拿到用户授权。它看起来简单,但 scope 怎么配、module.json5 怎么声明、用户拒绝后怎么办,实际开发中很容易踩坑。下面按基本调用、权限声明、scope 对照、典型场景和排障点梳理。
一、has.authorize 基本调用
has.authorize 只有一个方法入口,scope 必填,用于指定申请的权限类型。如果用户之前已经同意过授权,不会再弹窗,直接走 success。- has.authorize({
- scope: 'scope.userLocation',
- success: () => {
- console.info('用户已授权');
- },
- fail: (err) => {
- console.error('授权失败:', err);
- }
- });
复制代码
二、权限配置三步走
第一步,在 module.json5 的 requestPermissions 中声明系统权限,例如 CAMERA、MICROPHONE、LOCATION、APPROXIMATELY_LOCATION。不声明就调用 authorize,会直接走 fail。
第二步,在代码里通过 has.authorize 请求授权:- has.authorize({
- scope: 'scope.camera',
- success: () => { /* 权限已拿到 */ },
- fail: (err) => { /* 被拒绝或未声明 */ }
- });
复制代码 第三步,处理失败情况。用户可能拒绝授权,拒绝后再次调用 has.authorize,可能不再弹窗,直接走 fail。
三、scope 与系统权限对照
位置:scope.userLocation 对应精确定位,需要 LOCATION 和 APPROXIMATELY_LOCATION 两个权限;scope.userFuzzyLocation 对应模糊定位,只需要 APPROXIMATELY_LOCATION。
设备:scope.camera 用于相机;scope.record 用于录音,录像需要同时具备 camera 和 record 权限。
联系人:scope.contact。
日历:scope.calendar。
蓝牙:scope.bluetooth。
通知:scope.notification。
这里要注意,一个 scope 可能对应多个系统权限,漏声明一个都会失败。
四、先授权再调用是常见模式
几乎所有需要权限的 API,都要先 authorize 再调用。直接调用业务 API,没授权时可能直接失败;正确做法是先申请对应 scope,再在 success 回调里调用业务 API。项目里蓝牙、通讯录、日历、WiFi 都遵循这个顺序。- // 蓝牙
- has.authorize({
- scope: 'scope.bluetooth',
- success: () => {
- has.openBluetoothAdapter({ ... });
- }
- });
- // 通讯录
- has.authorize({
- scope: 'scope.contact',
- success: () => {
- has.addPhoneContact({ ... });
- }
- });
- // 日历
- has.authorize({
- scope: 'scope.calendar',
- success: () => {
- has.addPhoneCalendar({ ... });
- }
- });
- // WiFi:获取列表需要定位权限
- has.authorize({
- scope: 'scope.userLocation',
- success: () => {
- has.getWifiList({ ... });
- }
- });
复制代码 其中 WiFi 获取列表需要 scope.userLocation 权限,因为 WiFi 信息可用于定位,这一点比较反直觉。
五、用 Promise 封装授权
每次都写 success/fail 回调比较繁琐,可以封装成 Promise:- function authorize(scope) {
- return new Promise((resolve, reject) => {
- has.authorize({
- scope: scope,
- success: () => resolve(),
- fail: (err) => reject(err)
- });
- });
- }
- async function getLocation() {
- try {
- await authorize('scope.userLocation');
- const location = await new Promise((resolve, reject) => {
- has.getLocation({
- success: (res) => resolve(res),
- fail: (err) => reject(err)
- });
- });
- console.info('位置:', location);
- } catch (err) {
- console.error('获取位置失败:', err);
- }
- }
复制代码
六、典型场景
场景一,一次性申请多个权限。某些功能需要多个权限,比如录像需要相机和麦克风:- async function startRecording() {
- try {
- await authorize('scope.camera');
- await authorize('scope.record');
- // 两个权限都拿到了
- const ctx = has.createCameraContext();
- ctx.startRecord({ ... });
- } catch (err) {
- has.showToast({ title: '需要相机和麦克风权限' });
- }
- }
复制代码 场景二,权限拒绝后的引导。用户拒绝后再次调用 authorize 可能不再弹窗,可以提示用户去设置页手动开启:- has.authorize({
- scope: 'scope.userLocation',
- fail: (err) => {
- has.showModal({
- title: '需要定位权限',
- content: '请在设置中开启定位权限',
- confirmText: '去设置',
- success: (res) => {
- if (res.confirm) {
- has.openSetting({
- success: (settingRes) => {
- // 检查用户是否在设置里开启了权限
- console.info('设置结果:', settingRes);
- }
- });
- }
- }
- });
- }
- });
复制代码 has.openSetting 可以打开元服务的设置页面,用户可以在那里手动开启权限。
场景三,按需申请。不要一进应用就申请所有权限,用户会烦。应该在真正需要的时候再申请:- Page({
- // 用户点击扫一扫按钮时才申请相机权限
- onScanTap() {
- has.authorize({
- scope: 'scope.camera',
- success: () => {
- has.scanCode({
- success: (res) => {
- console.info('扫码结果:', res.result);
- }
- });
- },
- fail: () => {
- has.showToast({ title: '需要相机权限才能扫码' });
- }
- });
- },
- // 用户点击添加联系人时才申请通讯录权限
- onAddContact() {
- has.authorize({
- scope: 'scope.contact',
- success: () => {
- has.addPhoneContact({ ... });
- }
- });
- }
- });
复制代码
七、常见踩坑与排障
1. module.json5 没声明权限。这是最常见错误,scope 对应的系统权限必须在 requestPermissions 里声明,否则直接 fail。比如 scope.userLocation 必须声明 LOCATION 和 APPROXIMATELY_LOCATION 两个权限。
2. scope 和系统权限的对应关系不是一一对应。一个 scope 可能对应多个系统权限,漏一个都会失败。
3. 用户拒绝后不再弹窗。再次调用 has.authorize 可能直接走 fail,需要用 has.openSetting 引导用户去设置里手动开启。
4. WiFi 需要定位权限。获取 WiFi 列表需要 scope.userLocation 权限。
5. 后台定位需要额外配置。scope.userFuzzyLocation 用于前台定位;如果需要后台持续定位,除了权限,还需要在 module.json5 里配置 backgroundModes: ['location']。
6. 单次授权。HarmonyOS 支持单次授权,用户选择仅本次允许后,下次使用时需要重新申请,不要假设之前授权过就一直有效。
7. 权限分类。ASCF 的 scope 对应的都是敏感权限,所以都会弹窗。
八、小结
ASCF 授权 API 只有 has.authorize 一个方法,但它是所有需要权限 API 的前置步骤。排查时先记住三步:module.json5 声明权限、代码里 authorize、处理失败情况。用户拒绝后用 openSetting 引导,按需申请,不要一次性全申请。遇到 fail,先检查 module.json5 有没有声明对应的系统权限,再检查 scope 是否正确。 |