Preface
During the recent review of Huawei App Market, a new rule was added as follows:
您的应用在运行时,未同步告知权限申请的使用目的,向用户索取(存储、相机、位置信息)等权限,不符合华为应用市场审核标准。
测试步骤:点击在线聊-拍照/图片,申请存储、相机权限;点击首页-地图找房,申请位置信息权限。
修改建议:APP在调用终端敏感权限时,应同步说明权限申请的使用目的,包括但不限于申请权限的名称、服务的具体功能、用途;告知方式不限于弹窗、蒙层、浮窗、或者自定义操作系统权限弹框等。请排查应用内所有权限申请行为,确保均符合要求。
请参考《审核指南》第7.21相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-07#h3-1683701612940-2
APP常见个人信息保护问题FAQ请参考:https://developer.huawei.com/consumer/cn/doc/app/FAQ-faq-05#h1-1698326401789-0
测试环境:Wi-Fi联网、HonmonyOS 2.0(Nova5)、中文环境。
I will talk about a simple processing method in this blog. Others on the Internet have written too complicated methods. You can test it yourself online.
Look at the effect first
Encapsulation permission judgment tool class
Create a new authorizeUtils.ts file and copy the following code without thinking:
const checkIsIos = async () => {
return new Promise((resolve => {
uni.getSystemInfo({
success: function (res) {
resolve(systemInfo.value.platform === "ios")
}
});
}))
}
export default class authorizeUtils {
/**
* 授权前告知用户使用意图
* @param content
* @returns
*/
static showAuthTipModal = async (authorize: string) => {
// #ifdef H5
if (1 === 1) {
return true
}
// #endif
// ios端在manifest.json配置权限使用说明,以下权限判断仅在安卓端可用
let isIos = await checkIsIos()
if (isIos) return true
let compat: any = plus.android.importClass('androidx.core.content.ContextCompat')
let context = plus.android.runtimeMainActivity()
let result = compat.checkSelfPermission(context, authorize)
console.log("result===", result);
if (result === 0) return true
// // 如果已经授权直接返回
const contentData = {
['android.permission.ACCESS_FINE_LOCATION']: {
title: "定位权限说明",
describe: "便于您使用该功能在地图找房中根据您的位置检索附近的房源,请您确认授权,否则无法使用该功能"
},
["android.permission.READ_EXTERNAL_STORAGE"]: {
title: "相册权限说明",
describe: "便于您使用该功能上传您的照片/图片/视频及用户实名认证信息、发布房源时上传图片,请您确认授权,否则无法使用该功能"
},
["android.permission.CAMERA"]: {
title: "拍摄权限说明",
describe: "便于您使用该功能拍摄身份证、房源、头像、房产证等信息,请您确认授权,否则无法使用该功能"
},
["android.permission.CALL_PHONE"]: {
title: "拨打电话权限说明",
describe: "便于您使用该功能拨打房东、经纪人、管家、客服电话,请您确认授权,否则无法使用该功能"
},
}
return new Promise((resolve) => {
uni.showModal({
title: contentData[authorize].title,
content: contentData[authorize].describe,
success: (res) => {
resolve(!!res.confirm)
},
fail: () => {
}
})
})
}
/**
* 用户拒绝授权提示手动授权
*/
static showManualAuth = async (authorize: string) => {
let isIos = await checkIsIos()
if (isIos) return true
const contentData = {
['android.permission.ACCESS_FINE_LOCATION']: "获取定位权限失败,请手动打开授权或检查系统定位开关",
["android.permission.READ_EXTERNAL_STORAGE"]: "获取相册权限失败,请手动打开授权",
["android.permission.CAMERA"]: "获取拍摄权限失败,请手动打开授权",
["android.permission.CALL_PHONE"]: "获取拨打电话权限失败,请手动打开授权",
}
uni.showModal({
title: '提示',
content: contentData[authorize],
confirmText: "去设置",
success: (res) => {
if (res.confirm) {
uni.openAppAuthorizeSetting({
success(res) {
console.log(res);
}
});
}
if (res.cancel) {
console.log('用户点击取消');
}
}
});
}
}
Usage examples of tool classes
Example of making a call:
// 检查是否授权拨打电话权限
let flag = await authorizeUtils.showAuthTipModal("android.permission.CALL_PHONE")
// 用户拒绝授权
if (!flag) return
uni.makePhoneCall({
phoneNumber, fail: () => {
// 权限开启失败提示用户手动打开权限
authorizeUtils.showManualAuth("android.permission.CALL_PHONE")
}
});
Example of obtaining user location information:
getUserLocation = async (): Promise<null | {
longitude: number, latitude: number }> => {
return new Promise(async (resolve) => {
let authFlag = await authorizeUtils.showAuthTipModal("android.permission.ACCESS_FINE_LOCATION")
if (!authFlag) return resolve(null)
uni.getLocation({
type: "wgs84",
success: ({
longitude, latitude }) => {
return resolve({
longitude, latitude })
},
fail: (fail) => {
this.hideLoading()
authorizeUtils.showManualAuth("android.permission.ACCESS_FINE_LOCATION")
return resolve(null)
}
});
})
}
Notice
The image selection method chooseImage on the app side defaults to the pop-up option of taking a photo and selecting from the album. However, taking a photo and selecting from the album are two different permissions, so this pop-up option needs to be written manually. When the user chooses to take a photo, the camera permission is requested and the selection from the album is To request storage permission, I attach my code here for reference only:
const handleUpload = async (openType: "camera" | "album") => {
if (props.disabled) return;
// #ifdef APP-PLUS
const permissionType = openType === "album" ? "android.permission.READ_EXTERNAL_STORAGE" : "android.permission.CAMERA";
let authFlag = await authorizeUtils.showAuthTipModal(permissionType);
if (!authFlag) return;
// #endif
uni.chooseImage({
sourceType: [openType],
count: props.limit,
success: async (success) => {
},
fail: (fail) => {
if ([0, 11, 12].includes(fail.code)) return;
authorizeUtils.showManualAuth(permissionType);
}
});
};
Android permission list
// android.permission.ACCESS_FINE_LOCATION 位置权限
// android.permission.ACCESS_COARSE_LOCATION 模糊位置权限(蓝牙\ble依赖)
// android.permission.CAMERA 摄像头权限
// android.permission.READ_EXTERNAL_STORAGE 外部存储(含相册)读取权限
// android.permission.WRITE_EXTERNAL_STORAGE 外部存储(含相册)写入权限
// android.permission.RECORD_AUDIO 麦克风权限
// android.permission.READ_CONTACTS 通讯录读取权限
// android.permission.WRITE_CONTACTS 通讯录写入权限
// android.permission.READ_CALENDAR 日历读取权限
// android.permission.WRITE_CALENDAR 日历写入权限
// android.permission.READ_SMS 短信读取权限
// android.permission.SEND_SMS 短信发送权限
// android.permission.RECEIVE_SMS 接收新短信权限
// android.permission.READ_PHONE_STATE 获取手机识别码等信息的权限
// android.permission.CALL_PHONE 拨打电话权限
// android.permission.READ_CALL_LOG 获取通话记录权限
Summarize
Why is it so difficult to beat workers? It’s so difficult to beat workers! !