uniapp app权限说明弹框2024.4.23更新

news/2024/5/17 2:24:12
华为上架被拒绝

用uni-app开发的app,上架华为被拒,问题如下:

您的应用在运行时,未见向用户告知权限申请的目的,向用户索取(电话、相机、存储)等权限,不符合华为应用市场审核标准。

测试步骤:任意招聘信息详情页-电话联系,申请电话权限;点击置顶推广-保存二维码到相册,申请存储权限;点击发布-任意服务-上传图片-拍摄/从相册选择,申请相机、存储权限;修改建议:APP在调用终端权限时,应同步告知用户申请该权限的目的。请排查应用内所有权限申请行为,确保均符合要求。

本文是使用pinia集中管理的!!如果想使用vuex,照着改,大同小异

20214.4.23 uniapp权限弹框视频

<template><view><button @tap="applyCameraPermission('CAMERA')">申请相机权限</button><button @tap="applyPhonePermission('SET_CALL_PHONE')">申请电话权限</button><button @tap="applyReadexternal('READ_EXTERNAL_STORAGE')">读取照片</button><button @click="nextpage">跳转</button></view>
</template><script setup>
import { usePermission } from "/store/permission.js"
const permissionStore = usePermission()const applyCameraPermission = async (permission) => {/* #ifdef APP */if (!await permissionStore.requstPermission(permission)) return/* #endif */uni.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['camera'],success: (res) => {console.log(res)}});
}
const applyPhonePermission = async (permission) => {/* #ifdef APP */if (!await permissionStore.requstPermission(permission)) return/* #endif */uni.makePhoneCall({phoneNumber: '10086'});
}
const applyReadexternal = async (permission) => {/* #ifdef APP */if (!await permissionStore.requstPermission(permission)) return/* #endif */uni.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['album'],success: (res) => {console.log(res)}});
}const nextpage = () => {uni.navigateTo({url: '/pages/index/index'});
}
</script><style></style>

pinia权限管理仓库

