关键词:鸿蒙、程序访问控制、定位、应用详情页、startability、want

在app开发过程中,常进行系统权限的申请以提供设备访问或个性化功能(如扫一扫、城市定位、剪贴板等),从而保障应用功能的完整性,那么本期文章将以获取定位信息为例从①用户首次拒绝授权,②用户使用期间取消定位授权,③系统定位未开启 3 个方面介绍应用如何申请系统权限与引导用户授权,结尾附其他常用设置页跳转 URI 。

本期完整Demo已提交至Gitee:https://gitee.com/luvi/request-permission

目录

拉起授权弹窗

拒绝权限或途中取消授权 打开应用设置

系统功能未开启 打开系统设置

如何检查系统定位或app定位权限未开启

1. 系统定位未开启

2. app定位未允许

3. 示例代码

权限申请注意事项

Want 信息 uri 字段与设置页面对应表格


拉起授权弹窗

【HarmonyOS NEXT】权限申请及应用设置页跳转_JSON

编辑

用户首次同意该权限,并且已开启系统定位,那么直接拉起系统权限的申请弹窗即可,需要注意的是使用 AtManager 授权权限的前提是需要在模块的 module.json5 中添加权限。

【HarmonyOS NEXT】权限申请及应用设置页跳转_JSON_02

编辑

// 申请权限需导入Access模块
import { abilityAccessCtrl, PermissionRequestResult, Permissions } from '@kit.AbilityKit';


/**
 * 获取定位
 */
