uniapp打包app关于获取本机相机、相册、麦克风等权限问题(ios第一次安装权限列表里没有对应权限问题)

1.因为用户在app中如果拒绝了相机相册等的权限,将不会再弹出系统对应获取权限的弹框,所以为了引导用户在没有对应权限时,去权限设置页面开启对应权限,所以有了下面的判断

javascript 复制代码
//permission.js
/**
 * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
 */

var isIos;
var unPermission = [] //当前未获取到的权限
// #ifdef APP-PLUS
isIos = plus.os.name == 'iOS';
// #endif
var viewShow = true;
// 判断推送权限是否开启
function judgeIosPermissionPush() {
	var result = false;
	var UIApplication = plus.ios.import('UIApplication');
	var app = UIApplication.sharedApplication();
	var enabledTypes = 0;
	if (app.currentUserNotificationSettings) {
		var settings = app.currentUserNotificationSettings();
		enabledTypes = settings.plusGetAttribute('types');
		console.log('enabledTypes1:' + enabledTypes);
		if (enabledTypes == 0) {
				console.log('推送权限没有开启');
				unPermission.push('推送权限')
		} else {
			result = true;
			console.log('已经开启推送功能!');
		}
		plus.ios.deleteObject(settings);
	} else {
		enabledTypes = app.enabledRemoteNotificationTypes();
		if (enabledTypes == 0) {
			console.log('推送权限没有开启!');
		} else {
			result = true;
			console.log('已经开启推送功能!');
		}
		console.log('enabledTypes2:' + enabledTypes);
	}
	plus.ios.deleteObject(app);
	plus.ios.deleteObject(UIApplication);
	return result;
}

// 判断定位权限是否开启
function judgeIosPermissionLocation() {
	var result = false;
	var cllocationManger = plus.ios.import('CLLocationManager');
	var status = cllocationManger.authorizationStatus();
	result = status != 2;
	console.log('定位权限开启:' + result);
	// 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
	/* var enable = cllocationManger.locationServicesEnabled();
	var status = cllocationManger.authorizationStatus();
	console.log("enable:" + enable);
	console.log("status:" + status);
	if (enable && status != 2) {
	    result = true;
	    console.log("手机定位服务已开启且已授予定位权限");
	} else {
	    console.log("手机系统的定位没有打开或未给予定位权限");
	} */
	plus.ios.deleteObject(cllocationManger);
	return result;
}

// 判断麦克风权限是否开启
function judgeIosPermissionRecord() {
	var result = false;
	var avaudiosession = plus.ios.import('AVAudioSession');
	var avaudio = avaudiosession.sharedInstance();
	var permissionStatus = avaudio.recordPermission();
	console.log('permissionStatus:' + permissionStatus);
	if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
			console.log('麦克风权限没有开启');
			unPermission.push('麦克风权限')
	} else {
		result = true;
		console.log('麦克风权限已经开启');

	}
	plus.ios.deleteObject(avaudiosession);
	return result;
}

// 判断相机权限是否开启
function judgeIosPermissionCamera() {
	var result = false;
	var AVCaptureDevice = plus.ios.import('AVCaptureDevice');
	var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
	console.log('authStatus:' + authStatus);
	if (authStatus == 3) {
		result = true;
		console.log('相机权限已经开启');
	} else {
			console.log('相机权限没有开启');
			unPermission.push('相机权限')
	}
	plus.ios.deleteObject(AVCaptureDevice);
	return result;
}

// 判断相册权限是否开启
function judgeIosPermissionPhotoLibrary() {
	var result = false;
	var PHPhotoLibrary = plus.ios.import('PHPhotoLibrary');
	var authStatus = PHPhotoLibrary.authorizationStatus();
	console.log('authStatus:' + authStatus);
	if (authStatus == 3) {
		result = true;
		console.log('相册权限已经开启');
	} else {
			console.log('相册权限没有开启');
			unPermission.push('相册权限')
	}
	plus.ios.deleteObject(PHPhotoLibrary);
	return result;
}

// 判断通讯录权限是否开启
function judgeIosPermissionContact() {
	var result = false;
	var CNContactStore = plus.ios.import('CNContactStore');
	var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
	if (cnAuthStatus == 3) {
		result = true;
		console.log('通讯录权限已经开启');
	} else {
			console.log('通讯录权限没有开启');
			unPermission.push('通讯录权限')
	}
	plus.ios.deleteObject(CNContactStore);
	return result;
}

