这是我的权限弹窗组件, 里面加一个手机通知栏的权限 怎么加
<template>
<!-- 权限申请弹窗组件 -->
<view v-if="showPopup" class="uni-popup" :style="{top:isNativeHead?'':StatusBar}">
<view :class="[type, ani, animation ? 'ani' : '']" class="uni-custom uni-popup__wrapper" @click.stop="close(true)">
<view class="uni-popup__wrapper-box">
<view class="title">{{currentPermissionData.title}}</view>
<view class="content">{{currentPermissionData.content}}</view>
<!-- 操作按钮区域 -->
<view class="action-buttons">
<button class="btn cancel" @click.stop="handleLater">稍后再说</button>
<button class="btn confirm" @click.stop="handleAuthorize">立即授权</button>
</view>
</view>
</view>
</view>
</template>
<script>
// 权限状态常量
const IOS_PERMISSION_STATUS = {
NOT_DETERMINED: 0, // 未决定
RESTRICTED: 1, // 受限制
DENIED: 2, // 拒绝
AUTHORIZED: 3, // 授权
LIMITED: 4 // 有限授权(仅照片)
};
// 权限信息配置 - 集中管理
const PERMISSION_DATA = {
// 'WRITE_EXTERNAL_STORAGE': {
// title: "霍小帮对存储空间/照片权限申请说明",
// content: "便于您使用该功能上传您的照片/图片/视频及用于更换头像、意见反馈、保存相册、发布商品/分享、下载与客服沟通等场景中读取和写入相册和文件内容。"
// },
// 'ACCESS_FINE_LOCATION': {
// title: "霍小帮对地理位置权限申请说明",
// content: "便于应用程序可以提供基于位置的服务、定位导航、附近搜索等功能。APP收集WIFI扫描结果的目的为提供定位服务,仅在首页获取定位的城市的时候需要使用到,只收集周围可用WIFI网络的名称和信号强度等信息,不收集WIFI密码等敏感信息!为同城配送功能会获取骑手当前位置,不储存任何隐私信息!" },
// 'CAMERA':{
// title: "霍小帮对相机/摄像头权限申请说明",
// content: "便于您使用该功能拍照上传您的照片/视频及用于更换头像、意见反馈、保存相册、发布商品/动态、下载与客服沟通等场景中使用"
// },
// 'RECORD_AUDIO':{
// title: "霍小帮对麦克风权限申请说明",
// content: "便于您使用该功能进行录音、语音通话、发布语音、与客服语音沟通等场景中使用"
// },
// 'READ_PHONE_STATE':{
// title: "霍小帮对获取设备信息申请说明",
// content: "首次或切换设备请允许此权限,便于您收到APP的系统通知或APP内平台公告/好友消息通知的场景中使用,不会泄露任何个人信息,我们只保存您的设备ID用于发送消息通知"
// },
// 'CALL_PHONE': {
// title: "霍小帮对拨打/管理电话权限申请说明",
// content: "便于您使用该功能联系买家、骑手或者客服、业务经理与联系等场景下使用"
// }
WRITE_EXTERNAL_STORAGE: {
title: "存储空间/照片权限说明",
content: "用于上传照片/图片/视频、更换头像、意见反馈、保存相册等功能",
iosPermission: "PHPhotoLibrary" // iOS 对应的权限类
},
ACCESS_FINE_LOCATION: {
title: "地理位置权限说明",
content: "用于提供定位服务、附近搜索等功能,保护您的隐私安全",
iosPermission: "CLLocationManager"
},
CAMERA: {
title: "相机/摄像头权限说明",
content: "用于拍照上传照片/视频、更换头像、发布商品等功能",
iosPermission: "AVCaptureDevice"
},
RECORD_AUDIO: {
title: "麦克风权限说明",
content: "用于语音通话、语音消息、客服沟通等功能",
iosPermission: "AVAudioSession"
},
READ_PHONE_STATE: {
title: "设备信息权限说明",
content: "用于系统通知、消息推送功能,保护您的个人信息安全",
iosPermission: "CNContactStore"
},
CALL_PHONE: {
title: "电话权限说明",
content: "用于联系买家、骑手或客服等功能",
iosPermission: "CNContactStore"
}
};
export default {
name: 'YkAuthPopup',
props: {
animation: {
type: Boolean,
default: true
},
type: {
type: String,
default: 'top'
},
show: {
type: Boolean,
default: true
},
isNativeHead: {
type: Boolean,
default: false
},
permissionID: {
type: [String, Number],
required: true
}
},
data() {
return {
ani: '',
showPopup: false,
StatusBar: '',
refuseNum: 0, // 拒绝次数
currentPermissionData: {}, // 当前权限数据
authList: PERMISSION_DATA // 权限配置映射
}
},
watch: {
permissionID: {
immediate: true,
handler(newVal) {
// 更新当前权限数据
this.currentPermissionData = this.authList[newVal] || {};
}
}
},
created() {
// #ifdef APP-PLUS
this.getSystemInfo();
// #endif
},
methods: {
// 获取状态栏高度
getSystemInfo() {
uni.getSystemInfo({
success: (e) => {
this.StatusBar = e.statusBarHeight + 'px';
}
})
},
open() {
this.$nextTick(() => {
setTimeout(() => {
this.ani = 'uni-' + this.type;
// 延迟后自动检查权限
setTimeout(() => {
this.checkPermissions();
}, 300);
}, 30);
});
},
close() {
this.ani = '';
this.$nextTick(() => {
setTimeout(() => {
this.showPopup = false;
}, 300);
});
},
// 稍后再说处理
handleLater() {
this.close();
this.refuseNum++;
// 如果拒绝超过3次,显示引导提示
if (this.refuseNum >= 3) {
this.$emit('permission-denied', this.permissionID);
}
},
// 立即授权处理
handleAuthorize() {
this.close();
this.requestPermissions();
},
// 统一权限检查方法
async checkPermissions() {
var _this = this
const platform = plus.os.name;
// Android 权限检查
if (platform === 'Android') {
try {
const permissionStr = 'android.permission.' + this.permissionID;
const result = await new Promise((resolve) => {
plus.android.checkPermission(permissionStr, resolve);
});
if (result?.checkResult === -1) {
// 未授权:显示弹窗(已显示)
this.showPopup = true;
return;
}
// 已授权,通知父组件
this.$emit('changeAuth');
} catch (error) {
console.error('权限检查失败:', error);
}
}else if (platform === 'iOS') {
// try {
// const granted = await this.checkIOSPermission();
// if (granted) {
// // 已授权,通知父组件
// this.$emit('changeAuth');
// }
// } catch (error) {
// console.error('iOS权限检查失败:', error);
// }
//IOS不需要添加自定义弹框来描述权限目的,因为在配置文件的隐私信息访问的许可描述里可添加
//正常可以直接调用uni的API调起权限询问弹框使用各种权限,下面的判断使用场景主要是在IOS禁用某权限后,这个可以判断有无权限,进而引导用户跳转设置开启,仅列出了位置、相册、通讯录、相机、录音等权限,其他IOS权限可具体参考 https://ext.dcloud.net.cn/plugin?id=15787
let result = 0;
let permissionID = this.permissionID
console.log(permissionID,'permissionID');
if (permissionID == 'ACCESS_FINE_LOCATION') {
//IOS检测位置权限
let cLLocationManager = plus.ios.importClass("CLLocationManager"),
authStatus = cLLocationManager.authorizationStatus(),
enable = cLLocationManager.locationServicesEnabled();
if (enable && authStatus != 2) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(cLLocationManager);
} else if (permissionID == 'WRITE_EXTERNAL_STORAGE') {
//IOS检测相册权限
let PHPhotoLibrary = plus.ios.importClass("PHPhotoLibrary"),
authStatus = PHPhotoLibrary.authorizationStatus();
if (authStatus === 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(PHPhotoLibrary);
} else if (permissionID == 'CAMERA') {
//IOS检测相机/摄像头权限
let avCaptureDevice = plus.ios.importClass("AVCaptureDevice"),
authStatus = avCaptureDevice.authorizationStatusForMediaType("vide");
if (authStatus === 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(avCaptureDevice);
} else if (permissionID == 'CALL_PHONE') {
//IOS检测通讯录权限
let contactStore = plus.ios.importClass("CNContactStore"),
authStatus = contactStore.authorizationStatusForEntityType(0);
// console.log(authStatus,'authStatus');
if (authStatus === 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(contactStore);
}else if(permissionID == 'RECORD_AUDIO'){
//IOS检测麦克风权限
let aVAudioSession = plus.ios.importClass("AVAudioSession"),
aVAudio = aVAudioSession.sharedInstance(),
authStatus = aVAudio.recordPermission();
if ([1684369017, 1970168948].includes(authStatus)) {
result = 0;
} else {
result = 1;
}
plus.ios.deleteObject(aVAudioSession);
}
console.log(result,'result');
if (result) {
//当前查询权限已授权,此时可以通知页面执行接下来的操作
_this.$emit('changeAuth')
} else {
this.showPopup = true;
// //当前查询的权限已禁用,引导用户跳转手机系统设置去开启
// if(permissionID == 'READ_PHONE_STATE'){
// }else{
// console.log(this.currentPermissionData,'this.currentPermissionData');
// this.$util.showModal({
// title: '温馨提示【'+permissionID+'】',
// content: '请再设置打开此权限,更好使用此页面功能~',//是否立刻前往?'
// // cancelText: "取消",
// confirmText: "我知道了",
// showCancel: true,
// confirmColor: '#000',
// cancelColor: '#666',
// success: (res) => {
// if (res.confirm) {
// // _this.goSetting();
// }
// }
// })
// }
}
}
},
// 修复后的 iOS 权限检查方法
async checkIOSPermission() {
try {
// 特殊处理不需要权限检查的情况
if (this.permissionID === 'READ_PHONE_STATE') {
// iOS 设备信息不需要额外权限
return true;
}
// 获取对应的权限类名
const permissionClass = this.currentPermissionData?.iosPermission;
if (!permissionClass) {
console.error(`未配置权限类: ${this.permissionID}`);
return false;
}
// 安全导入 iOS 类
let manager;
try {
manager = plus.ios.importClass(permissionClass);
if (!manager) {
console.warn(`无法导入iOS类: ${permissionClass}`);
return false;
}
} catch (importError) {
console.error(`导入iOS类失败: ${permissionClass}`, importError);
return false;
}
// 统一权限状态检查
let granted = false;
switch (this.permissionID) {
case 'ACCESS_FINE_LOCATION':
// 位置权限检查
const authStatus = manager.authorizationStatus?.();
const enabled = manager.locationServicesEnabled?.();
granted = !!enabled && authStatus !== 2;
break;
case 'WRITE_EXTERNAL_STORAGE':
// 存储权限检查
granted = manager.authorizationStatus?.() === 3;
break;
case 'CAMERA':
// 相机权限检查
granted = manager.authorizationStatusForMediaType?.("vide") === 3;
break;
case 'CALL_PHONE':
case 'READ_PHONE_STATE':
// 电话权限检查
// iOS 14+ 需要使用 CNContactStore 检查通讯录权限
const authStatusPhone = manager.authorizationStatusForEntityType?.(0);
granted = authStatusPhone === 3;
break;
case 'RECORD_AUDIO':
// 麦克风权限检查
const session = manager.sharedInstance?.();
const status = session?.recordPermission?.();
// 使用更安全的状态检查方式
const deniedStatuses = [1684369017, 1970168948];
granted = !deniedStatuses.includes(status);
break;
default:
console.warn(`未处理的权限类型: ${this.permissionID}`);
granted = false;
}
return granted;
} catch (error) {
console.error(`iOS权限检查失败: ${this.permissionID}`, error);
return false;
} finally {
// 确保释放原生对象
if (manager) {
try {
plus.ios.deleteObject(manager);
} catch (deleteError) {
console.warn(`释放iOS对象失败:`, deleteError);
}
}
}
},
// 请求权限的统一方法
async requestPermissions() {
const platform = plus.os.name;
if (platform === 'Android') {
await this.requestAndroidPermission();
} else if (platform === 'iOS') {
await this.requestIOSPermission();
}
},
// Android 请求权限
requestAndroidPermission() {
return new Promise((resolve) => {
const permissionStr = 'android.permission.' + this.permissionID;
plus.android.requestPermissions([permissionStr], (e) => {
if (e.granted.length > 0) {
this.$emit('changeAuth');
} else if (e.deniedAlways.length > 0) {
this.showSettingGuide();
}
resolve();
});
});
},
// iOS权限检查与请求方法
async requestIOSPermission() {
// 特殊处理不需要请求的权限
if (this.permissionID === 'READ_PHONE_STATE') {
console.log('iOS设备信息权限不需要请求');
this.$emit('changeAuth');
return true;
}
try {
// 1. 获取原生权限管理器
const { manager, checkMethod, requestMethod } = this.getIOSPermissionManager();
if (!manager || !checkMethod) {
console.warn(`不支持此权限类型: ${this.permissionID}`);
return false;
}
// 2. 检查当前权限状态
const status = await this.checkIOSPermissionStatus(manager, checkMethod);
console.log(`权限 ${this.permissionID} 当前状态:`, status);
if (status === IOS_PERMISSION_STATUS.AUTHORIZED) {
console.log('权限已授权');
this.$emit('changeAuth');
return true;
}
if (status === IOS_PERMISSION_STATUS.DENIED) {
console.log('权限已永久拒绝');
this.showSettingGuide();
return false;
}
// 3. 请求权限
if (status === IOS_PERMISSION_STATUS.NOT_DETERMINED) {
console.log('准备请求权限:', this.permissionID);
const granted = await this.requestIOSPermissionNative(manager, requestMethod);
// 检查最终状态
const finalStatus = await this.checkIOSPermissionStatus(manager, checkMethod);
if (finalStatus === IOS_PERMISSION_STATUS.AUTHORIZED) {
console.log('授权成功');
this.$emit('changeAuth');
return true;
}
console.log('最终权限状态:', finalStatus);
if (finalStatus === IOS_PERMISSION_STATUS.DENIED) {
this.showSettingGuide();
}
return false;
}
return false;
} catch (error) {
console.error('iOS权限处理异常:', error);
return false;
}
},
// 获取iOS原生权限管理器
getIOSPermissionManager() {
const permissionMap = {
'ACCESS_FINE_LOCATION': {
class: 'CLLocationManager',
checkMethod: 'authorizationStatus',
requestMethod: 'requestWhenInUseAuthorization'
},
'WRITE_EXTERNAL_STORAGE': {
class: 'PHPhotoLibrary',
checkMethod: 'authorizationStatus',
requestMethod: 'requestAuthorization'
},
'CAMERA': {
class: 'AVCaptureDevice',
checkMethod: (manager) => manager.authorizationStatusForMediaType('vide'),
requestMethod: 'requestAccessForMediaType:completionHandler:'
},
'RECORD_AUDIO': {
class: 'AVAudioSession',
checkMethod: 'recordPermission',
requestMethod: 'requestRecordPermission:'
},
'CALL_PHONE': {
class: 'CNContactStore',
checkMethod: (manager) => manager.authorizationStatusForEntityType(0),
requestMethod: 'requestAccessForEntityType:completionHandler:'
}
};
const config = permissionMap[this.permissionID];
if (!config) {
console.warn(`未定义的权限类型: ${this.permissionID}`);
return {};
}
try {
const manager = plus.ios.importClass(config.class);
return {
manager: manager,
checkMethod: config.checkMethod,
requestMethod: config.requestMethod
};
} catch (error) {
console.error(`导入iOS类失败: ${config.class}`, error);
return {};
}
},
// 检查iOS权限状态
checkIOSPermissionStatus(manager, checkMethod) {
return new Promise((resolve) => {
try {
// 方法类型处理
let status;
if (typeof checkMethod === 'function') {
status = checkMethod(manager);
} else if (typeof manager[checkMethod] === 'function') {
status = manager[checkMethod]();
} else {
console.warn('不支持的状态检查方法');
resolve(IOS_PERMISSION_STATUS.NOT_DETERMINED);
return;
}
// 特殊处理麦克风权限
if (this.permissionID === 'RECORD_AUDIO') {
// 麦克风权限状态码特殊处理
const AVAudioSessionRecordPermission = {
Undetermined: 1970168948, // 'undt'
Denied: 1684369017, // 'deny'
Granted: 1735552628 // 'grnt'
};
if (status === AVAudioSessionRecordPermission.Granted) {
resolve(IOS_PERMISSION_STATUS.AUTHORIZED);
} else if (status === AVAudioSessionRecordPermission.Denied) {
resolve(IOS_PERMISSION_STATUS.DENIED);
} else {
resolve(IOS_PERMISSION_STATUS.NOT_DETERMINED);
}
return;
}
// 通用状态解析
resolve(status);
} catch (error) {
console.error('权限状态检查失败:', error);
resolve(IOS_PERMISSION_STATUS.NOT_DETERMINED);
}
});
},
// 请求iOS权限(原生方式)
requestIOSPermissionNative(manager, requestMethod) {
return new Promise((resolve) => {
try {
// 处理不同的请求方法
switch (this.permissionID) {
case 'ACCESS_FINE_LOCATION':
// 位置权限
const locationManager = manager.new();
if (locationManager[requestMethod]) {
locationManager[requestMethod]();
// 设置代理监听状态变化
const delegate = plus.ios.implements('CLLocationManagerDelegate', {
'locationManager:didChangeAuthorizationStatus:': (mgr, status) => {
if (status === 3 || status === 4) {
resolve(true);
} else if (status === 2) {
resolve(false);
}
plus.ios.deleteObject(locationManager);
}
});
locationManager.delegate = delegate;
} else {
resolve(false);
}
break;
case 'WRITE_EXTERNAL_STORAGE':
// 存储权限
manager[requestMethod](function(status) {
resolve(status === 3);
});
break;
case 'CAMERA':
// 相机权限
manager[requestMethod]('vide', function(granted) {
resolve(granted);
});
break;
case 'RECORD_AUDIO':
// 麦克风权限
const audioSession = manager.sharedInstance();
audioSession[requestMethod](function(granted) {
resolve(granted);
});
break;
case 'CALL_PHONE':
// 电话权限
const contactStore = manager.new();
contactStore[requestMethod](0, function(granted, error) {
resolve(!error && granted);
});
break;
default:
resolve(false);
}
} catch (error) {
console.error('权限请求失败:', error);
resolve(false);
}
});
},
// 获取 iOS 对应的 scope
getIOSScope() {
const mapping = {
'ACCESS_FINE_LOCATION': 'scope.userLocation',
'WRITE_EXTERNAL_STORAGE': 'scope.writePhotosAlbum',
'CAMERA': 'scope.camera',
'RECORD_AUDIO': 'scope.record',
'READ_PHONE_STATE': 'scope.notification',
'CALL_PHONE': 'scope.addressBook'
};
return mapping[this.permissionID] || '';
},
// 显示设置引导
showSettingGuide() {
this.$util.showModal({
title: '温馨提示',
content: '请前往系统设置开启权限,以获得完整功能体验',
cancelText: "取消",
confirmText: "前往设置",
showCancel: true,
confirmColor: '#000',
cancelColor: '#666',
success: (res) => {
if (res.confirm) {
this.goSetting();
}
}
});
},
// 跳转系统设置
goSetting() {
// Android
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);
}
// iOS
else {
const UIApplication = plus.ios.import("UIApplication");
const application = UIApplication.sharedApplication();
const NSURL = plus.ios.import("NSURL");
try {
// 优先使用官方设置URL
const settingsURL = NSURL.URLWithString(UIApplicationOpenSettingsURLString);
if (application.canOpenURL(settingsURL)) {
const iosVersion = parseFloat(plus.os.version);
if (iosVersion >= 10.0) {
application.openURLOptionsCompletionHandler(settingsURL, {}, null);
} else {
application.openURL(settingsURL);
}
return;
}
} catch (e) {
console.warn("使用官方设置URL失败,尝试备选方案");
}
// 备选方案
const settingsURL = NSURL.URLWithString("app-settings:");
application.openURL(settingsURL);
}
}
}
}
</script>
<style lang="scss">
.uni-popup {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 99999;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-start;
justify-content: center;
&__wrapper {
position: relative;
margin-top: 100rpx;
&.ani {
transition: all 0.3s ease-out;
}
&.top {
animation: slideDown 0.3s forwards;
}
&-box {
width: 650rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.15);
.title {
padding: 30rpx 30rpx 10rpx;
font-size: 34rpx;
font-weight: bold;
color: #333;
text-align: center;
}
.content {
padding: 20rpx 40rpx;
font-size: 28rpx;
color: #666;
line-height: 1.6;
text-align: center;
}
}
}
}
.action-buttons {
display: flex;
border-top: 1rpx solid #eee;
margin-top: 20rpx;
.btn {
flex: 1;
height: 90rpx;
line-height: 90rpx;
font-size: 32rpx;
border-radius: 0;
background: none;
position: relative;
margin: 0;
&::after {
border: none;
}
&.cancel {
color: #999;
border-right: 1rpx solid #eee;
}
&.confirm {
color: #007AFF;
font-weight: 500;
}
}
}
@keyframes slideDown {
from {
transform: translateY(-100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
</style>
最新发布