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, StatusBar} 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 StatusBar.setBackgroundColor('transparent'); 108 StatusBar.setTranslucent(true); 109 110 extraMakeup(); 111 ErrorUtils.setGlobalHandler(error => { 112 errorLog('未捕获的错误', error); 113 }); 114} 115 116/** 初始化 */ 117async function setupFolder() { 118 await Promise.all([ 119 checkAndCreateDir(pathConst.dataPath), 120 checkAndCreateDir(pathConst.logPath), 121 checkAndCreateDir(pathConst.cachePath), 122 checkAndCreateDir(pathConst.pluginPath), 123 checkAndCreateDir(pathConst.lrcCachePath), 124 checkAndCreateDir(pathConst.downloadPath).then(() => { 125 checkAndCreateDir(pathConst.downloadMusicPath); 126 }), 127 ]); 128} 129 130export default async function () { 131 try { 132 await _bootstrap(); 133 } catch (e) { 134 errorLog('初始化出错', e); 135 } 136 // 隐藏开屏动画 137 console.log('HIDE'); 138 RNBootSplash.hide({fade: true}); 139} 140 141/** 不需要阻塞的 */ 142async function extraMakeup() { 143 // 自动更新 144 try { 145 if (Config.get('setting.basic.autoUpdatePlugin')) { 146 const lastUpdated = 147 (await getStorage('pluginLastupdatedTime')) || 0; 148 const now = Date.now(); 149 if (Math.abs(now - lastUpdated) > 86400000) { 150 setStorage('pluginLastupdatedTime', now); 151 const plugins = PluginManager.getValidPlugins(); 152 for (let i = 0; i < plugins.length; ++i) { 153 const srcUrl = plugins[i].instance.srcUrl; 154 if (srcUrl) { 155 await PluginManager.installPluginFromUrl(srcUrl); 156 } 157 } 158 } 159 } 160 } catch {} 161 162 async function handleLinkingUrl(url: string) { 163 // 插件 164 try { 165 if (url.endsWith('.js')) { 166 PluginManager.installPlugin(url) 167 .then(res => { 168 Toast.success(`插件「${res.name}」安装成功~`); 169 }) 170 .catch(e => { 171 console.log(e); 172 Toast.warn(e?.message ?? '无法识别此插件'); 173 }); 174 } else if (supportLocalMediaType.some(it => url.endsWith(it))) { 175 // 本地播放 176 const musicItem = await PluginManager.getByHash( 177 localPluginHash, 178 )?.instance?.importMusicItem?.(url); 179 console.log(musicItem); 180 if (musicItem) { 181 MusicQueue.play(musicItem); 182 } 183 } 184 } catch {} 185 } 186 187 // 开启监听 188 Linking.addEventListener('url', data => { 189 if (data.url) { 190 handleLinkingUrl(data.url); 191 } 192 }); 193 const initUrl = await Linking.getInitialURL(); 194 if (initUrl) { 195 handleLinkingUrl(initUrl); 196 } 197 198 if (Config.get('setting.basic.autoPlayWhenAppStart')) { 199 MusicQueue.play(); 200 } 201} 202