// 判断日历权限是否开启
function judgeIosPermissionCalendar() {
	var result = false;
	var EKEventStore = plus.ios.import('EKEventStore');
	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0)
	if (ekAuthStatus == 3) {
		result = true;
		console.log('日历权限已经开启');
	} else {
			console.log('日历权限没有开启');
			unPermission.push('日历权限')
	}
	plus.ios.deleteObject(EKEventStore);
	return result;
}

// 判断备忘录权限是否开启
function judgeIosPermissionMemo() {
	var result = false;
	var EKEventStore = plus.ios.import('EKEventStore');
	var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
	if (ekAuthStatus == 3) {
		result = true;
		console.log('备忘录权限已经开启');
	} else {
			console.log('备忘录权限没有开启');
			nPermission.push('备忘录权限')
	}
	plus.ios.deleteObject(EKEventStore);
	return result;
}
//获取当前权限中文描述
function getCurrentPermissionType(permissionId) {
	console.log(permissionId);
	switch (permissionId) {
		case 'android.permission.READ_EXTERNAL_STORAGE':
			return '文件读取权限';
		case 'android.permission.WRITE_EXTERNAL_STORAGE':
			return '文件写入权限';
		case 'android.permission.CAMERA':
			return '相机权限';
		case 'android.permission.RECORD_AUDIO':
			return '麦克风权限';
		default:
			return '其他权限';
	}
}
// Android权限查询 -export
function requestAndroidPermission(permissionID) {
	console.log(permissionID.split(","));

	return new Promise((resolve, reject) => {
		plus.android.requestPermissions(
			permissionID.split(","),
			// [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
			function(resultObj) {
				var result = 0;
				for (var i = 0; i < resultObj.granted.length; i++) {
					var grantedPermission = resultObj.granted[i];
					console.log('已获取的权限:' + grantedPermission);
					result = 1;
				}
				for (var i = 0; i < resultObj.deniedPresent.length; i++) {
					var deniedPresentPermission = resultObj.deniedPresent[i];
					console.log('拒绝本次申请的权限:' + deniedPresentPermission);
					console.log('deniedPresentPermission', deniedPresentPermission);
					let permissionName = getCurrentPermissionType(deniedPresentPermission)
					console.log(permissionName);	
					unPermission.push(permissionName)
          result = 0;
				}
				for (var i = 0; i < resultObj.deniedAlways.length; i++) {
					var deniedAlwaysPermission = resultObj.deniedAlways[i];
					console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
					console.log('deniedPresentPermission', deniedAlwaysPermission);
					let permissionName = getCurrentPermissionType(deniedAlwaysPermission);
					unPermission.push(permissionName)
                    result = -1;
				}
				resolve(result);
				// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
				// if (result != 1) {
				// gotoAppPermissionSetting()
				// }
			},
			function(error) {
				console.log('申请权限错误:' + error.code + ' = ' + error.message);
				resolve({
					code: error.code,
					message: error.message
				});
			}
		);
	});
}



// 使用一个方法,根据参数判断权限 -export
function judgeIosPermission(permissionID) {
	return new Promise((resolve, reject) => {
		console.log(permissionID)
		let result
		if (permissionID == 'location') {
			result =judgeIosPermissionLocation();
			resolve(result)
		} else if (permissionID == 'camera') {
			result =judgeIosPermissionCamera();
			resolve(result)
		} else if (permissionID == 'photoLibrary') {
			result =judgeIosPermissionPhotoLibrary();
			resolve(result)
		} else if (permissionID == 'record') {
			result =judgeIosPermissionRecord();
			resolve(result)
		} else if (permissionID == 'push') {
			result =judgeIosPermissionPush();
			resolve(result)
		} else if (permissionID == 'contact') {
			result =judgeIosPermissionContact();
			resolve(result)
		} else if (permissionID == 'calendar') {
			result =judgeIosPermissionCalendar();
			resolve(result)
		} else if (permissionID == 'memo') {
			result =judgeIosPermissionMemo();
			resolve(result)
		}
		resolve(false);
	})

}

