Files
qiming/qiming-mobile/utils/permissionHelper.uts

263 lines
7.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 权限处理工具类
* 用于处理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()