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