uniapp app权限说明弹框2024.4.23更新

news2024/11/26 6:22:01
华为上架被拒绝

用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('拒绝授权');
							} else
								if (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.coloradmin.cn/o/1626003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙ArkUI实战开发-如何通过上下滑动实现亮度和音量调节

场景说明 在音视频应用中通常可以通过上下滑动来调节屏幕亮度和音量大小&#xff0c;本例即为大家介绍如何实现上述UI效果。 说明&#xff1a; 由于当前亮度和音量调节功能仅对系统应用开发&#xff0c;所以本例仅讲解UI效果的实现。 效果呈现 本例效果如下&#xff1a; 当在…

【Redis 开发】一人一单,超卖问题(悲观锁,乐观锁,分布式锁)

锁 悲观锁乐观锁第一种&#xff1a;版本号法第二种&#xff1a;CAS法实现乐观锁 悲观锁与乐观锁的比较 一人一单分布式锁Redis实现分布式锁 悲观锁 认为线程问题一定会发生&#xff0c;因此在操作数据库之前先获取锁&#xff0c;确保线程串行执行&#xff0c;例如Synchronized…

17 JavaScript 学习:正则表达式

JavaScript 正则表达式 JavaScript中正则表达式是一种强大的工具&#xff0c;用于在字符串中进行模式匹配和搜索。下面是一些JavaScript中使用正则表达式的基本知识&#xff1a; 创建正则表达式&#xff1a;可以使用字面量形式或者RegExp构造函数来创建正则表达式。 字面量形式…

【快速上手ESP32(基于ESP-IDFVSCode)】11-MQTT

MQTT MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;是一种基于发布/订阅模式的轻量级通讯协议&#xff0c;构建于TCP/IP协议之上。它最初由IBM在1999年发布&#xff0c;主要用于在硬件性能受限和网络状况不佳的情况下&…

M-LAG的基本概念

如图所示&#xff0c;用户侧设备Switch&#xff08;可以是交换机或主机&#xff09;通过M-LAG机制与另外两台设备&#xff08;SwitchA和SwitchB&#xff09;进行跨设备链路聚合&#xff0c;共同组成一个双活系统。这样可以实现SwitchA和SwitchB共同进行流量转发的功能&#xff…

泰迪智能科技助力中山三院放射科搭建生成式大模型应用

泰迪智能科技作为一家专业从事物联网、大数据及人工智能技术研发、咨询与培训的高科技企业&#xff0c;具有强大的技术研发实力和应用经验。中山大学附属第三医院放射科是集医疗、教学、科研工作于一体的广东省临床重点专科&#xff0c;具有深厚的医疗资源和科研基础。两者合作…

安卓和ios设置自己的短链

ios 的info.plist文件 设置 CFBundleURLSchemes 其中konnect 就是设置app的短链名称 <array><dict><key>CFBundleTypeRole</key><string>Editor</string><key>CFBundleURLName</key><string>org.konnect.app</str…

4.keepalive 与 Idle 监测

为什么需要 keepalive ? 假设你开了一个饭店,别人电话来订餐,电话通了后,订餐的说了一堆订餐要求,说着说 着,对方就不讲话了(可能忘记挂机/出去办事/线路故障等)。 这个时候你会一直握着电话等么? 不会 如果不会,那你一般怎么去做?会确认一句“你还在么?”,如果对…

常见的掼蛋误区

1、过于依赖大牌 很多新手玩家会觉得手中的大牌是必胜的保证&#xff0c;然而这种想法都是片面的。在掼蛋游戏中&#xff0c;一个合理的牌型组合往往比单一的大牌更有胜算。因此玩家要综合考虑的是手中的牌型和牌面大小。 2、盲目跟风 不少玩家在掼蛋中喜欢跟着对手的出牌思路走…

当NebulaGraph遇上智能体:图数据库智能助手

在数字化转型的浪潮中&#xff0c;图数据库技术凭借其出色的数据关联性能和灵活的查询功能&#xff0c;逐渐成为企业重要的技术选项。我们的团队之前曾经在两个项目中进行了图数据库的重构&#xff1a;一次是从OrientDB迁移到NebulaGraph&#xff0c;另一次是将ES系统迁移到Neb…

边写论文边发疯,多大仇啊?导师批注学生论文:建议把致谢部分烧掉

盼望着&#xff0c;盼望着&#xff0c;夏天来了&#xff0c;毕业的脚步近了。 于是乎&#xff0c;莘莘学子又开始幻想自己被导师带飞一路畅通顺利毕业了。 而且&#xff0c;如果可行的话&#xff0c;大家还希望能够这样&#xff1a; 然而&#xff0c;我阴暗的心中不由得泛起一…

只需几步,即可享有笔记小程序

本示例是一个简单的外卖查看店铺点菜的外卖微信小程序&#xff0c;小程序后端服务使用了MemFire Cloud&#xff0c;其中使用到的MemFire Cloud功能包括&#xff1a; 其中使用到的MemFire Cloud功能包括&#xff1a; 云数据库&#xff1a;存储外卖微信小程序所有数据表的信息。…

[Diffusion Model 笔记]DDIM 笔记 数学推导 Denoising Diffusion Implicit Models

目录 核心总结符号定义第一套&#xff0c;快速简单讲清采样方法继续分析&#xff0c;待定系数法求解图示理解关于参数sigma 本文是观看以下视频的笔记&#xff0c;强烈推荐观看最后的图示理解&#xff1a; https://www.bilibili.com/video/BV13P411J7dm/?spm_id_from333.788 论…

http基础了解

超文本传输协议&#xff08;HTTP&#xff09;是一个用于传输超媒体文档&#xff08;例如 HTML&#xff09;的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的&#xff0c;但也可以用于其他目的。HTTP 遵循经典的客户端—服务端模型&#xff0c;客户端打开一个连…

01、创建型-单例模式--只有一个实例

文章目录 前言一、基本介绍1.1 什么是单例模式1.2 为什么要用单例模式1.3 应用场景1.4 单例优缺点 二、单例模式的实现方式2.1 饿汉式单例2.1.1 静态变量方式2.1.2 静态代码块 2.2 懒汉式单例2.2.1 懒汉式单例2.2.2 懒汉式优化①-线程安全2.2.2 懒汉式优化②-双重检查锁2.2.3 懒…

力扣-1832.判断句子是否全为字母句

思路: 首先&#xff0c;我们初始化了一个长度为 26 的布尔值列表 exist&#xff0c;所有值都为 False&#xff0c;表示所有字母初始都未出现过。然后&#xff0c;我们遍历输入的字符串 sentence 中的每个字符。对于每个字符&#xff0c;我们通过计算其 ASCII 码值减去字母 a 的…

ArcGIS Pro专题地图系列教程

专题地图系列是ArcGIS Pro3.2的新功能。之前&#xff0c;如果要做8张相同区域的专题图&#xff0c;可能需要新建8个布局&#xff0c;分别进行排版&#xff0c;再导出。现在&#xff0c;一幅地图&#xff0c;一个布局&#xff0c;就可以完成这个流程。 原理是&#xff0c;根据单…

ROS python实现乌龟跟随

产生两只乌龟&#xff0c;中间的乌龟(A) 和 左下乌龟(B), B 会自动运行至A的位置&#xff0c;并且键盘控制时&#xff0c;只是控制 A 的运动&#xff0c;但是 B 可以跟随 A 运行 乌龟跟随实现的核心&#xff0c;是乌龟A和B都要发布相对世界坐标系的坐标信息&#xff0c;然后&am…

用例整体执行及pytest.ini文件

在我们写代码的过程中&#xff0c;一般都是右键或者命令行去执行一个用例 但是当我们写完后&#xff0c;需要整体执行一遍。那应该怎么搞呢&#xff1f; 我们可以在根目录下新建一个main.py或者run.py之类的文件&#xff0c;文件内容如下&#xff1a; if __name__ "__ma…

报错:图片验证码接口对接vue+springboot(下一个笔记会记录整个验证码的代码)

问题&#xff1a;空指针异常ai: 根据错误堆栈信息中提供的方法调用位置&#xff0c;看起来空指针异常是在 AuthCodeServiceImpl 类的 authUserCoded 方法的第 41 行发生的。 为了解决这个问题&#xff0c;你可以检查 AuthCodeServiceImpl 类中 authUserCoded 方法的第 41 行&am…