/** * 权限处理工具类 * 用于处理H5端的各种权限请求和状态检测 */ import { t } from "@/utils/i18n"; // 权限状态类型 export type PermissionState = 'granted' | 'denied' | 'prompt' | 'unknown' // 权限类型 export type PermissionType = 'microphone' | 'camera' | 'geolocation' | 'notifications' /** * 权限管理器类 */ export class PermissionManager { private static instance: PermissionManager | null = null private constructor() {} /** * 获取单例实例 */ static getInstance(): PermissionManager { if (!PermissionManager.instance) { PermissionManager.instance = new PermissionManager() } return PermissionManager.instance } /** * 检查权限状态 * @param permissionType 权限类型 * @returns 权限状态 */ async checkPermission(permissionType: PermissionType): Promise { // #ifdef H5 try { if (navigator.permissions && navigator.permissions.query) { const permission = await navigator.permissions.query({ name: permissionType as PermissionName }) return permission.state } else { // 如果不支持 permissions API,尝试获取权限来检测状态 return await this.checkPermissionByRequest(permissionType) } } catch (error) { console.error(`检查${permissionType}权限失败:`, error) return 'unknown' } // #endif // #ifndef H5 return 'granted' // 非H5平台默认有权限 // #endif } /** * 通过请求权限来检测权限状态 * @param permissionType 权限类型 * @returns 权限状态 */ private async checkPermissionByRequest(permissionType: PermissionType): Promise { // #ifdef H5 try { switch (permissionType) { case 'microphone': // 麦克风 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }) stream.getTracks().forEach(track => track.stop()) return 'granted' // 允许 case 'camera': // 摄像头 const videoStream = await navigator.mediaDevices.getUserMedia({ video: true }) videoStream.getTracks().forEach(track => track.stop()) return 'granted' // 允许 default: // 其他 return 'unknown' // 未知 } } catch (error: any) { if (error.name === 'NotAllowedError') { return 'denied' // 拒绝 } else { return 'prompt' // 提示 } } // #endif // #ifndef H5 return 'granted' // #endif } /** * 请求权限 * @param permissionType 权限类型 * @returns 是否成功获取权限 */ async requestPermission(permissionType: PermissionType): Promise { // #ifdef H5 try { switch (permissionType) { case 'microphone': // 麦克风 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }) stream.getTracks().forEach(track => track.stop()) return true case 'camera': // 摄像头 const videoStream = await navigator.mediaDevices.getUserMedia({ video: true }) videoStream.getTracks().forEach(track => track.stop()) return true default: // 其他 return false // 失败 } } catch (error: any) { console.error(`请求${permissionType}权限失败:`, error) return false } // #endif // #ifndef H5 return true // #endif } /** * 监听权限状态变化 * @param permissionType 权限类型 * @param callback 回调函数 */ async watchPermission(permissionType: PermissionType, callback: (state: PermissionState) => void): Promise { // #ifdef H5 try { if (navigator.permissions && navigator.permissions.query) { const permission = await navigator.permissions.query({ name: permissionType as PermissionName }) permission.onchange = () => { callback(permission.state) } } } catch (error) { console.error(`监听${permissionType}权限变化失败:`, error) } // #endif } /** * 显示权限引导弹窗 * @param permissionType 权限类型 */ showPermissionGuide(permissionType: PermissionType): void { const guides = { microphone: { title: t("Mobile.Permission.microphoneTitle"), description: t("Mobile.Permission.microphoneDescription"), steps: [ t("Mobile.Permission.stepClickLock"), t("Mobile.Permission.stepAllowMicrophone"), t("Mobile.Permission.stepRefreshRetryRecord") ] }, camera: { title: t("Mobile.Permission.cameraTitle"), description: t("Mobile.Permission.cameraDescription"), steps: [ t("Mobile.Permission.stepClickLock"), t("Mobile.Permission.stepAllowCamera"), t("Mobile.Permission.stepRefreshRetryPhoto") ] } } const guide = guides[permissionType] if (guide) { uni.showModal({ title: guide.title, content: t("Mobile.Permission.guideContent", { description: guide.description, steps: guide.steps.map((step, index) => `${index + 1}. ${step}`).join('\n'), }), showCancel: true, cancelText: t("Mobile.Common.cancel"), confirmText: t("Mobile.Permission.gotIt"), success: (res) => { if (res.confirm) { console.log('用户确认了权限引导') } } }) } } /** * 检查是否支持权限API * @returns 是否支持 */ isPermissionAPISupported(): boolean { // #ifdef H5 return !!(navigator.permissions && navigator.permissions.query) // #endif // #ifndef H5 return false // #endif } } /** * 麦克风权限专用工具函数 */ export class MicrophonePermissionHelper { private static manager = PermissionManager.getInstance() /** * 检查麦克风权限状态 */ static async check(): Promise { return await this.manager.checkPermission('microphone') } /** * 请求麦克风权限 */ static async request(): Promise { return await this.manager.requestPermission('microphone') } /** * 监听麦克风权限变化 */ static async watch(callback: (state: PermissionState) => void): Promise { return await this.manager.watchPermission('microphone', callback) } /** * 显示麦克风权限引导 */ static showGuide(): void { this.manager.showPermissionGuide('microphone') } /** * 确保麦克风权限可用 * @param showGuide 是否显示权限引导 * @returns 是否成功获取权限 */ static async ensure(showGuide: boolean = true): Promise { // Always attempt to request permission first const success = await this.request() if (success) { return true } // If request fails, check the current state const state = await this.check() // Show guide if denied and showGuide is true if (showGuide && state === 'denied') { this.showGuide() } return false } } // 导出默认实例 export default PermissionManager.getInstance()