// utils/audioManager.js export default { player: null, isApp: uni.getSystemInfoSync().platform === 'ios' || uni.getSystemInfoSync().platform === 'android', initPlayer() { if (!this.player) { this.player = uni.createInnerAudioContext() // this.player.obeyMuteSwitch = false // iOS静音模式设置 } return this.player }, // 从单词数据中提取所有音频信息 extractAudioInfo(wordData) { const audioInfo = { main: null, syllables: [], frequencies: [] } // 主音频 if (wordData.yinpin) { audioInfo.main = { id: `word_${wordData.id}_main`, url: wordData.yinpin, type: 'main', text: wordData.name } } // 音节音频 if (wordData.yinjie && Array.isArray(wordData.yinjie)) { audioInfo.syllables = wordData.yinjie.map((item, index) => ({ id: `word_${wordData.id}_syllable_${index}`, url: item.yinpin, type: 'syllable', text: item.cigen, index })).filter(item => item.url) } // 频度音频 if (wordData.pindu && Array.isArray(wordData.pindu)) { audioInfo.frequencies = wordData.pindu.map((item, index) => ({ id: `word_${wordData.id}_frequency_${index}`, url: item.yinpin, type: 'frequency', text: item.cigen, index })).filter(item => item.url) } return audioInfo }, // 缓存单词的所有音频 async cacheWordAudios(wordData) { try { // 1. 提取音频信息 const { main, syllables, frequencies } = this.extractAudioInfo(wordData) // 2. 准备所有需要缓存的音频 const allAudios = [] if (main) allAudios.push(main) allAudios.push(...syllables) allAudios.push(...frequencies) // App环境才进行真实下载 if (this.isApp) { await this.downloadAndSaveAudios(allAudios) } // 4. 保存音频信息到统一存储 this.saveAudioInfoToStorage(wordData.id, { main, syllables, frequencies }) return true } catch (error) { console.error('音频缓存失败:', error) return false } }, // 保存音频信息到storage(结构化存储) saveAudioInfoToStorage(wordId, audioInfo) { const cacheKey = `word_audio_${wordId}` const cachedData = { timestamp: Date.now(), ...audioInfo } uni.setStorageSync(cacheKey, cachedData) }, // 从storage获取音频信息 getAudioInfoFromStorage(wordId) { const cacheKey = `word_audio_${wordId}` return uni.getStorageSync(cacheKey) || null }, // 下载并保存音频(仅App环境) async downloadAndSaveAudios(audioList) { const downloadPromises = audioList.map(audio => { return new Promise((resolve, reject) => { // 先检查是否已缓存 const cachedPath = uni.getStorageSync(`audio_file_${audio.id}`) if (cachedPath) return resolve() console.log('audio.url',audio.url); uni.downloadFile({ url: audio.url, success: (res) => { if (res.statusCode === 200) { uni.setStorageSync(`audio_file_${audio.id}`, res.tempFilePath) resolve() } else { reject(new Error(`下载失败,状态码: ${res.statusCode}`)) } }, fail: reject }) }).catch(e => { console.warn(`音频 ${audio.id} 预加载失败:`, e) // 即使下载失败也继续其他下载 }) }) await Promise.all(downloadPromises) }, // 缓存单个音频 async cacheSingleAudio(id, url) { return new Promise((resolve, reject) => { uni.downloadFile({ url, success: (res) => { if (res.statusCode === 200) { // 存储音频文件路径 uni.setStorageSync(`audio_file_${id}`, res.tempFilePath) resolve() } else { reject(new Error(`下载失败,状态码: ${res.statusCode}`)) } }, fail: reject }) }) }, // 播放音频(优先本地,失败后回退网络) playAudio(audioInfo) { if (!audioInfo?.url) return const player = this.initPlayer() player.stop() console.log('this.isApp',this.isApp); // 在App环境尝试使用本地缓存 if (this.isApp) { const cachedPath = uni.getStorageSync(`audio_file_${audioInfo.id}`) if (cachedPath) { player.src = cachedPath player.play() return player } } // 非App环境或缓存失败时使用网络 console.warn(`使用网络音频: ${audioInfo.id}`) console.log('player',player); console.log('audioInfo.url',audioInfo.url); player.src = audioInfo.url player.play() // App环境下后台继续尝试缓存 if (this.isApp) { this.downloadAndSaveAudios([audioInfo]).catch(console.error) } // player.onError((err) => { // console.error('播放失败:', err) // uni.showToast({ title: '播放失败', icon: 'none' }) // }) return player }, // 清理指定单词的缓存 clearWordCache(wordId) { // 1. 清理音频信息 uni.removeStorageSync(`word_audio_${wordId}`) // 2. 清理所有相关音频文件 const prefix = `word_${wordId}_` const keys = uni.getStorageInfoSync().keys keys.filter(key => key.startsWith('audio_file_') && key.includes(prefix)) .forEach(key => uni.removeStorageSync(key)) }, // 清理所有缓存 clearAllCache() { // 1. 清理所有音频信息 const keys = uni.getStorageInfoSync().keys keys.filter(key => key.startsWith('word_audio_')) .forEach(key => uni.removeStorageSync(key)) // 2. 清理所有音频文件 keys.filter(key => key.startsWith('audio_file_')) .forEach(key => uni.removeStorageSync(key)) } }