当前位置: 首页 > news >正文

记录 App webview加载h5页面有上传图片,应用商店审核必须加授权提示问题的解决方案

场景:
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 APPsetTimeout(() => {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 = trueimageInput.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';// IEif (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 APPtry {if (axCc.info.platform == "android") {let permissionDs: any[] = JSON.parse(v);let permissionState = false;let permissionDenied = "";if (!Array.isArray(permissionDs)) {// @ts-ignoreif (Array.isArray(permissionDs.permissionList)) {// @ts-ignorepermissionState = permissionDs.state;// @ts-ignorepermissionDenied = permissionDs.denied;// @ts-ignorepermissionDs = 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.requestPermissionsplus.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);}// #endifback ? back(1) : vueSelf.$callback("abAct.userPermissions", proj, 1);},

相关文章:

记录 App webview加载h5页面有上传图片,应用商店审核必须加授权提示问题的解决方案

场景&#xff1a; 1、项目内加载了h5页面的七鱼客服&#xff0c;(相当于webview 加载help.html) 2、应用上架要求必须有授权提示弹窗 解决思路 1、客服的h5 页面在跳转时候&#xff0c;给父层webview 发消息&#xff0c;注入一段拦截代码&#xff0c;监听到有上传操作时候&…...

Stable Diffusion模型原理

1 Stable Diffusion概述 1.1 图像生成的发展 在Stable Diffusion诞生之前&#xff0c;计算机视觉和机器学习方面最重要的突破是 GAN&#xff08;Generative Adversarial Networks 生成对抗网络&#xff09;。GAN让超越训练数据已有内容成为可能&#xff0c;从而打开了一个全新…...

【Android 13】使用Android Studio调试系统应用之Settings移植(二):构建settings app项目目录

文章目录 一、篇头二、系列文章2.1 Android 13 系列文章2.2 Android 9 系列文章2.3 Android 11 系列文章三、准备工作3.1 创建目录3.2 初始化 git 仓库四、提取settings原始代码4.1 提取目标4.2 源码路径4.2.1 settings app4.2.2 SettingsLib4.3 存放位置...

w16php系列之基础数组

一、索引数组 概念 索引数组 是指键名为整数的数组。默认情况下&#xff0c;索引数组的键名是从0开始&#xff0c;并依次递增。它主要适用于利用位置&#xff08;0、1、2……&#xff09;来标识数组元素的情况。另外&#xff0c;索引数组的键名也可以自己指定 示例代码 <…...

【C语言】指针详解(四)

目录 1.assert断言 2.指针的使用和传址调用 2.1strlen的模拟使用 2.2传值调用和传址调用 1.assert断言 assert.h头文件定义了宏 assert()&#xff0c;用于在运行时确保程序符合指定条件&#xff0c;如果不符合&#xff0c;就报错终止运行。这个宏常常被称为“断言”。 例如…...

算法leetcode|94. 二叉树的中序遍历(多语言实现)

文章目录 94. 二叉树的中序遍历&#xff1a;样例 1&#xff1a;样例 2&#xff1a;样例 3&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 94. 二叉树的中序遍历&#xff1a; …...

3.[BUUCTF HCTF 2018]WarmUp1

1.看题目提示分析题目内容 盲猜一波~ &#xff1a; 是关于PHP代码审计的 2.打开链接&#xff0c;分析题目 给你提示了我们访问source.php来看一下 大boss出现&#xff0c;开始详细手撕~ 3.手撕PHP代码&#xff08;代码审计&#xff09; 本人是小白&#xff0c;所以第一步&…...

rocky linux9 安装go 即接下去

首先&#xff0c;更新系统的软件包索引以获取最新的软件包信息&#xff1a; sudo dnf update使用以下命令安装 Go 语言&#xff1a; sudo dnf install golang安装完成后&#xff0c;你可以通过以下命令验证 Go 语言是否安装成功&#xff1a; go version4、用相对路径初始化g…...

NLP中的嵌入层

在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;嵌入层&#xff08;Embedding Layer&#xff09;是一个特殊的层&#xff0c;通常用于深度学习模型的第一层&#xff0c;它的作用是将离散的文本数据&#xff08;如单词或短语&#xff09;转换为连续的向量表示。每个单…...

MongoDB文档操作

3.3 文档操作 3.1 文档介绍 文档的数据结构和 JSON 基本一样。 所有存储在集合中的数据都是 BSON 格式。 BSON 是一种类似 JSON 的二进制形式的存储格式&#xff0c;是 Binary JSON 的简称。 文档是一组键值(key-value)对(即 BSON)&#xff0c;一个简单的文档例子如下&…...

解决谷歌浏览器下CSS设置字体小于12px无效办法,关于如何在chrome里实现小于12px的文字。

关于如何在chrome里实现小于12px的文字。 当然文字缩小到12px以下本来就一定程度影响到可用性了&#xff0c;建议无视chrome的这个特性。 谷歌浏览器默认最小字体为12px&#xff0c;小于12px的字体它都以12px显示&#xff0c;有时我们需要字体小点&#xff0c;特别是在制作英文…...

springboot(ssm智慧校园之家长子系统 智慧校园系统Java系统

springboot(ssm0智慧校园之家长子系统 智慧校园系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09…...

RM3100 stm32驱动(硬件i2c)

目录 RM3100接线HAL库I2C函数HAL_I2C_Mem_ReadHAL_I2C_Mem_WriteHAL_I2C_Master_Transmit / HAL_I2C_Master_Receive例子 HSHAKE寄存器 cubemx配置RM3100寄存器驱动最终效果 RM3100接线 原理图 SA0 SA1接地&#xff0c;此时i2c设备地址为0100000&#xff0c;即0x20 如果SA0接…...

视觉学习(7) —— 接收数据和发送数据以及全局变量和浮点数

1、前提 创建一个四个字节的地址 2、发送数据 &#xff08;1&#xff09;直接发送数据 再观察地址里的值 与我们想要值不一样 输入0&#xff0c;而实际值则为 结论&#xff1a;直接输入值到地址&#xff0c;值会发生变化 &#xff08;2&#xff09;走全局变量发送数据 添加全…...

leetcode 1576. 替换所有的问号(easy)(优质解法)

链接&#xff1a;1576. 替换所有的问号 代码&#xff1a; class Solution {public String modifyString(String s) {char[] charSs.toCharArray();int lengthcharS.length;//遍历找到 &#xff1f;for(int i0;i<length;i){if(charS[i]?){//遍历 a ~ z 选择一个合适的字符来…...

Advanced IP Scanner - 网络扫描器

Advanced IP Scanner - 网络扫描器 1. Advanced IP ScannerReferences https://www.advanced-ip-scanner.com/cn/ ​ 可靠且免费的网络扫描器可以分析 LAN。该程序可扫描所有网络设备&#xff0c;使您能够访问共享文件夹和 FTP 服务器&#xff0c;(通过 RDP 和 Radmin) 远程控制…...

搜索百度百科官方创建入口,怎么创建更新公司的百度百科词条呢?

在百度搜索百度百科找到百度百科官方创建入口&#xff0c;可以上传并创建公司类的百度百科词条&#xff0c;创建词条后还可以再修改更新百科词条&#xff0c;最终完善好的百度百科词条将会在百度上获得大量曝光。那么百度百科可以怎么创建&#xff0c;下面洛希爱做百科网把十多…...

大数据与人工智能|全面数字化战略与企业数字化转型(第1节 )

要点一&#xff1a;培养跨学科思维 在分析时&#xff0c;需要采用多学科的思维方式 结果不重要&#xff0c;重要的是如何提炼现象、分析问题和得出结论的过程。 1. 介绍了锤子精神和多学科思维方式的重要性。指出了只从自身学科出发解决问题的局限性。 2. 提倡跨学科思维方式&a…...

【四】【C语言\动态规划】地下城游戏、按摩师、打家劫舍 II,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…...

【大数据存储与处理】开卷考试总复习笔记

文章目录 实验部分一、 HBase 的基本操作1. HBase Shell入门2. HBase创建数据库表3. HBase数据操作4. HBase删除数据库表5. HBase Python基本编程 before二、 HBase 过滤器操作1.创建表和插入数据2.行键过滤器3.列族与列过滤器4.值过滤器5.其他过滤器6.python hbase 过滤器编程…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...