获取权限前给用户提示,并在用户拒绝后48小时内不再弹窗请求授权。
优化方案分析
您的代码已经实现了基本的权限申请逻辑,但可以进一步优化以满足应用商店的审核要求。
1. 权限申请前的用户提示优化
当前代码中已经包含了权限申请前的提示功能,但可以增强用户体验:
// 优化提示内容,增加更友好的解释
uni.showModal({
title: "需要以下权限",
content: "为了给您提供更好的服务,我们需要以下权限:\n\n" +
"• 相机权限 - 用于拍照上传功能\n" +
"• 存储权限 - 用于选择照片和文件\n\n" +
"我们承诺严格保护您的隐私安全",
success(res) {
if (res.confirm) {
// 用户同意后申请权限
plus.android.requestPermissions(requestPermissions, (e) => {
// 处理权限申请结果
});
} else {
// 用户拒绝,记录时间
androidPermissions[permission] = new Date().getTime();
axCc.saveStorage("_androidPermissions", androidPermissions);
}
}
});
2. 48小时限制逻辑优化
您的代码中已经实现了48小时限制逻辑,但可以更明确:
// 检查是否在48小时限制期内
const nowTime = new Date().getTime();
const lastDeniedTime = androidPermissions[permission] || 0;
const hours48 = 48 * 60 * 60 * 1000; // 48小时的毫秒数
if (lastDeniedTime && (nowTime - lastDeniedTime) < hours48) {
// 在48小时内,不再请求
return back ? back(-2) : vueSelf.$callback("abAct.userPermissions", proj, -2);
}
3. 权限申请流程优化
建议将权限申请流程分为几个清晰的阶段:
- 权限检查阶段:检查是否已有权限
- 时间限制检查:检查是否在48小时限制期内
- 用户提示阶段:向用户解释权限用途
- 权限申请阶段:实际申请权限
- 结果处理阶段:处理用户选择
完整优化代码
以下是优化后的代码结构建议(不改变原有逻辑,仅增强可读性和用户体验):
userPermissions(v?: string, back?: any) {
proj = proj || vueSelf.$proj(tag, source);
// #ifdef APP
try {
if (axCc.info.platform == "android") {
let permissionDs: any[] = JSON.parse(v);
let permissionState = false;
let permissionDenied = "";
// 解析权限配置
if (!Array.isArray(permissionDs)) {
if (Array.isArray(permissionDs.permissionList)) {
permissionState = permissionDs.state;
permissionDenied = permissionDs.denied;
permissionDs = permissionDs.permissionList;
} else {
permissionDs = [permissionDs];
}
}
// 初始化权限存储
let androidPermissions = SdkActs._androidPermissions;
if (!androidPermissions) {
androidPermissions = axCc.getStorage("_androidPermissions") || {};
SdkActs._androidPermissions = androidPermissions;
}
const mainActivity = plus.android.runtimeMainActivity();
const nowTime = new Date().getTime();
const HOURS_48_MS = 48 * 60 * 60 * 1000;
// 过滤已授权和受限权限
let requestPermissions = [];
let needExplain = false;
let explanation = "";
for (let permissionD of permissionDs) {
const permission = permissionD.androidPermission;
// 已授权检查
if (androidPermissions[permission] === 1 ||
mainActivity.checkSelfPermission(permission) === 0) {
androidPermissions[permission] = 1;
continue;
}
// 48小时限制检查
const lastDeniedTime = androidPermissions[permission] || 0;
if (lastDeniedTime && (nowTime - lastDeniedTime) < HOURS_48_MS) {
if (permissionDenied) {
return showDeniedModal(back, proj);
}
return back ? back(-2) : vueSelf.$callback("abAct.userPermissions", proj, -2);
}
// 准备请求的权限
requestPermissions.push(permission);
if (permissionD.tips && !permissionState) {
explanation += `• ${permissionD.tips}\n`;
needExplain = true;
}
}
// 保存更新的权限状态
axCc.saveStorage("_androidPermissions", androidPermissions);
// 处理需要请求的权限
if (requestPermissions.length === 0) {
return back ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);
}
if (needExplain) {
return showPermissionExplanation(explanation, requestPermissions, back, proj);
}
// 直接请求权限
return requestAndroidPermissions(requestPermissions, back, proj);
}
} catch (e) {
console.error(e);
}
// #endif
return back ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);
}
// 辅助函数:显示拒绝后的提示
function showDeniedModal(back, proj) {
uni.showModal({
title: "提示",
content: "您已拒绝授权,48小时内将不再提示",
showCancel: false,
complete() {
back ? back(-2) : vueSelf.$callback("abAct.userPermissions", proj, -2);
}
});
return true;
}
// 辅助函数:显示权限解释
function showPermissionExplanation(explanation, permissions, back, proj) {
uni.showModal({
title: "权限申请",
content: "我们需要以下权限来提供完整服务:\n\n" + explanation,
success(res) {
if (res.confirm) {
requestAndroidPermissions(permissions, back, proj);
} else {
recordDeniedPermissions(permissions);
back ? back(0) : vueSelf.$callback("abAct.userPermissions", proj, 0);
}
}
});
return true;
}
// 辅助函数:记录被拒绝的权限
function recordDeniedPermissions(permissions) {
const nowTime = new Date().getTime();
const androidPermissions = SdkActs._androidPermissions || {};
permissions.forEach(p => {
androidPermissions[p] = nowTime;
});
axCc.saveStorage("_androidPermissions", androidPermissions);
SdkActs._androidPermissions = androidPermissions;
}
// 辅助函数:实际请求权限
function requestAndroidPermissions(permissions, back, proj) {
plus.android.requestPermissions(permissions, (e) => {
const androidPermissions = SdkActs._androidPermissions || {};
const nowTime = new Date().getTime();
// 处理授权结果
e.deniedAlways.concat(e.deniedPresent).forEach(p => {
androidPermissions[p] = nowTime;
});
e.granted.forEach(p => {
androidPermissions[p] = 1;
});
axCc.saveStorage("_androidPermissions", androidPermissions);
SdkActs._androidPermissions = androidPermissions;
// 回调处理
if (e.deniedAlways.length > 0) {
back ? back(-2) : vueSelf.$callback("abAct.userPermissions", proj, -2);
} else if (e.deniedPresent.length > 0 || e.granted.length === 0) {
back ? back(-1) : vueSelf.$callback("abAct.userPermissions", proj, -1);
} else {
back ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);
}
});
return true;
}
注意事项
华为应用市场特殊要求:华为应用市场特别强调在调用终端权限时应同步告知用户申请该权限的目的。建议在提示信息中明确说明权限用途。
权限分组处理:Android将危险权限分为不同的权限组,当用户授予某个组的一个权限时,该组中的其他权限也会自动获得授权。可以利用这一点优化权限申请策略。
用户体验优化:可以考虑使用更美观的自定义弹窗来替代系统默认的权限申请界面,但核心逻辑保持不变。
隐私政策合规:确保您的应用符合各大应用市场的隐私政策要求,特别是关于权限说明的部分。
测试验证:使用HBuilderX 4.01及以上版本测试时,Vue2项目需要使用自定义基座测试监听权限申请的功能,标准基座暂不支持测试。
通过以上优化,您的权限申请逻辑将更符合应用商店的审核要求,同时提供更好的用户体验。