// 跳转到**应用**的权限页面 -export
export function gotoAppPermissionSetting() {
	if (isIos) {
		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);
	}
}

// 检查系统的设备服务是否开启 -export
// var checkSystemEnableLocation = async function () {
export function checkSystemEnableLocation() {
	if (isIos) {
		var result = false;
		var cllocationManger = plus.ios.import('CLLocationManager');
		var result = cllocationManger.locationServicesEnabled();
		console.log('系统定位开启:' + result);
		plus.ios.deleteObject(cllocationManger);
		return result;
	} else {
		var context = plus.android.importClass('android.content.Context');
		var locationManager = plus.android.importClass('android.location.LocationManager');
		var main = plus.android.runtimeMainActivity();
		var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
		var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
		console.log('系统定位开启:' + result);
		return result;
	}
}

let permissionMap = {
	"android": {
		"CAMERA_EXTERNAL_STORAGE": { // 相机权限/相册读写权限
			"name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA",
			"title": "相机/相册权限说明",
			"content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"
		},
		"CAMERA": { // 相机权限
			"name": "android.permission.CAMERA",
			"title": "相机权限说明",
			"content": "便于您使用该功能上传图片,用于与客服沟通等场景中发送拍摄图片"
		},
		"EXTERNAL_STORAGE": { //相册读写权限
			"name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE",
			"title": "相册读写权限说明",
			"content": "便于您使用该功能上传您的照片/图片/视频及用于更换头像、发布产品/需求、下载、与客服沟通等场景中读取和写入相册和文件内容"
		},
		"CAMERA_EXTERNAL_STORAGE_RECORD_AUDIO": { //视频录制和获取权限
			"name": "android.permission.READ_EXTERNAL_STORAGE,android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA,android.permission.RECORD_AUDIO",
			"title": "相机/相册和麦克风权限说明",
			"content": "便于您使用该功能获取并上传视频用于发布产品/需求过程中读取和写入视频文件内容"
		}
	},
	"ios": {}
}

let view = null;
//华为要求每一个获取权限都要有对应的说明提示,否则无法上架
function showViewDesc(permission) {
	let plat = isIos ? "ios" : "android";
	view = new plus.nativeObj.View('per-modal', {
		top: '0px',
		left: '0px',
		width: '100%',
		backgroundColor: 'rgba(0,0,0,0.2)',
		//opacity: '.9'     
	})
	view.drawRect({
		color: '#fff',
		radius: '5px'
	}, {
		top: '30px',
		left: '5%',
		width: '90%',
		height: "100px",
	})
	view.drawText(permissionMap[plat][permission]["title"], {
		top: '40px',
		left: "8%",
		height: "30px"
	}, {
		align: "left",
		color: "#000",
	}, {
		onClick: function(e) {
			console.log(e);
		}
	})
	view.drawText(permissionMap[plat][permission]["content"], {
		top: '65px',
		height: "60px",
		left: "8%",
		width: "84%"
	}, {
		whiteSpace: 'normal',
		size: "14px",
		align: "left",
		color: "#656563"
	})
	setTimeout(() => {
		if (viewShow) view.show()
	}, 200)
}

async function permissionIosCheck(permission) {
	console.log('permissionIosCheck',permission);
	let results = [];
	if (permission == 'CAMERA_EXTERNAL_STORAGE') {
		results.push(await judgeIosPermission('camera'));
		results.push(await judgeIosPermission('photoLibrary'));
	} else if (permission == 'CAMERA_EXTERNAL_STORAGE_RECORD_AUDIO') {
		results.push(await judgeIosPermission('camera'));
		results.push(await judgeIosPermission('photoLibrary'));
		results.push(await judgeIosPermission('record'));
	} else if (permission == 'CAMERA') {
		results.push(await judgeIosPermission('camera'));
	}else if(permission == 'RECORD'){
		results.push(await judgeIosPermission('record'));
	}else if(permission == 'PHOTO_LIBRARY'){
		results.push(await judgeIosPermission('photoLibrary'));
	}
	// 检查所有权限是否都已开启
	let allPermissionsGranted = results.every(result => result);
	return allPermissionsGranted;
}

// 权限检查
/**
 * 
 * @param {*} permission // 要获取的权限 type:String
 * @returns 
 */
