uniapp app权限说明弹框2024.4.23更新

华为上架被拒绝

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

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

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

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

20214.4.23 uniapp权限弹框视频

javascript 复制代码
<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权限管理仓库

javascript 复制代码
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 插件市场

相关推荐
咸虾米_3 天前
咸虾米壁纸微信小程序下载图片到相册saveImageToPhotosAlbum功能修改
微信小程序·小程序·uniapp·notepad++
~牧马~3 天前
【记录50】uniapp安装uview插件,样式引入失败分析及解决
uniapp·uview插件
流氓也是种气质 _Cookie4 天前
uniapp 将base64字符串保存为图片、Word、Excel、音频、视频等文件
uniapp·base64tofile
!win !8 天前
WebP图片使用踩坑
小程序·uniapp·webp
顽疲8 天前
从零用java实现 小红书 springboot vue uniapp (3)详情页优化
java·vue.js·spring boot·uniapp
程序猿看视界9 天前
uniapp小程序的锚点定位(将页面滚动到目标位置)
uniapp·锚点定位
oil欧哟13 天前
给我的小程序加了个丝滑的搜索功能,踩坑表情包长度问题
前端·vue.js·微信小程序·uniapp
一殊酒23 天前
【前端开发】小程序无感登录验证
前端·小程序·uniapp
竣子好逑1 个月前
uniapp 自定义popup 弹窗 简单封装(微信小程序)
前端·微信小程序·小程序·uni-app·uniapp
h185385922441 个月前
志愿者小程序源码社区网格志愿者服务小程序php
微信小程序·小程序·php·uniapp·源码软件