场景:
1、项目内加载了h5页面的七鱼客服,(相当于webview 加载help.html)
2、应用上架要求必须有授权提示弹窗
解决思路
1、客服的h5 页面在跳转时候,给父层webview 发消息,注入一段拦截代码,监听到有上传操作时候,调用原生的授权提示,下次点击时候就可以根据返回的授权信息判断是否要执行input file 的click事件 。
注:项目用uniapp 写的,自己写了一套webview 和 h5 通信的逻辑,文中$abAct(‘getImagePermission’, ‘’, function(err,succ) {}) ; p o s t M e s s a g e ( " k e f u I n j e c t " ) ; 都是通信交互方法,其中 postMessage("kefuInject");都是通信交互方法,其中 postMessage("kefuInject");都是通信交互方法,其中abAc是有回调的。可以自行处理这块逻辑
客服的html
help.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<style>
#YSF-BTN-HOLDER {
display: none;
}
</style>
<body>
</body>
<script src="这里是引入我通信的js代码"></script>
<script type="text/javascript">
let kefuCode = query("kefuCode");
let url = "";
let plt = '"https://qiyukf.com/script/';
if (location.href.startsWith("https")) {
url = "https://qiyukf.com/script/";
} else {
url = "http://qiyukf.com/script/";
}
if (!kefuCode || kefuCode == 0) {
url = url + "七鱼客服的key" + ".js";
} else {
url = url + kefuCode + ".js";
}
url = url + "?subdomain=1";
console.log("加载客服js", url);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
var flage = false;
script.onload = function () {
// 加载完成后的操作
initKefu();
};
document.body.appendChild(script);
window.onload = function () {
initKefu();
};
function initKefu() {
if (flage) {
return;
}
flage = true;
ysf.on({
onload: function () {
var data = [];
try {
data = query("data")
? JSON.parse(decodeURIComponent(query("data")))
: [];
if (data.length > 1 && data[1].url) {
ysf("product", {
show: 1, // 1为打开, 其他参数为隐藏(包括非零元素)
title: data[1].title,
desc: data[1].desc,
picture: data[1].picture,
note: data[1].note,
url: data[1].url,
});
data.splice(1, 1);
}
} catch (e) {
console.error(e);
}
var uid = query("uid") ? query("uid") : GetRandomNum(10000, 999999);
console.log("uiduiduiduid", uid);
var cfg = {
uid: uid,
name: query("name"),
mobile: query("mobile"),
data: JSON.stringify(data),
success: function () {
// 成功回调
console.log(ysf.url());
let ysfurl = ysf.url();
if (data[0].templateId) {
ysfurl = ysf.url() + "&templateId=" + data[0].templateId;
}
console.log(uniReady);
try {
if (ab_.uniApp && query("newHelp")) {
uniReady(() => {
//这里是调用获取授权的方法,是自己封装的 webview 和 h5 的通信方式,可自行处理
$postMessage("kefuInject");
location.href = ysfurl;
});
return;
}
} catch (e) {
console.log(e);
}
location.href = ysfurl;
},
error: function () {
// 错误回调
location.href = ysf.url();
},
};
// console.log(cfg)
ysf.config(cfg);
},
});
}
function GetRandomNum(Min, Max) {
var Range = Max - Min;
var Rand = Math.random();
return Min + Math.round(Rand * Range);
}
function query(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return decodeURIComponent(r[2]);
}
return null;
}
</script>
</html>
注入js的代码
sdk.ts
kefuInject(v: string, tag?: any, source?: any, proj?: any) {
proj = proj || vueSelf.$proj(tag, source)
// #ifdef APP
setTimeout(() => {
console.log('kefuInject', proj)
// if(false) {
// return
// }
proj.evalJs(`
window.permissionApply = false
// window.οnlοad=function(){
// alert('0 οnlοad')
loadJS( 'https://p2.dev.yiyiny.com/plt-demo/static/open.plt.0.1.js?v=2',function(){
// ab_.vconsoled = true
//加载,并执行回调函数
injectKefuPermissions()
// alert('2injectKefuPermissions' )
});
// }
function injectKefuPermissions() {
var videoInput = document.querySelector('input[accept="video/*"]')
var imageInput = document.querySelector('input[accept="image/*"]')
if (!imageInput) {
setTimeout(injectKefuPermissions, 500)
}else{
var imageInputClick = function(e) {
saveImagePermissionApply(imageInput,e);
}
var videoInputClick = function(e) {
saveImagePermissionApply(videoInput,e);
}
imageInput.addEventListener('click', imageInputClick);
videoInput.addEventListener('click', videoInputClick);
}
}
function saveImagePermissionApply(el,e){
// alert('0' + window.permissionApply)
if(!window.permissionApply){
// alert('1' +window. permissionApply)
e.preventDefault();
uniReady(function() {
$abAct('getImagePermission', '', function(err,succ) {
// alert('2' + succ)
if(succ){
window.permissionApply = true
imageInput.removeEventListener('click', imageInputClick)
videoInput.removeEventListener('click', videoInputClick)
el.click()
}
})
})
}else{
// window.permissionApply = false
}
}
function loadJS(url, callback) {
var script = document.createElement('script'), fn = callback || function() {
};
script.type = 'text/javascript';
// IE
if (script.readyState) {
script.onreadystatechange = function() {
if (script.readyState == 'loaded'
|| script.readyState == 'complete') {
script.onreadystatechange = null;
fn();
}
};
} else {
// 其他浏览器
script.onload = function() {
fn();
};
}
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
`)
}, 3000);
// #endif
},
};
获取权限代码
SdkActs.ts
getImagePermission(v?: string, tag?: any, source?: any, proj?: any) {
// proj = proj || vueSelf.$proj(tag, source);
let data = {
state: false,//是否原生授权
denied: true,//是否提示
permissionList: [
{
permissionName: "相机",
tips: "允许应用打开摄像头",
androidPermission: "android.permission.CAMERA",
},
{
permissionName: "相册",
tips: "允许应用读取存储卡上的照片、媒体内容和文件",
androidPermission: "android.permission.READ_EXTERNAL_STORAGE",
},
],
};
SdkActs.userPermissions(
JSON.stringify(data), null, null, null,
function (res) {
console.log("getImagePermission res", res);
// console.log("getImagePermission back", back);
// back(res === 1 ? true : false)
vueSelf.$callback('abAct.getImagePermission', null, res == 1 ? true : false);
}
);
return true
},
_androidPermissions: <any>undefined,
//此为48小时授权和提示的代码
userPermissions(v?: string, tag?: any, source?: any, proj?: any, 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)) {
// @ts-ignore
if (Array.isArray(permissionDs.permissionList)) {
// @ts-ignore
permissionState = permissionDs.state;
// @ts-ignore
permissionDenied = permissionDs.denied;
// @ts-ignore
permissionDs = permissionDs.permissionList;
} else {
permissionDs = [permissionDs];
}
}
let androidPermissionsDirty = false;
let androidPermissions = SdkActs._androidPermissions;
if (!androidPermissions) {
androidPermissions = axCc.getStorage("_androidPermissions");
if (typeof androidPermissions !== "object") {
androidPermissions = {};
}
SdkActs._androidPermissions = androidPermissions;
}
let mainActivity: any;
let nowTime: any;
let deniedTime: any;
let deniedPermissions;
let requestPermissions;
let nonePermissions = false;
let tips = "";
for (let i = permissionDs.length - 1; i >= 0; i--) {
let permissionD = permissionDs[i];
let permission = permissionD.androidPermission;
let permissionV = androidPermissions[permission];
if (permissionV === 1) {
permissionDs.splice(i, 1);
} else {
mainActivity || (mainActivity = plus.android.runtimeMainActivity());
if (mainActivity.checkSelfPermission(permission) === 0) {
permissionDs.splice(i, 1);
androidPermissionsDirty = true;
androidPermissions[permission] = 1;
} else {
// 暂停二次授权间隔48小时
if (!deniedTime) {
nowTime = new Date().getTime();
deniedTime = nowTime - 48 * 24 * 3600;
}
if (permissionV > deniedTime) {
// 暂停二次授权
(deniedPermissions || (deniedPermissions = [])).push(
permissionD
);
} else {
if (permissionD.tips && !permissionState) {
// 可授权提示
tips = permissionD.tips + tips;
(requestPermissions || (requestPermissions = [])).push(
permission
);
} else {
nonePermissions = true;
}
}
}
}
}
if (androidPermissionsDirty) {
// 权限记录
androidPermissionsDirty = false;
axCc.saveStorage("_androidPermissions", androidPermissions);
}
if (nonePermissions) {
// 没有授权
back
? back(-1)
: vueSelf.$callback("abAct.userPermissions", proj, -1);
return;
} else if (deniedPermissions) {
// 暂停二次授权
if (permissionDenied) {
uni.showModal({
title: "提示",
content: "没有权限",
showCancel: false,
complete(result) {
back
? back(-2)
: vueSelf.$callback("abAct.userPermissions", proj, -2);
},
});
return true;
}
back
? back(-2)
: vueSelf.$callback("abAct.userPermissions", proj, -2);
return;
} else if (tips) {
uni.showModal({
title: "权限申请",
content: tips,
success(res) {
if (res.confirm) {
// https://www.html5plus.org/doc/zh_cn/android.html#plus.android.requestPermissions
plus.android.requestPermissions(requestPermissions, (e) => {
for (let i = e.deniedAlways.length - 1; i >= 0; i--) {
androidPermissions[e.deniedAlways[i]] = nowTime;
}
for (let i = e.deniedPresent.length - 1; i >= 0; i--) {
androidPermissions[e.deniedPresent[i]] = nowTime;
}
for (let i = e.granted.length - 1; i >= 0; i--) {
androidPermissions[e.granted[i]] = 1;
}
axCc.saveStorage("_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
) {
//权限被临时拒绝
// 弹出提示框解释为何需要定位权限,可再次调用plus.android.requestPermissions申请权限
back
? back(-1)
: vueSelf.$callback("abAct.userPermissions", proj, -1);
} else {
//权限被允许
//调用依赖获取定位权限的代码
back
? back(1)
: vueSelf.$callback("abAct.userPermissions", proj, 1);
}
});
} else if (res.cancel) {
// 拒接授权
back
? back(0)
: vueSelf.$callback("abAct.userPermissions", proj, 0);
}
},
});
return true;
}
back ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);
return;
}
} catch (e) {
console.error(e);
}
// #endif
back ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);
},