function premissionCheck(permission) {
	console.log(permission);
	console.log(isIos);
	return new Promise(async (resolve, reject) => {
		let plat = isIos ? "ios" : "android";
		unPermission = []
		if (isIos) { // ios  

			// const camera = judgeIosPermissionCamera();//判断ios是否给予摄像头权限  
			// //ios相册没权限,系统会自动弹出授权框  
			// //let photoLibrary = permission.judgeIosPermission("photoLibrary");//判断ios是否给予相册权限  
			// if(camera){  
			//     resolve();  
			// }else{  
			//     reject('需要开启相机使用权限');  
			// }  
			console.log('permission', permission);
			if (permission) {
				let result = await permissionIosCheck(permission)
				if (result) {
					resolve(1)
				} else {
					// reject('需要开启相机使用权限');  
					let str = unPermission.join(',')
					uni.showModal({
						title: '温馨提示',
						content: `请注意:该功能需要获取${str}!`,
						showCancel: true,
						confirmText: '去设置',
						success: function(res) {
							if (res.confirm) {
								gotoAppPermissionSetting()
							} else if (res.cancel) {
								return
							}
						}

					})
				}
			}

		} else { // android  
			console.log("android");
			let permission_arr = permissionMap[plat][permission]["name"].split(",");
			console.log(permission_arr);
			let flag = true;
			for (let i = 0; i < permission_arr.length; i++) {
				let status = plus.navigator.checkPermission(permission_arr[i]);
				if (status == "undetermined") {
					flag = false;
				}
			}
			console.log("flag", flag)
			if (flag == false) { // 未完全授权  
				console.log('未授权');
				showViewDesc(permission);
				requestAndroidPermission(permissionMap[plat][permission]["name"]).then((res) => {
					viewShow = false;
					setTimeout(() => {
						viewShow = true;
					}, 120)
					console.log('值', res);

					if (res == -1) {
						let str = unPermission.join(',')
						console.log(str);
						uni.showModal({
							title: '提示',
							content: `操作权限已被拒绝,请手动前往设置${str}`,
							confirmText: "立即设置",
							success: (res) => {
								if (res.confirm) {
									gotoAppPermissionSetting()
								}
								view.close();
								resolve(res)
							},
							fail() {
								view.close();
								resolve(res)
							}

						})
					} else if (res == 1) {
						view.close();
						resolve(res)
					} else {
						view.close();
					}

				})
			} else {
				resolve(1)
			}
		}
	})
}
module.exports = {
	judgeIosPermission: judgeIosPermission,
	requestAndroidPermission: requestAndroidPermission,
	checkSystemEnableLocation: checkSystemEnableLocation,
	gotoAppPermissionSetting: gotoAppPermissionSetting,
	premissionCheck: premissionCheck
}

2.此时直接在选择文件之前判断是否有权限就可以了

javascript 复制代码
let result=1;
result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE") //使用

3.问题:这种使用方法在安卓手机上是没有问题的,但是在ios上会出现初次下载时app没有任何权限,引导进入权限列表开启时,权限列表页没有对应的开启按钮???

看到这里会很懵逼,权限不时都在权限列表吗,我当时也很懵,后来查阅资料明白,原来ios为了控制权限初次下载是没有任何额外权限的,只有当用户调起相机相册等的权限申请时,系统才会添加对应的权限控制按钮,此时无论用户点击的是允许还是拒绝,都会出现在权限列表中。所以此时不能直接调用permission中的方法判断是否有对应权限,应为判断了肯定没有,引导进入权限开启页面也无法开启。

4.解决方法

(1)在uni-file-picker的选择失败回调中判断是否是因为没有权限问题导致的,这样会先进行对应系统功能的调用,失败了再引导用户开启对应的权限,开启后用户再次点击就可以正常访问了。

