309 lines
8.5 KiB
JavaScript
309 lines
8.5 KiB
JavaScript
|
|
// permissionUtils.js
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 统一权限检测工具
|
|||
|
|
* 支持平台:APP(Android/iOS)、微信小程序、H5
|
|||
|
|
*/
|
|||
|
|
export default {
|
|||
|
|
/**
|
|||
|
|
* 检查权限状态
|
|||
|
|
* @param {String} permission 权限类型
|
|||
|
|
* @param {String} description 权限描述(仅APP端需要)
|
|||
|
|
* @returns {Promise<Object>}
|
|||
|
|
* - granted: 是否已授权
|
|||
|
|
* - firstRequest: 是否第一次请求
|
|||
|
|
* - canRequest: 是否可以请求(用户未永久拒绝)
|
|||
|
|
*/
|
|||
|
|
async checkPermission(permission, description = '') {
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
return await this._checkAppPermission(permission, description);
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef MP-WEIXIN
|
|||
|
|
return await this._checkMpPermission(permission);
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef H5
|
|||
|
|
// H5默认返回已授权,实际权限由浏览器控制
|
|||
|
|
return { granted: true, firstRequest: false, canRequest: false };
|
|||
|
|
// #endif
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* APP端权限检查
|
|||
|
|
*/
|
|||
|
|
async _checkAppPermission(permission, description) {
|
|||
|
|
// Android和iOS通用权限映射
|
|||
|
|
const permissionMap = {
|
|||
|
|
'camera': {
|
|||
|
|
android: 'android.permission.CAMERA',
|
|||
|
|
ios: 'camera'
|
|||
|
|
},
|
|||
|
|
'location': {
|
|||
|
|
android: 'android.permission.ACCESS_FINE_LOCATION',
|
|||
|
|
ios: 'location'
|
|||
|
|
},
|
|||
|
|
'phone': {
|
|||
|
|
android: 'android.permission.CALL_PHONE',
|
|||
|
|
ios: 'phone'
|
|||
|
|
},
|
|||
|
|
'photo_library': {
|
|||
|
|
android: [
|
|||
|
|
'android.permission.READ_EXTERNAL_STORAGE',
|
|||
|
|
'android.permission.WRITE_EXTERNAL_STORAGE'
|
|||
|
|
],
|
|||
|
|
ios: 'photo_library',
|
|||
|
|
}
|
|||
|
|
// 添加其他需要的权限...
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const platformPerm = permissionMap[permission];
|
|||
|
|
if (!platformPerm) {
|
|||
|
|
console.error('不支持的权限类型:', permission);
|
|||
|
|
return { granted: false, firstRequest: false, canRequest: false };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
if (plus.os.name === 'Android') {
|
|||
|
|
return this._checkAndroidPermission(platformPerm.android);
|
|||
|
|
}else {
|
|||
|
|
return this._checkIosPermission(platformPerm.ios, description);
|
|||
|
|
}
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
return { granted: false, firstRequest: false, canRequest: false };
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Android权限检查
|
|||
|
|
*/
|
|||
|
|
async _checkAndroidPermission(permission) {
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
plus.android.requestPermissions(
|
|||
|
|
Array.isArray(permission) ? permission : [permission],
|
|||
|
|
(e) => {
|
|||
|
|
console.log(`perm_${permission}`,e)
|
|||
|
|
// 第一次请求标记
|
|||
|
|
const firstRequest = !plus.storage.getItem(`perm_${permission}`);
|
|||
|
|
if (firstRequest) {
|
|||
|
|
plus.storage.setItem(`perm_${permission}`, '1');
|
|||
|
|
}
|
|||
|
|
if(e.deniedPresent.length !== 0) {
|
|||
|
|
plus.storage.setItem(`perm_${permission}_no`, '2');
|
|||
|
|
}
|
|||
|
|
if(e.granted.length !== 0) {
|
|||
|
|
plus.storage.removeItem(`perm_${permission}_no`, '2');
|
|||
|
|
}
|
|||
|
|
resolve({
|
|||
|
|
granted: e.granted.length !== 0,
|
|||
|
|
firstRequest,
|
|||
|
|
canRequest: true // Android可以重复请求
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
(e) => {
|
|||
|
|
resolve({
|
|||
|
|
granted: false,
|
|||
|
|
firstRequest: false,
|
|||
|
|
canRequest: true
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* iOS权限检查
|
|||
|
|
*/
|
|||
|
|
async _checkIosPermission(permission, description) {
|
|||
|
|
try {
|
|||
|
|
let status;
|
|||
|
|
switch (permission) {
|
|||
|
|
case 'camera':
|
|||
|
|
status = plus.ios.invoke('AVCaptureDevice', 'authorizationStatusForMediaType:', 'vide');
|
|||
|
|
break;
|
|||
|
|
case 'location':
|
|||
|
|
const locationManager = plus.ios.newObject('CLLocationManager');
|
|||
|
|
status = plus.ios.invoke(locationManager, 'authorizationStatus');
|
|||
|
|
plus.ios.deleteObject(locationManager);
|
|||
|
|
break;
|
|||
|
|
// 其他权限处理...
|
|||
|
|
default:
|
|||
|
|
return { granted: false, firstRequest: false, canRequest: false };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// iOS授权状态
|
|||
|
|
// 0: 未决定(第一次)
|
|||
|
|
// 1: 受限
|
|||
|
|
// 2: 已拒绝
|
|||
|
|
// 3: 已授权
|
|||
|
|
return {
|
|||
|
|
granted: status === 3,
|
|||
|
|
firstRequest: status === 0,
|
|||
|
|
canRequest: status !== 2 // 不是永久拒绝
|
|||
|
|
};
|
|||
|
|
} catch (e) {
|
|||
|
|
console.error('iOS权限检查错误:', e);
|
|||
|
|
return { granted: false, firstRequest: false, canRequest: false };
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 小程序权限检查
|
|||
|
|
*/
|
|||
|
|
async _checkMpPermission(permission) {
|
|||
|
|
// 小程序scope映射
|
|||
|
|
const scopeMap = {
|
|||
|
|
'camera': 'scope.camera',
|
|||
|
|
'location': 'scope.userLocation',
|
|||
|
|
'record': 'scope.record',
|
|||
|
|
// 其他小程序权限...
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const scope = scopeMap[permission];
|
|||
|
|
if (!scope) {
|
|||
|
|
return { granted: false, firstRequest: false, canRequest: false };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
uni.getSetting({
|
|||
|
|
success(res) {
|
|||
|
|
const authSetting = res.authSetting;
|
|||
|
|
resolve({
|
|||
|
|
granted: authSetting[scope] === true,
|
|||
|
|
firstRequest: authSetting[scope] === undefined,
|
|||
|
|
canRequest: authSetting[scope] !== false // 不是拒绝状态
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
fail() {
|
|||
|
|
resolve({ granted: false, firstRequest: false, canRequest: false });
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 请求权限
|
|||
|
|
*/
|
|||
|
|
async requestPermission(permission, description = '') {
|
|||
|
|
const { granted, firstRequest, canRequest } = await this.checkPermission(permission, description);
|
|||
|
|
|
|||
|
|
if (granted) return true;
|
|||
|
|
if (!canRequest) return false;
|
|||
|
|
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
return this._requestAppPermission(permission, description);
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef MP-WEIXIN
|
|||
|
|
return this._requestMpPermission(permission);
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef H5
|
|||
|
|
return false; // H5无法主动请求权限
|
|||
|
|
// #endif
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* APP端请求权限
|
|||
|
|
*/
|
|||
|
|
async _requestAppPermission(permission, description) {
|
|||
|
|
// #ifdef APP-PLUS && ANDROID
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
plus.android.requestPermissions(
|
|||
|
|
[permission],
|
|||
|
|
(e) => resolve(e.denied.length === 0),
|
|||
|
|
() => resolve(false)
|
|||
|
|
);
|
|||
|
|
});
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef APP-PLUS && IOS
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
switch (permission) {
|
|||
|
|
case 'camera':
|
|||
|
|
plus.ios.invoke('AVCaptureDevice', 'requestAccessForMediaType:completionHandler:', 'vide', (granted) => {
|
|||
|
|
resolve(granted);
|
|||
|
|
});
|
|||
|
|
break;
|
|||
|
|
case 'location':
|
|||
|
|
const locationManager = plus.ios.newObject('CLLocationManager');
|
|||
|
|
plus.ios.invoke(locationManager, 'requestWhenInUseAuthorization');
|
|||
|
|
// iOS定位权限需要监听变化
|
|||
|
|
setTimeout(() => {
|
|||
|
|
const status = plus.ios.invoke(locationManager, 'authorizationStatus');
|
|||
|
|
plus.ios.deleteObject(locationManager);
|
|||
|
|
resolve(status === 3 || status === 4);
|
|||
|
|
}, 300);
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
resolve(false);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 小程序请求权限
|
|||
|
|
*/
|
|||
|
|
async _requestMpPermission(permission) {
|
|||
|
|
const scopeMap = {
|
|||
|
|
'camera': 'scope.camera',
|
|||
|
|
'location': 'scope.userLocation',
|
|||
|
|
'record': 'scope.record',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const scope = scopeMap[permission];
|
|||
|
|
if (!scope) return false;
|
|||
|
|
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
uni.authorize({
|
|||
|
|
scope,
|
|||
|
|
success: () => resolve(true),
|
|||
|
|
fail: () => resolve(false)
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 打开系统设置页
|
|||
|
|
*/
|
|||
|
|
openSystemSettings() {
|
|||
|
|
// #ifdef APP-PLUS
|
|||
|
|
if (plus.os.name === 'Android') {
|
|||
|
|
const Intent = plus.android.importClass('android.content.Intent');
|
|||
|
|
const Settings = plus.android.importClass('android.provider.Settings');
|
|||
|
|
const Uri = plus.android.importClass('android.net.Uri');
|
|||
|
|
const mainActivity = plus.android.runtimeMainActivity();
|
|||
|
|
|
|||
|
|
const intent = new Intent();
|
|||
|
|
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
|||
|
|
const uri = Uri.fromParts('package', mainActivity.getPackageName(), null);
|
|||
|
|
intent.setData(uri);
|
|||
|
|
mainActivity.startActivity(intent);
|
|||
|
|
} else {
|
|||
|
|
const UIApplication = plus.ios.import('UIApplication');
|
|||
|
|
const NSURL = plus.ios.import('NSURL');
|
|||
|
|
const url = NSURL.URLWithString('app-settings:');
|
|||
|
|
const application = UIApplication.sharedApplication();
|
|||
|
|
|
|||
|
|
if (plus.ios.invoke(application, 'canOpenURL:', url)) {
|
|||
|
|
plus.ios.invoke(application, 'openURL:', url);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
plus.ios.deleteObject(url);
|
|||
|
|
plus.ios.deleteObject(application);
|
|||
|
|
}
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef MP-WEIXIN
|
|||
|
|
uni.openSetting();
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifdef H5
|
|||
|
|
console.log('H5无法打开系统设置');
|
|||
|
|
// #endif
|
|||
|
|
}
|
|||
|
|
};
|