263 lines
7.1 KiB
Plaintext
263 lines
7.1 KiB
Plaintext
/**
|
||
* 权限处理工具类
|
||
* 用于处理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<PermissionState> {
|
||
// #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<PermissionState> {
|
||
// #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<boolean> {
|
||
// #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<void> {
|
||
// #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<PermissionState> {
|
||
return await this.manager.checkPermission('microphone')
|
||
}
|
||
|
||
/**
|
||
* 请求麦克风权限
|
||
*/
|
||
static async request(): Promise<boolean> {
|
||
return await this.manager.requestPermission('microphone')
|
||
}
|
||
|
||
/**
|
||
* 监听麦克风权限变化
|
||
*/
|
||
static async watch(callback: (state: PermissionState) => void): Promise<void> {
|
||
return await this.manager.watchPermission('microphone', callback)
|
||
}
|
||
|
||
/**
|
||
* 显示麦克风权限引导
|
||
*/
|
||
static showGuide(): void {
|
||
this.manager.showPermissionGuide('microphone')
|
||
}
|
||
|
||
/**
|
||
* 确保麦克风权限可用
|
||
* @param showGuide 是否显示权限引导
|
||
* @returns 是否成功获取权限
|
||
*/
|
||
static async ensure(showGuide: boolean = true): Promise<boolean> {
|
||
// 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()
|