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)