javascript 复制代码
//uni-file-picker.vue 原码修改,
	import permission from '@/utils/permission.js'; //权限判断
	/**
			 * 选择文件并上传
			 */
			chooseFiles() {
				const _extname = get_extname(this.fileExtname)
				// 获取后缀
				uniCloud
					.chooseAndUploadFile({
						type: this.fileMediatype,
						compressed: false,
						sizeType: this.sizeType,
						sourceType: this.sourceType,
						// TODO 如果为空,video 有问题
						extension: _extname.length > 0 ? _extname : undefined,
						count: this.limitLength - this.files.length, //默认9
						onChooseFile: this.chooseFileCallback,
						onUploadProgress: progressEvent => {
							this.setProgress(progressEvent, progressEvent.index)
						}
					})
					.then(result => {
						console.log('选择成功', result);
						this.setSuccessAndError(result.tempFiles)
					})
					.catch(async err => {
						console.log('选择失败', err)
						let result = 1
						// #ifdef APP-PLUS
						uni.getSystemInfo({
							success: async function(res) {
								if (res.osName == 'ios') {
									if (err.errMsg == 'chooseAndUploadFile:fail No filming permission') {
										console.log('没有权限');
										result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE") //使用
									}
								} else {
									result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE")
								}
							}
						})
						// #endif
					})
			},

(2)通过判断是否为ios ,如果为ios 单独判断,不是ios直接引导去开区

javascript 复制代码
			uni.getSystemInfo({
				success: async function (res) {
					//#ifdef APP-PLUS
					console.log(res);
					if (res.osName == 'ios') {
						const appAuthorizeSetting = uni.getAppAuthorizeSetting()
						let iosFirstCamera = (appAuthorizeSetting.cameraAuthorized != 'not determined' ? 'false' : 'true') //设为false就代表不是第一次开启相机
						let iosFirstPhoto = (appAuthorizeSetting.albumAuthorized != 'not determined' ? 'false' : 'true') //设为false就代表不是第一次开启相册
						// console.log('iosFirstCamera', iosFirstCamera);
						// console.log('iosFirstPhoto', iosFirstPhoto);
						
						if (iosFirstCamera == 'false' && iosFirstPhoto == 'false') {
							result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE")
						} else if (appAuthorizeSetting.cameraAuthorized == 'denied') {
							result = await permission.premissionCheck("CAMERA")
						} else if (appAuthorizeSetting.albumAuthorized == 'denied') {
							result = await permission.premissionCheck("PHOTO_LIBRARY")
						}
					} else {
						result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE")
					}
					// #endif
					if (result == 1) {
					//插件
						that.$refs.XeUpload.upload(that.type)
					}
					// });
				}
			})

上面是先判断是否是ios const appAuthorizeSetting = uni.getAppAuthorizeSetting() 这个可以判断对应权限是否没有调用过,没有调用正常执行,有调用执行权限检查。

javascript 复制代码
例如:
const appAuthorizeSetting = uni.getAppAuthorizeSetting()
'authorized':表示已经获得授权,无需再次请求授权;
'denied':表示请求授权被拒绝,无法再次请求授权;(此情况需要引导用户打开系统设置,在设置页中打开权限)
'not determined':表示尚未请求授权,会在App下一次调用系统相应权限时请求;(仅 iOS 会出现。此种情况下引导用户打开系统设置,不展示开关)
'config error':只有在 App 端时返回
appAuthorizeSetting.albumAuthorized == 'denied' //这种可以单独申请对应的权限检
查,没有引导进入权限控制列表
[官网对应方法地址](https://uniapp.dcloud.net.cn/api/system/getappauthorizesetting.html#getappauthorizesetting)
相关推荐
程序员王天29 分钟前
Uniapp 自定义TabBar + 动态菜单实现教程(Vuex状态管理详解)
微信小程序·uni-app
卡尔特斯5 小时前
Uniapp 控制台日志工具(DZMUniappConsoleLog)
前端·uni-app
xixixin_7 小时前
【uniapp】uni.setClipboardData 方法失效 bug 解决方案
java·前端·uni-app
学前端搞口饭吃7 小时前
uniapp打ios包
ios·uni-app
```陪伴7 小时前
uniapp打包IOS私钥证书过期了,如何在非mac系统操作
macos·ios·uni-app
Monly2112 小时前
Uniapp:创建项目
uni-app
清晨細雨12 小时前
uniapp微信小程序:WIFI设备配网之TCP/UDP开发AP配网
前端·物联网·小程序·uni-app
寒寒_12 小时前
uni-app 安卓10以上上传原图解决方案
uni-app
敲代码的彭于晏13 小时前
2025 年必看!uni-app 结合 VSCode 实现高效跨平台开发入门
vue.js·uni-app