关键词:鸿蒙、程序访问控制、定位、应用详情页、startability、want
在app开发过程中,常进行系统权限的申请以提供设备访问或个性化功能(如扫一扫、城市定位、剪贴板等),从而保障应用功能的完整性,那么本期文章将以获取定位信息为例从①用户首次拒绝授权,②用户使用期间取消定位授权,③系统定位未开启 3 个方面介绍应用如何申请系统权限与引导用户授权,结尾附其他常用设置页跳转 URI 。
本期完整Demo已提交至Gitee:https://gitee.com/luvi/request-permission
目录
[拒绝权限或途中取消授权 打开应用设置](#拒绝权限或途中取消授权 打开应用设置)
[系统功能未开启 打开系统设置](#系统功能未开启 打开系统设置)
[1. 系统定位未开启](#1. 系统定位未开启)
[2. app定位未允许](#2. app定位未允许)
[3. 示例代码](#3. 示例代码)
[Want 信息 uri 字段与设置页面对应表格](#Want 信息 uri 字段与设置页面对应表格)
拉起授权弹窗
用户首次同意该权限,并且已开启系统定位,那么直接拉起系统权限的申请弹窗即可,需要注意的是使用 AtManager 授权权限的前提是需要在模块的 module.json5 中添加权限。
javascript
// 申请权限需导入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)
})
}
});
})
}
拒绝权限或途中取消授权 打开应用设置
若用户首次拒绝定位权限 或在应用使用期间用户自行取消了定位权限的授权行为,再次使用该权限对应的功能会引发报错问题导致应用程序功能无法正确执行,此时我们需要进行弹窗提示,引导用户前往应用设置页手动开启该权限,只要在功能使用时检查app授权状态即使用户途中取消授权也可进行弹窗提示。
跳转方案:配置 want 信息,使用 startAbility 进行跳转,此处需要设置应用包名信息,直接通过应用上下文 context 获取,不过这里需要断言类型为 UIAbilityContext ,不然没有 bundleName 的获取接口。
javascript
/**
* 打开应用设置
*/
_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)
}
系统功能未开启 打开系统设置
在使用应用该功能过程中,用户未开启系统定位,需引导用户前往系统定位页手动开启定位权限。
跳转方案:配置 want 信息,使用 startAbility 进行跳转。
javascript
/**
* 打开系统设置
*/
_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. 示例代码
javascript
/**
* 获取定位
*/
_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-关于本机-设备名称 | 是 | 是 |