import {defineStore
} from 'pinia'export const usePermission = defineStore('permission', {state: () => ({dialogView: null,permissionListener: null,list: [{name: "READ_CALENDAR",title: "手机状态权限申请说明:",content: "uni-app正在申请手机日历日历状态权限,允许或拒绝均不会获取任何隐私信息。",}, {name: "CALL_PHONE",title: "拨打电话权限申请说明:",content: "uni-app正在申请拨打电话权限,允许或拒绝均不会获取任何隐私信息。",}, {name: "CAMERA",title: "读取存储权限申请说明:",content: "uni-app正在申请摄像头权限,允许或拒绝均不会获取任何隐私信息。",}, {name: "READ_EXTERNAL_STORAGE",title: "读取存储权限申请说明:",content: "uni-app正在申请读取存储权限,允许或拒绝均不会获取任何隐私信息。",}]}),getters: {},actions: {//监听权限申请async requstPermission(permissionID) {return new Promise((resolve, reject) => {try {// if (!uni.getSystemInfoSync().platform == 'android') return resolve(true) /*** @description plus.navigator.checkPermission 检查应用是否获取指定权限 * 有些权限检测不到 就继续下面的代码,比如相册权限就可以直接检测,就很方便,授权情况下不需要再走下面代码了* checkPermission 返回参数* @params undetermined 未确定* @params authorized 授权*/let checkPermission = plus.navigator.checkPermission('android.permission.' + permissionID)if (checkPermission == 'authorized') return resolve(true)//判断是否自己在list里面配置了这个权限let index = this.list.findIndex(item => item.name == permissionID)if (index == -1) throw new Error('这个权限没有配置')//唤起原生权限说明弹框this.requstPermissionDialog(index)//授权检测回调plus.android.requestPermissions(['android.permission.' + permissionID  //单个权限// 'android.permission.CAMERA', 'android.permission.READ_EXTERNAL_STORAGE'  //多个权限],(resultObj) => {console.log(resultObj, 'resultObj');// 权限申请结果/*** @description resultObj.deniedAlways 永久拒绝授权* 多个权限返回结果可能是{"granted":["android.permission.CAMERA"],"deniedPresent":[],"deniedAlways":["android.permission.READ_EXTERNAL_STORAGE"]}* 这个情况就是我同时授权相册和相机,但是只允许了相机,没有授权相册* 这个时候 可以通过deniedAlways 查看哪个权限被永久拒绝了,然后自行在设置弹框内容* 所以可以自己判断细分一下,我下面的代码是先判断了是否有永久拒绝的权限,然后直接弹框提示用户去设置*/if (resultObj.deniedAlways && resultObj.deniedAlways.length > 0) {uni.showModal({title: '提示',content: '操作权限已被拒绝,请手动前往设置',confirmText: "立即设置",success: (res) => {if (res.confirm) {this.gotoAppPermissionSetting()} else {resolve(false)}}})console.log('永久拒绝授权');} else if (resultObj.deniedPresent && resultObj.deniedPresent.length > 0) {resolve(false)console.log('拒绝授权');} elseif (resultObj.granted && resultObj.granted.length > 0) {resolve(true)console.log('授权成功');}},(error) => {reject(false)console.log('申请权限错误:',error);});} catch (err) {reject(false)console.log(err);}})},//监听弹框requstPermissionDialog(index) {try {if (!this.permissionListener) this.permissionListener = uni.createRequestPermissionListener()const dialogData = this.list[index]this.permissionListener.onConfirm((res) => {this.dialogStyle(dialogData, true)})this.permissionListener.onComplete(async (res) => {this.dialogStyle({}, false)})} catch (err) {console.log('监听弹框错误', err);}},//弹框样式dialogStyle({ title = '', content = '' }, status) {try {if (!status) return this.dialogView.close()const systemInfo = uni.getSystemInfoSync();const statusBarHeight = systemInfo.statusBarHeight;const navigationBarHeight = systemInfo.platform === 'android' ? 48 :44;const totalHeight = statusBarHeight + navigationBarHeight;this.dialogView = new plus.nativeObj.View('per-modal', {top: '0px',left: '0px',width: '100%',backgroundColor: '#444',//opacity: .5;})this.dialogView.drawRect({color: '#fff',radius: '5px'}, {top: totalHeight + 'px',left: '5%',width: '90%',height: "100px",})this.dialogView.drawText(title, {top: totalHeight + 5 + 'px',left: "8%",height: "30px"}, {align: "left",color: "#000",})this.dialogView.drawText(content, {top: totalHeight + 35 + 'px',height: "60px",left: "8%",width: "84%"}, {whiteSpace: 'normal',size: "14px",align: "left",color: "#656563"})this.dialogView.show()} catch (e) {console.log(e, '权限说明弹框样式错误');}},//跳转到app权限设置页面gotoAppPermissionSetting() {if (!uni.getSystemInfoSync().platform == 'android') {var UIApplication = plus.ios.import("UIApplication");var application2 = UIApplication.sharedApplication();var NSURL2 = plus.ios.import("NSURL");// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");		var setting2 = NSURL2.URLWithString("app-settings:");application2.openURL(setting2);plus.ios.deleteObject(setting2);plus.ios.deleteObject(NSURL2);plus.ios.deleteObject(application2);} else {// console.log(plus.device.vendor);var Intent = plus.android.importClass("android.content.Intent");var Settings = plus.android.importClass("android.provider.Settings");var Uri = plus.android.importClass("android.net.Uri");var mainActivity = plus.android.runtimeMainActivity();var intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);intent.setData(uri);mainActivity.startActivity(intent);}}}
})

更多permissionID 值域清单权限  App权限判断和提示 - DCloud 插件市场


http://www.mrgr.cn/p/20845357

相关文章

iOS - 多线程-atomic

文章目录 iOS - 多线程-atomic1. 源码分析1.1 get方法1.2 set方法 2. 一般不使用atomic的原因 iOS - 多线程-atomic atomic用于保证属性setter、getter的原子性操作&#xff0c;相当于在getter和setter内部加了线程同步的锁可以参考源码objc4的objc-accessors.mm它并不能保证使…

数据结构单链表”质检员“*2

1.随机链表的逻辑结构复制 原题链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode-cn.com/problems/copy-list-with…

智慧旅游引领旅游行业创新发展:借助智能科技的力量,推动旅游服务的个性化、精准化,提升游客的满意度和忠诚度

随着信息技术的迅猛发展和广泛应用&#xff0c;智慧旅游已成为旅游行业创新发展的重要引擎。智慧旅游借助智能科技的力量&#xff0c;推动旅游服务的个性化、精准化&#xff0c;不仅提升了游客的满意度和忠诚度&#xff0c;也为旅游行业的可持续发展注入了新的活力。本文将从智…

《Vid2Seq》论文笔记

原文链接 [2302.14115] Vid2Seq: Large-Scale Pretraining of a Visual Language Model for Dense Video Captioning (arxiv.org) 原文笔记 What&#xff1a; 《Vid2Seq: Large-Scale Pretraining of a Visual Language Model for Dense Video Captioning》 作者提出一种多…

《软件设计师教程:数据库系统基础知识大总结》

​ 个人主页&#xff1a;李仙桎 &#x1f525; 个人专栏: 《软件设计师》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ​ ⛺️前言&#xff1a;各位铁汁们好啊&#xff01;&#xff01;&#xff01;今天继续正式学习中级软件设计师考试相关的内容&#xff0c;后续不断更新…

Ansible 自动化运维

一、介绍 1、定义&#xff1a; ansible是自动化运维工具&#xff0c;基于Python开发&#xff0c;具有批量系统配置、批量程序部署、批量运行命令等功能。 ansible是基于 paramiko&#xff08;框架&#xff09; 开发的&#xff0c;并且基于模块化工作&#xff0c;本身没有批量…

node.js egg.js

Egg 是 Node.js 社区广泛使用的框架&#xff0c;简洁且扩展性强&#xff0c;按照固定约定进行开发&#xff0c;低协作成本。 在Egg.js框架中&#xff0c;ctx 是一个非常核心且常用的对象&#xff0c;全称为 Context&#xff0c;它代表了当前 HTTP 请求的上下文。ctx 对象封装了…

java中serverlet的体系结构

GenericServlet继承三个接口,HttpServerlet继承GenericServlet

React-editor-js not showing up in a function component

React-editor-js not showing up in a function component react-editor-js 在react 函数组件中显示不出来 真的&#xff0c;我马上就想放弃它了。但是看它周下载量还挺多&#xff0c;我不信别人没遇到过。于是我继续在网络上挖呀挖。只是我一开始的方向错了。我一直以为我的写…

Profinet转Modbus网关接称重设备与1200PLC通讯

Profinet转Modbus网关(XD-MDPN100)是一种能够实现Modbus协议和Profinet协议之间转换的设备。Profinet转Modbus网关可提供单个或多个RS485接口,使用Profinet转Modbus网关将称重设备与西门子1200 PLC进行通讯,可以避免繁琐的编程和配置过程,节省了工程师的时间和精力。其次,…

自动驾驶横向控制算法

本文内容来源是B站——忠厚老实的老王&#xff0c;侵删。 三个坐标系和一些有关的物理量 使用 frenet坐标系可以实现将车辆纵向控制和横向控制解耦&#xff0c;将其分开控制。使用右手系来进行学习。 一些有关物理量的基本概念&#xff1a; 运动学方程 建立微分方程 主要是弄…

给Qt搭建一个简单的Json服务器用于软件调试

一. vscode+nodejs+npm安装 二. nodejs服务器开启打开vscode - 终端 - 新建终端进入json_server目录 cd D:\json_server运行启动命令, 启动json-server服务器 npm run json:server效果如下: PS D:\json_server> npm run json:server> jsonserver@1.0.0 json:server > …

酒店订单管理系统搭建教程

1、演示环境配置 centos7.9、mysql5.7、php7.2 2、宝塔创建站点记录创建站点时候创建的数据库信息3、上传fastadmin压缩包点击开始上传 4、解压上传的fastadmin5、配置网站目录和运行目录运行目录选择public点击保存即可 6、配置伪静态选择thinkphp 7、直接访问域名根据自己的实…

加速软件定义汽车进程:安波福推出全栈式软硬件平台

随着智能汽车行业的飞速发展&#xff0c;“软件定义汽车”也得到了越来越多行业人士的认可&#xff0c;成为了汽车行业的大势所趋。为了推动和加速软件定义汽车的进程&#xff0c;也有越来越多的科技企业在为其不断添砖加瓦。 2024北京国际车展期间&#xff0c;安波福正式对外展…

14、pWnOS_v2.0(VulnHub)

pWnOS_v2.0 一、nmap 靶机ip找不见的自行上网查找解决办法。二、web渗透 目录爆破/blog/whatweb/search.php/register.php qwe 123qwe点击给定的链接兔子洞,无法登入?一直卡在这个界面wfuzz貌似没什么用nmap -> 目录Simple PHP Blog 0.4.0perl 1191.pl如果出现运行报错Can…

SQL Server实战三:数据库表完整性约束及索引、视图的创建、编辑与删除

本文介绍基于Microsoft SQL Server软件,实现数据库表完整性约束、索引与视图的创建、编辑与删除等操作的方法~本文介绍基于Microsoft SQL Server软件,实现数据库表完整性约束、索引与视图的创建、编辑与删除等操作的方法。 目录1 交互式为数据库表S创建PRIMARY KEY约束2 交互…

上位机开发-PyQt5

PyQt是一套Python的GUI开发框架&#xff0c;即图形用户界面开发框架 其中PyQt是Qt(C语言实现的)为Python专门提供的扩展 PySide官网&#xff1a;Qt for Python 插件安装 pip install 插件名字 # 安装 pip uninstall 插件名字 # 卸载 pip install 插件名字 -i 指定下载的镜…

vue.js 3 初学经验:开发环境搭建,Windows,nginx

Windows 11 nginx-1.20.0 "vue": "^3.4.21" ---序章 vue3 开发,不需要后端服务业是可以的。 在需要后端服务时,使用 nginx 来转发请求是很好的(个人开发者)。注,还有什么其它方式吗? 注,本文的后端服务 是使用 Java 开发的 HTTP 接口。 注,参考资料…

怎么给字符串字段加索引?

怎么给字符串字段加索引&#xff1f; 现在&#xff0c;几乎所有的系统都支持邮箱登录&#xff0c;如何在邮箱这样的字段上建立合理的索引&#xff0c;是我们今天要讨论的问题。 假设&#xff0c;你现在维护一个支持邮箱登录的系统&#xff0c;用户表是这么定义的&#xff1a; …

使用图集Atlas创建Fnt文件的工具

fnt文件生成unity字体的原理其实就是渲染图集Atlas上的Sprite,这边直接利用Unity自带的图集工具生成fnt文件 注意:这里生成的fnt文件还没发直接用,因为没有关联字符,这个工具只是第1步,要配合Fnt编辑工具一起使用 public class SpriteToFntTool : EditorWindow {[MenuItem…