1import MusicQueue from '@/core/musicQueue'; 2import MusicSheet from '@/core/musicSheet'; 3import {check, PERMISSIONS, request} from 'react-native-permissions'; 4import TrackPlayer, {Capability} from 'react-native-track-player'; 5import 'react-native-get-random-values'; 6import Config from '@/core/config'; 7import RNBootSplash from 'react-native-bootsplash'; 8import pathConst from '@/constants/pathConst'; 9import {checkAndCreateDir} from '@/utils/fileUtils'; 10import {errorLog, trace} from '@/utils/log'; 11import MediaMeta from '@/core/mediaMeta'; 12import Cache from '@/core/cache'; 13import PluginManager from '@/core/pluginManager'; 14import Network from '@/core/network'; 15import {ImgAsset} from '@/constants/assetsConst'; 16import LocalMusicSheet from '@/core/localMusicSheet'; 17import {Linking} from 'react-native'; 18import Theme from '@/core/theme'; 19import LyricManager from '@/core/lyricManager'; 20import {getStorage, setStorage} from '@/utils/storage'; 21import Toast from '@/utils/toast'; 22import {localPluginHash, supportLocalMediaType} from '@/constants/commonConst'; 23 24/** app加载前执行 25 * 1. 检查权限 26 * 2. 数据初始化 27 * 3. 28 */ 29async function _bootstrap() { 30 // 1. 检查权限 31 const [readStoragePermission, writeStoragePermission] = await Promise.all([ 32 check(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE), 33 check(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE), 34 ]); 35 if ( 36 !( 37 readStoragePermission === 'granted' && 38 writeStoragePermission === 'granted' 39 ) 40 ) { 41 await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); 42 await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); 43 } 44 45 // 2. 数据初始化 46 /** 初始化路径 */ 47 await setupFolder(); 48 trace('文件夹初始化完成'); 49 // 加载配置 50 await Promise.all([ 51 Config.setup(), 52 MediaMeta.setup(), 53 MusicSheet.setup(), 54 Network.setup(), 55 ]); 56 trace('配置初始化完成'); 57 // 加载插件 58 try { 59 await TrackPlayer.setupPlayer({ 60 maxCacheSize: 61 Config.get('setting.basic.maxCacheSize') ?? 1024 * 1024 * 512, 62 }); 63 } catch (e: any) { 64 if ( 65 e?.message !== 66 'The player has already been initialized via setupPlayer.' 67 ) { 68 throw e; 69 } 70 } 71 await TrackPlayer.updateOptions({ 72 icon: ImgAsset.logoTransparent, 73 alwaysPauseOnInterruption: true, 74 progressUpdateEventInterval: 1, 75 capabilities: [ 76 Capability.Play, 77 Capability.Pause, 78 Capability.SkipToNext, 79 Capability.SkipToPrevious, 80 ], 81 compactCapabilities: [ 82 Capability.Play, 83 Capability.Pause, 84 Capability.SkipToNext, 85 Capability.SkipToPrevious, 86 ], 87 notificationCapabilities: [ 88 Capability.Play, 89 Capability.Pause, 90 Capability.SkipToNext, 91 Capability.SkipToPrevious, 92 ], 93 }); 94 trace('播放器初始化完成'); 95 await Cache.setup(); 96 trace('缓存初始化完成'); 97 await PluginManager.setup(); 98 trace('插件初始化完成'); 99 await MusicQueue.setup(); 100 trace('播放列表初始化完成'); 101 await LocalMusicSheet.setup(); 102 trace('本地音乐初始化完成'); 103 Theme.setup(); 104 trace('主题初始化完成'); 105 await LyricManager.setup(); 106 107 extraMakeup(); 108 ErrorUtils.setGlobalHandler(error => { 109 errorLog('未捕获的错误', error); 110 }); 111} 112 113/** 初始化 */ 114async function setupFolder() { 115 await Promise.all([ 116 checkAndCreateDir(pathConst.dataPath), 117 checkAndCreateDir(pathConst.logPath), 118 checkAndCreateDir(pathConst.cachePath), 119 checkAndCreateDir(pathConst.pluginPath), 120 checkAndCreateDir(pathConst.lrcCachePath), 121 checkAndCreateDir(pathConst.downloadPath).then(() => { 122 checkAndCreateDir(pathConst.downloadMusicPath); 123 }), 124 ]); 125} 126 127export default async function () { 128 try { 129 await _bootstrap(); 130 } catch (e) { 131 errorLog('初始化出错', e); 132 } 133 // 隐藏开屏动画 134 console.log('HIDE'); 135 RNBootSplash.hide({fade: true}); 136} 137 138/** 不需要阻塞的 */ 139async function extraMakeup() { 140 // 自动更新 141 try { 142 if (Config.get('setting.basic.autoUpdatePlugin')) { 143 const lastUpdated = 144 (await getStorage('pluginLastupdatedTime')) || 0; 145 const now = Date.now(); 146 if (Math.abs(now - lastUpdated) > 86400000) { 147 setStorage('pluginLastupdatedTime', now); 148 const plugins = PluginManager.getValidPlugins(); 149 for (let i = 0; i < plugins.length; ++i) { 150 const srcUrl = plugins[i].instance.srcUrl; 151 if (srcUrl) { 152 await PluginManager.installPluginFromUrl(srcUrl); 153 } 154 } 155 } 156 } 157 } catch {} 158 159 async function handleLinkingUrl(url: string) { 160 // 插件 161 try { 162 if (url.endsWith('.js')) { 163 PluginManager.installPlugin(url) 164 .then(res => { 165 Toast.success(`插件「${res.name}」安装成功~`); 166 }) 167 .catch(e => { 168 console.log(e); 169 Toast.warn(e?.message ?? '无法识别此插件'); 170 }); 171 } else if (supportLocalMediaType.some(it => url.endsWith(it))) { 172 // 本地播放 173 const musicItem = await PluginManager.getByHash( 174 localPluginHash, 175 )?.instance?.importMusicItem?.(url); 176 console.log(musicItem); 177 if (musicItem) { 178 MusicQueue.play(musicItem); 179 } 180 } 181 } catch {} 182 } 183 184 // 开启监听 185 Linking.addEventListener('url', data => { 186 if (data.url) { 187 handleLinkingUrl(data.url); 188 } 189 }); 190 const initUrl = await Linking.getInitialURL(); 191 if (initUrl) { 192 handleLinkingUrl(initUrl); 193 } 194 195 if (Config.get('setting.basic.autoPlayWhenAppStart')) { 196 MusicQueue.play(); 197 } 198} 199