async _requestPermission(): Promise<boolean> {
  this.tipsType = TIPS_TYPE.NULL
  return new Promise((r, j) => {
    // 此处 permissionList 需要在项目的 module.json5 文件中添加权限与描述
    let permissionList: Permissions[] = ["ohos.permission.LOCATION", "ohos.permission.APPROXIMATELY_LOCATION"]
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionsFromUser(getContext(), permissionList,
        (err: BusinessError, data: PermissionRequestResult) => {
        if (err) {
          console.error(`luvi > requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
          r(false)
        } else {
          console.info('luvi > data:' + JSON.stringify(data));
          console.info('luvi > data permissions:' + data.permissions);
          console.info('luvi > data authResults:' + data.authResults);
          console.info('luvi > data dialogShownResults:' + data.dialogShownResults);
          // 授权成功
          data.authResults?.forEach((aItem) => {
            aItem == 0 && r(true)
          })
        }
      });
  })
}

拒绝权限或途中取消授权 打开应用设置

【HarmonyOS NEXT】权限申请及应用设置页跳转_bundle_03

编辑

用户首次拒绝定位权限在应用使用期间用户自行取消了定位权限的授权行为,再次使用该权限对应的功能会引发报错问题导致应用程序功能无法正确执行,此时我们需要进行弹窗提示,引导用户前往应用设置页手动开启该权限,只要在功能使用时检查app授权状态即使用户途中取消授权也可进行弹窗提示。

跳转方案:配置 want 信息,使用 startAbility 进行跳转,此处需要设置应用包名信息,直接通过应用上下文 context 获取,不过这里需要断言类型为 UIAbilityContext ,不然没有 bundleName 的获取接口。

/**
 * 打开应用设置
 */
_openAppSetting() {
  let context = getContext(this) as common.UIAbilityContext;
  let want: Want = {
    bundleName: 'com.huawei.hmos.settings', //设置应用bundleName
    abilityName: 'com.huawei.hmos.settings.MainAbility', //设置应用abilityName
    uri: "application_info_entry", //通知管理页面
    parameters: {
      pushParams: context.abilityInfo.bundleName
    }
  }
   context.startAbility(want)
}

系统功能未开启 打开系统设置

【HarmonyOS NEXT】权限申请及应用设置页跳转_JSON_04

编辑

在使用应用该功能过程中,用户未开启系统定位,需引导用户前往系统定位页手动开启定位权限。

跳转方案:配置 want 信息,使用 startAbility 进行跳转。

/**
 * 打开系统设置
 */
_openSysSetting() {
  let context = getContext(this) as common.UIAbilityContext;
  let want: Want = {
    bundleName: 'com.huawei.hmos.settings', //设置应用bundleName
    abilityName: 'com.huawei.hmos.settings.MainAbility', //设置应用abilityName
    uri: "location_manager_settings"
  }
  context.startAbility(want)
}

如何检查系统定位或app定位权限未开启

1. 系统定位未开启

获取位置信息需要使用 geoLocationManager 模块的 getCurrentLocation 方法,在使用该方法前用 try catch 捕获代码异常,若系统权限未开启,则会直接进入 catch 回调中并返回报错原因,若错误码返回 3301100 即代表app权限未开启(同理可利用该回调判断当前设备是否支持定位功能),那么我们可以在此时进行弹窗提示引导用户前往系统设置页面。

2. app定位未允许

若系统定位已开启,app定位权限未允许,在调用 getCurrentLocation 后会进入 Promise 的 .catch() 失败回调中(若使用 callback 形式,则 err 返回值不为空),若错误码返回 201 即代表app权限未开启,那么我们可以在此时进行弹窗提示引导用户前往app设置页面。

3. 示例代码

/**
 * 获取定位
 */
_loadLocation() {
    let request: geoLocationManager.SingleLocationRequest =
      { 'locatingTimeoutMs': 10000, 'locatingPriority': geoLocationManager.LocatingPriority.PRIORITY_ACCURACY };
    try {
      geoLocationManager.getCurrentLocation(request).then((result) => {
        console.log('luvi current location: ' + JSON.stringify(result));
        // 经纬度换城市名
        let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest =
          { "latitude": result.latitude, "longitude": result.longitude, "maxItems": 1 };
        try {
          geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, (err, data) => {
            if (err) {
              console.error('getAddressesFromLocation: err=' + JSON.stringify(err));
            }
            if (data) {
              let res =
                `latitude: ${result.latitude}, longitude: ${result.longitude}, cityName: ${data[0].placeName}`
              this.result = res
              console.log("luvi > res " + res)
            }
          });
        } catch (err) {
          console.error("luvi > errCode:" + JSON.stringify(err));
        }
      })
        .catch((err: BusinessError) => {
          // 应用定位权限未开启
          if (err.code == 201) {
            // 引导用户前往app设置页面
          }
          console.log("luvi > errCode:" + JSON.stringify(err));
        })
    } catch (err) {
      console.log("luvi > errCode:" + JSON.stringify(err));
      // 位置信息获取失败,没有开启系统定位,
      if (err.code == 3301100) {
        // 引导用户前往系统设置页面
      }
    }
 }

权限申请注意事项

并非所有权限都需要拉起弹窗授权,如网络权限只需在 module.json5 中配置即可,如定位、相机、日历则需要用户手动授权,此时需要关注官方文档的描述按规则开发即可。需要注意的是,在拉起系统弹窗授权前一步,APP中需明确告知接下来要授权的权限的作用和使用场景,需自行弹窗描述,当用户手动确认同意后才可进行系统权限的授权拉起操作,否则缺少这一步直接拉起系统授权,应用上架应用市场时可能会审核不通过。

Want 信息 uri 字段与设置页面对应表格

字段

拉起界面

手机设备是否支持

2in1设备是否支持

/(传/会拉起一个空白页面,如果拉起设置首页,传空字符串即可)

HOME-设置

wifi_entry

HOME-WLAN

bluetooth_entry

HOME-蓝牙

mobile_network_entry

HOME-移动网络

hotspot_data_settings

HOME-移动网络-个人热点界面

password_entry

HOME-移动网络-个人热点-密码界面

connected_device_entry

HOME-移动网络-个人热点-已连接设备界面

more_share_entry

HOME-移动网络-个人热点-更多共享设置界面

more_connections_settings

HOME-更多连接

nfc_settings

HOME-更多连接-NFC三级页面

display_settings

HOME-显示和亮度

screen_zoom

HOME-显示和亮度-显示大小三级页面

screen_refresh_rate_entry

HOME-显示和亮度-屏幕刷新率三级页面

需看具体设备是否有刷新率选项

volume_settings

HOME-声音和振动

systemui_notification_settings

HOME-通知和状态栏

accessibility_feature

HOME-辅助功能

accessibility_operation_entry

HOME-辅助功能-辅助功能快捷键三级页面

accessibility_more_settings_entry

HOME-辅助功能-已安装的服务-服务详情-更多设置五级页面

application_and_service_settings

HOME-应用与元服务

application_settings

HOME-应用与服务-应用管理三级页面

application_info_entry

HOME-应用和元服务HOME-某个具体应用的应用信息,需传递want.parameters.pushParams为具体应用的包名

storage_settings

HOME-存储界面

battery

HOME-电池

biometrics_and_password_settings

HOME-生物识别和密码

lock_screen_password_title

HOME-生物识别和密码-设置数字锁屏密码

change_six_to_number_entry

HOME-生物识别和密码-锁屏密码(其他密码类型)-自定义数字密码(设置锁屏数字密码)四级页面

change_six_to_mixed_entry

HOME-生物识别和密码-锁屏密码(其他密码类型)-混合密码(设置锁屏密码)四级页面

fingerprint_settings_entry

HOME-生物识别与密码-指纹3级页面

需看具体设备是否支持指纹解锁能力

privacy_settings

HOME-隐私与安全

location_help_entry

HOME-隐私与安全-定位服务-帮助四级页面

users_accounts

HOME-用户和账户

current_user

HOME-用户和账户-当前登录(用户)三级页面

system_and_updates

HOME-系统和更新

time_zone_settings

HOME-系统和更新-日期时间-时区-时区选择列表

date_and_time

HOME-系统和更新-日期时间三级页面

set_input

HOME-系统和更新-输入法页面



set_language

HOME-系统和更新-语言和输入法-语言和输入法四级页面

set_language_region

HOME-系统和更新-语言和输入法-语言和地区-语言和地区5级页面

reset_settings

HOME-系统和更新-重置三级页面

developer_options_settings

HOME-系统和更新-开发人员选项三级页面

edit_language_entry

HOME-系统和更新-语言和输入法-语言和地区-编辑(编译语言)五级页面

add_language_entry

HOME-系统和更新-语言和输入法-语言和地区-添加语言五级页面

select_region_entry

HOME-系统和更新-语言和输入法-语言和地区-当前地区(选择地区)五级页面

reset_factory_settings

HOME-系统和更新-重置-恢复出厂设置四级页面

reset_net_settings

HOME-系统和更新-重置-还原网络设置四级页面

reset_confirm_settings

HOME-系统和更新-重置-恢复出厂设置-重置手机五级页面

reset_net_confirm_settings

HOME-系统和更新-重置-还原网络设置-还原网络设置确认五级页面

about_device

HOME-关于本机界面

device_name

HOME-关于本机-设备名称