/** * 应用主Ability入口文件 * 功能: * 1. 管理应用生命周期 * 2. 处理窗口创建和尺寸变化 * 3. 响应外部调用请求 * 4. 全局状态管理 */ import UIAbility from '@ohos.app.ability.UIAbility'; import hilog from '@ohos.hilog'; import window from '@ohos.window'; import { AbilityConstant, Want } from '@kit.AbilityKit'; import { BusinessError, emitter } from '@kit.BasicServicesKit'; import { AppUtil, ArrayUtil, GlobalContext, LogUtil, StrUtil } from '@pura/harmony-utils'; import { rpc } from '@kit.IPCKit'; import { Utility } from '../common/util/Utility'; import { WXApi, WXEventHandler } from '../common/util/WXApiWrap'; import { UnifiedPlayerService } from '../common/service/UnifiedPlayerService'; import { WidgetRegistrationFix } from '../common/widget/WidgetRegistrationFix'; import { systemShare } from '@kit.ShareKit'; import { CustomCrashHandler } from '../common/utils/CustomCrashHandler'; import { smartMobilityCommon } from '@kit.CarKit'; import { url } from '@kit.ArkTS'; import { display } from '@kit.ArkUI'; /** * 播放状态广播数据接口 */ interface PlayStateBroadcast { isPlaying: boolean; isPaused: boolean; isLoading: boolean; } interface SongBroadcast { id: string; title: string; artist: string; album: string; coverImagePath: string; duration: number; } interface ProgressBroadcast { currentPosition: number; duration: number; percentage: number; currentTimeText: string; totalTimeText: string; } interface PlaylistBroadcast { hasNext: boolean; hasPrevious: boolean; currentIndex: number; totalCount: number; } interface BroadcastData { playState: PlayStateBroadcast; currentSong: SongBroadcast; progress: ProgressBroadcast; playlist: PlaylistBroadcast; } interface PublishInfo { data: string; } interface EventDataWrapper { data: BroadcastData; } /** * RPC通信返回类型的实现,用于RPC通信数据序列化和反序列化 */ class MyParcelable implements rpc.Parcelable { num: number; str: string; constructor(num: number, str: string) { this.num = num; this.str = str; } marshalling(messageSequence: rpc.MessageSequence): boolean { messageSequence.writeInt(this.num); messageSequence.writeString(this.str); return true; } unmarshalling(messageSequence: rpc.MessageSequence): boolean { this.num = messageSequence.readInt(); this.str = messageSequence.readString(); return true; } } /** * 主Ability类,继承自UIAbility * 负责: * - 应用初始化 * - 窗口管理 * - 事件分发 */ export default class EntryAbility extends UIAbility { // UI上下文对象,用于获取窗口信息 private uiContext?: UIContext; // private awareness: smartMobilityCommon.SmartMobilityAwareness = smartMobilityCommon.getSmartMobilityAwareness(); private awareness: smartMobilityCommon.SmartMobilityAwareness|undefined = canIUse("SystemCapability.SmartOptimizer.SmartMobility")?smartMobilityCommon.getSmartMobilityAwareness():undefined; /** * 窗口尺寸变化回调函数 * @param windowSize 新的窗口尺寸对象 * 功能: * 1. 获取最新的窗口断点尺寸 * 2. 更新AppStorage中的尺寸状态 * 3. 记录尺寸变化日志 */ private onWindowSizeChange: (windowSize: window.Size) => void = async (windowSize: window.Size) => { // 获取宽度断点并更新全局状态 let widthBp = this.uiContext!.getWindowWidthBreakpoint(); AppStorage.setOrCreate('currentWidthBreakpoint', widthBp); // 获取高度断点并更新全局状态 let heightBp = this.uiContext!.getWindowHeightBreakpoint(); AppStorage.setOrCreate('currentHeightBreakpoint', heightBp); // 记录尺寸变化日志 // LogUtil.info('pura onWindowSizeChange currentHeightBreakpoint= '+heightBp); // LogUtil.info( 'pura onWindowSizeChange currentWidthBreakpoint= '+widthBp); AppStorage.setOrCreate('windowWidth', windowSize.width); AppStorage.setOrCreate('windowHeight', windowSize.height); if(windowSize.width > windowSize.height){ AppStorage.setOrCreate('isLandscape', true); }else{ AppStorage.setOrCreate('isLandscape', false); } // LogUtil.info('hicar onWindowSizeChange width= '+windowSize.width); // LogUtil.info( 'hicar onWindowSizeChange height= '+windowSize.height); }; onAvoidAreaChange = (data: window.AvoidAreaOptions) => { if (data.type === window.AvoidAreaType.TYPE_SYSTEM) { let topRectHeight = px2vp(data.area.topRect.height); AppStorage.setOrCreate('topRectHeight', topRectHeight); } else if (data.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { let bottomRectHeight = px2vp(data.area.bottomRect.height); AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight); } } async onCreate(want:Want, launchParam:AbilityConstant.LaunchParam) { AppUtil.init(this.context); AppStorage.setOrCreate('context', this.context); hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onCreate'); // 注册卡片call事件监听器 this.registerWidgetCallListeners(); // 异步初始化统一播放器服务,避免阻塞生命周期 this.initializePlayerServiceAsync(); // 执行卡片注册修复(异步执行,不阻塞启动) this.fixWidgetRegistrationAsync(); // 异步处理Want参数,避免阻塞生命周期 this.handleWantAsync(want); this.handleWeChatCallIfNeed(want) this.getHiCarStatus() } async onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): Promise { hilog.info(0x0000, 'Heanup2', `onNewWant, want=${JSON.stringify(want)}`); super.onNewWant(want, launchParam); // 异步处理Want参数,避免阻塞生命周期 this.handleWantAsync(want); this.handleWeChatCallIfNeed(want) } private handleWeChatCallIfNeed(want: Want) { WXApi.handleWant(want, WXEventHandler) } //处理其他app点击其他应用打开播放器播放视频或者音频 loadDoWant(want: Want){ // console.info('onecold KnockController 碰一碰 want ='+JSON.stringify(want)); let uri = want.uri; if (uri == null || uri == undefined|| StrUtil.isEmpty(uri)) { console.info('uri is invalid'); return; } hilog.info(0x0000, 'Heanup2', `onCreate or onNewWant, uri=${uri}`); this.doSendEmit(uri) } //广播通知打开播放器播放视频或者音频 doSendEmit(uri:string){ setTimeout(async ()=>{ let eventData: emitter.EventData = { data: { message: uri } }; if(Utility.isMeidaByExtension(uri)){ emitter.emit({ eventId: 2 }, eventData); // 发送音频打开广播事件 }else{ emitter.emit({ eventId: 1 }, eventData); // 发送视频打开广播事件 } },300) } // 华为分享拉起接收 处理分享数据 // 1. 改造 handleParam 为异步函数,让其返回 Promise async handleParam(want: Want) { try { // 通过 await 等待异步操作完成 const data = await systemShare.getSharedData(want); const records = data.getRecords(); let uri = want.uri; for (const record of records) { if (record.uri) { uri = record.uri; this.doSendEmit(uri) break; } } } catch (error) { const businessError = error as BusinessError; console.error(`Failed: Code ${businessError.code}, ${businessError.message}`); } } onDestroy() { hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onDestroy'); // 关键修复:在APP销毁时保存播放器状态 try { const unifiedPlayerService = UnifiedPlayerService.getInstance(); if (unifiedPlayerService) { // 确保在APP被杀掉时保存当前播放状态 unifiedPlayerService.release(); hilog.info(0x0000, 'Heanup2', 'UnifiedPlayerService released and state saved on app destroy'); } } catch (error) { hilog.error(0x0000, 'Heanup2', `Failed to release UnifiedPlayerService: ${error}`); } // 注销卡片call事件监听器 this.unregisterWidgetCallListeners(); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); if(this.awareness){ let types: smartMobilityCommon.SmartMobilityType[] = [smartMobilityCommon.SmartMobilityType.CAR_HOP]; // 出行连接状态回调函数 const callBack = (info: smartMobilityCommon.SmartMobilityInfo) => { hilog.info(0x0000, 'Received smart mobility info: ', JSON.stringify(info)); }; // 解注册智慧出行连接状态的监听 示例2 this.awareness.off('smartMobilityStatus', types, callBack); } } onWindowStageCreate(windowStage: window.WindowStage) { // Main window is created, set main page for this ability hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageCreate'); // 使用自定义崩溃处理器替代 SpiderMan.init() // SpiderMan.init(); CustomCrashHandler.init(); AppUtil.init(this.context); //1.获取应用主窗口。 let windowClass: window.Window | null = null; windowStage.getMainWindow((err: BusinessError, data) => { windowClass = data; // LogUtil.info( 'getMainWindow = '); GlobalContext.getContext().setObject('windowClass', data); // 使用GlobalContext替代globalThis let curDisplay = display.getDisplayByIdSync(windowClass.getWindowProperties().displayId); console.info('twocold curDisplay = '+curDisplay.name); if(curDisplay.name =='HiCar'||curDisplay.name =='SuperLauncher'){ AppStorage.setOrCreate('curDisplayIsHiCar', true); }else{ AppStorage.setOrCreate('curDisplayIsHiCar', false); } windowClass.setWindowLayoutFullScreen(true).then(() => { console.info('Succeeded in setting the window layout to full-screen mode.'); }).catch((e: BusinessError) => { console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(e)); }) // let avoidArea = windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM) // let topRectHeight = px2vp(avoidArea.topRect.height); // AppStorage.setOrCreate('topRectHeight', topRectHeight); let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例 let avoidArea = windowClass.getWindowAvoidArea(type); let bottomRectHeight = px2vp(avoidArea.bottomRect.height); // 获取到导航条区域的高度 AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight); type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例 avoidArea = windowClass.getWindowAvoidArea(type); let topRectHeight = px2vp(avoidArea.topRect.height) // 获取状态栏区域高度 AppStorage.setOrCreate('topRectHeight', topRectHeight); LogUtil.info('onecold topRectHeight = '+topRectHeight); windowClass.on('avoidAreaChange', this.onAvoidAreaChange) }) AppStorage.setOrCreate('windowStage',windowStage); hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/SplashIndex', (err, data) => { if (err.code) { hilog.error(0x0000, 'Heanup2', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } //一多断点开发 windowStage.getMainWindow().then((data: window.Window) => { this.uiContext = data.getUIContext(); let widthBp = this.uiContext.getWindowWidthBreakpoint(); let heightBp = this.uiContext.getWindowHeightBreakpoint(); AppStorage.setOrCreate('currentWidthBreakpoint', widthBp); AppStorage.setOrCreate('currentHeightBreakpoint', heightBp); LogUtil.info( 'getMainWindow currentHeightBreakpoint= '+heightBp); LogUtil.info( 'getMainWindow currentWidthBreakpoint= '+widthBp); data.on('windowSizeChange', this.onWindowSizeChange); AppStorage.setOrCreate('windowWidth', data.getWindowProperties().windowRect.width); AppStorage.setOrCreate('windowHeight', data.getWindowProperties().windowRect.height); if(data.getWindowProperties().windowRect.width > data.getWindowProperties().windowRect.height){ AppStorage.setOrCreate('isLandscape', true); }else{ AppStorage.setOrCreate('isLandscape', false); } // LogUtil.info('hicar getMainWindow width= '+data.getWindowProperties().windowRect.width); // LogUtil.info( 'hicar getMainWindow height= '+data.getWindowProperties().windowRect.height); }).catch((err: BusinessError) => { console.error(`Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`); }); hilog.info(0x0000, 'Heanup2', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); }); } onWindowStageDestroy() { // Main window is destroyed, release UI related resources hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onWindowStageDestroy'); } onForeground() { // Ability has brought to foreground hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onForeground start'); // 异步处理前台逻辑,避免阻塞生命周期 setTimeout(() => { this.handleForegroundAsync(); }, 10); hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onForeground end'); } onBackground() { // Ability has back to background hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onBackground start'); // 异步处理后台逻辑,避免阻塞生命周期 setTimeout(() => { this.handleBackgroundAsync(); }, 10); hilog.info(0x0000, 'Heanup2', '%{public}s', 'Ability onBackground end'); } getHiCarStatus(){ if(this.awareness){ // this.awareness = smartMobilityCommon.getSmartMobilityAwareness(); // 业务类型 let types: smartMobilityCommon.SmartMobilityType[] = [smartMobilityCommon.SmartMobilityType.HICAR]; // 获取出行业务连接状态 let info = this.awareness.getSmartMobilityStatus(types[0]); hilog.info(0x0000, 'getHiCarStatus info: ', JSON.stringify(info)); if(info&&info.status==1){ AppStorage.setOrCreate('isHiCarStatus', true); }else{ AppStorage.setOrCreate('isHiCarStatus', false); } // 出行连接状态回调函数 const callBack = (info: smartMobilityCommon.SmartMobilityInfo) => { hilog.info(0x0000, 'getHiCarStatus Received smart mobility info: ', JSON.stringify(info)); if(info&&info.status==1){ AppStorage.setOrCreate('isHiCarStatus', true); }else{ AppStorage.setOrCreate('isHiCarStatus', false); } this.sendChangeEvent() }; // 注册智慧出行连接状态的监听 this.awareness.on('smartMobilityStatus', types, callBack); }else{ AppStorage.setOrCreate('isHiCarStatus', false); } } //发送广播通知更新UI sendChangeEvent() { const eventData: emitter.EventData = {}; emitter.emit({ eventId: 333 }, eventData); // 发送广播通知更新doSwipBack } /** * 注册卡片call事件监听器(增强版本:服务就绪检查) */ private registerWidgetCallListeners(): void { try { // 监听播放/暂停事件 this.callee.on('playPause', (data: rpc.MessageSequence) => { try { const params: Record = JSON.parse(data.readString()) as Record; hilog.info(0x0000, 'Heanup2', `🎵 Widget call: playPause received`); // 异步发送播放/暂停事件到主应用(包含服务就绪检查) this.sendWidgetControlEvent('PLAY_PAUSE', params).catch((error: Error) => { hilog.error(0x0000, 'Heanup2', `❌ playPause async error: ${error}`); }); return new MyParcelable(1, 'playPause_success'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ playPause handler error: ${error}`); return new MyParcelable(-1, 'playPause_error'); } }); // 监听下一首事件 this.callee.on('nextSong', (data: rpc.MessageSequence) => { try { hilog.info(0x0000, 'Heanup2', `🎵 Widget call: nextSong received`); const params: Record = JSON.parse(data.readString()) as Record; hilog.info(0x0000, 'Heanup2', `Widget nextSong params: ${JSON.stringify(params)}`); // 异步发送下一首事件到主应用(包含服务就绪检查) this.sendWidgetControlEvent('NEXT_SONG', params).catch((error: Error) => { hilog.error(0x0000, 'Heanup2', `❌ nextSong async error: ${error}`); }); return new MyParcelable(2, 'nextSong_success'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ nextSong handler error: ${error}`); return new MyParcelable(-2, 'nextSong_error'); } }); // 监听上一首事件 this.callee.on('prevSong', (data: rpc.MessageSequence) => { try { hilog.info(0x0000, 'Heanup2', `🎵 Widget call: prevSong received`); const params: Record = JSON.parse(data.readString()) as Record; hilog.info(0x0000, 'Heanup2', `Widget prevSong params: ${JSON.stringify(params)}`); // 异步发送上一首事件到主应用(包含服务就绪检查) this.sendWidgetControlEvent('PREV_SONG', params).catch((error: Error) => { hilog.error(0x0000, 'Heanup2', `❌ prevSong async error: ${error}`); }); return new MyParcelable(3, 'prevSong_success'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ prevSong handler error: ${error}`); return new MyParcelable(-3, 'prevSong_error'); } }); // 监听打开应用事件 this.callee.on('openApp', (data: rpc.MessageSequence) => { try { hilog.info(0x0000, 'Heanup2', `🎵 Widget call: openApp received`); const params: Record = JSON.parse(data.readString()) as Record; hilog.info(0x0000, 'Heanup2', `Widget openApp params: ${JSON.stringify(params)}`); // 异步发送打开应用事件到主应用 this.sendWidgetControlEvent('OPEN_APP', params).catch((error: Error) => { hilog.error(0x0000, 'Heanup2', `❌ openApp async error: ${error}`); }); return new MyParcelable(4, 'openApp_success'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ openApp handler error: ${error}`); return new MyParcelable(-4, 'openApp_error'); } }); hilog.info(0x0000, 'Heanup2', '🎵 Widget call listeners registered successfully (Enhanced)'); } catch (err) { hilog.error(0x0000, 'Heanup2', `❌ Failed to register widget call listeners: ${JSON.stringify(err as BusinessError)}`); } } /** * 注销卡片call事件监听器 */ private unregisterWidgetCallListeners(): void { try { this.callee.off('playPause'); this.callee.off('nextSong'); this.callee.off('prevSong'); // this.callee.off('openApp'); // this.callee.off('playByAction'); // this.callee.off('collectAction'); // this.callee.off('requestUpdatePlayCard'); hilog.info(0x0000, 'Heanup2', 'Widget call listeners unregistered successfully'); } catch (err) { hilog.error(0x0000, 'Heanup2', `Failed to unregister widget call listeners: ${JSON.stringify(err as BusinessError)}`); } } /** * 发送卡片控制事件到主应用(增强版本,确保服务已初始化) */ private async sendWidgetControlEvent(command: string, params: Record): Promise { try { hilog.info(0x0000, 'Heanup2', `🎵 收到桌面卡片指令: ${command}`); // 获取UnifiedPlayerService实例 const unifiedService = UnifiedPlayerService.getInstance(); // 确保服务已经初始化 if (!unifiedService) { hilog.error(0x0000, 'Heanup2', '❌ UnifiedPlayerService 未初始化'); return; } // 获取详细的服务就绪状态信息 const readinessInfo = unifiedService.getServiceReadinessInfo(); hilog.info(0x0000, 'Heanup2', `🔍 Service readiness: ${JSON.stringify(readinessInfo.details)}`); // 智能等待服务完全就绪(多级检查) hilog.info(0x0000, 'Heanup2', '🔄 检查服务就绪状态...'); let ready = await this.waitForServiceReady(unifiedService); if (ready) { hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService 已就绪'); } else { hilog.warn(0x0000, 'Heanup2', '⚠️ UnifiedPlayerService 未完全就绪,尝试执行基础操作'); // 检查是否至少可以进行基础操作 if (!unifiedService.isAllServicesReady()) { const finalReadinessInfo = unifiedService.getServiceReadinessInfo(); hilog.error(0x0000, 'Heanup2', `❌ 基础服务未就绪,无法执行操作: ${JSON.stringify(finalReadinessInfo.details)}`); return; } } // 检查初始化状态 const currentState = unifiedService.getCurrentState(); const playlist = unifiedService.getPlaylist(); hilog.info(0x0000, 'Heanup2', `🎵 Widget command - Service state: isPlaying=${currentState.isPlaying}, currentIndex=${currentState.currentIndex}, playlistSize=${playlist.length}`); // 对于播放控制操作,检查是否有可播放内容 if ((command === 'PLAY_PAUSE' || command === 'NEXT_SONG' || command === 'PREV_SONG') && playlist.length === 0) { hilog.warn(0x0000, 'Heanup2', '⚠️ 播放列表为空,尝试强制数据恢复'); // 强制触发数据恢复 await this.forceDataRestoration(unifiedService); // 重新检查播放列表 const updatedPlaylist = unifiedService.getPlaylist(); if (updatedPlaylist.length === 0) { hilog.warn(0x0000, 'Heanup2', '⚠️ 强制数据恢复后播放列表仍为空,无法执行播放控制操作'); return; } hilog.info(0x0000, 'Heanup2', `✅ 强制数据恢复完成,播放列表大小: ${updatedPlaylist.length}`); } // 根据命令执行相应的播放控制 switch (command) { case 'PLAY_PAUSE': // 获取卡片传递的当前显示状态 const widgetIsPlaying = params['widgetIsPlaying'] as boolean; const hasWidgetState = widgetIsPlaying !== undefined; // 获取服务内部状态 const latestState = unifiedService.getCurrentState(); hilog.info(0x0000, 'Heanup2', `🎵 卡片显示状态: isPlaying=${widgetIsPlaying} (有效: ${hasWidgetState})`); hilog.info(0x0000, 'Heanup2', `🎵 服务内部状态: isPlaying=${latestState.isPlaying}`); if (hasWidgetState) { // 新逻辑:根据卡片显示的状态来决定操作 // - 如果卡片显示播放按钮(widgetIsPlaying=false),则执行播放操作 // - 如果卡片显示暂停按钮(widgetIsPlaying=true),则执行暂停操作 if (widgetIsPlaying) { // 卡片显示暂停按钮,用户点击要暂停 await unifiedService.pause(); hilog.info(0x0000, 'Heanup2', '✅ 卡片操作:暂停播放'); } else { // 卡片显示播放按钮,用户点击要播放 hilog.info(0x0000, 'Heanup2', '🔄 卡片操作:开始播放'); await unifiedService.startPlayOrResumePlay(); hilog.info(0x0000, 'Heanup2', '✅ 卡片操作:开始播放'); } } else { // 向后兼容:使用原来的逻辑(根据服务内部状态) hilog.info(0x0000, 'Heanup2', '⚠️ 使用向后兼容模式(基于服务状态)'); if (latestState.isPlaying) { await unifiedService.pause(); hilog.info(0x0000, 'Heanup2', '✅ 兼容模式:暂停播放'); } else { hilog.info(0x0000, 'Heanup2', '🔄 兼容模式:开始播放'); await unifiedService.startPlayOrResumePlay(); hilog.info(0x0000, 'Heanup2', '✅ 兼容模式:开始播放'); } } break; case 'NEXT_SONG': await unifiedService.playNext(); hilog.info(0x0000, 'Heanup2', '✅ Widget command: Next song'); break; case 'PREV_SONG': await unifiedService.playPrevious(); hilog.info(0x0000, 'Heanup2', '✅ Widget command: Previous song'); break; case 'OPEN_APP': hilog.info(0x0000, 'Heanup2', '✅ Widget command: Open app (handled by UI)'); break; default: hilog.warn(0x0000, 'Heanup2', `❓ Unknown widget command: ${command}`); break; } // 操作完成后,广播最新状态给主应用UI和桌面卡片 setTimeout(() => { this.broadcastCurrentPlayerState(); hilog.info(0x0000, 'Heanup2', '📡 桌面卡片操作后广播状态更新'); // 同时触发UnifiedPlayerService的状态广播,确保所有监听器都能收到更新 try { unifiedService.broadcastCurrentState(); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 触发服务状态广播失败: ${error}`); } }, 100); // 短延迟,确保操作完全完成 hilog.info(0x0000, 'Heanup2', `✅ Widget control command processed: ${command}`); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ Failed to process widget control command: ${error}`); } } /** * 强制数据恢复(用于桌面卡片冷启动场景) */ private async forceDataRestoration(unifiedService: UnifiedPlayerService): Promise { try { hilog.info(0x0000, 'Heanup2', '🔄 开始强制数据恢复...'); // 检查是否已经有数据恢复完成 if (unifiedService.isDataRestorationCompleted()) { hilog.info(0x0000, 'Heanup2', '✅ 数据已恢复,无需强制恢复'); return; } // 调用UnifiedPlayerService的强制数据恢复方法 const restored = await unifiedService.forceDataRestoration(); if (restored) { hilog.info(0x0000, 'Heanup2', '✅ 强制数据恢复成功'); } else { hilog.warn(0x0000, 'Heanup2', '⚠️ 强制数据恢复失败,尝试等待'); // 如果强制恢复失败,再等待一段时间 await unifiedService.waitForDataRestoration(2000); } // 额外等待一小段时间,确保播放列表数据完全加载 await new Promise(resolve => setTimeout(resolve, 300)); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 强制数据恢复失败: ${error}`); } } /** * 智能等待服务就绪(增强版本) */ private async waitForServiceReady(unifiedService: UnifiedPlayerService): Promise { try { hilog.info(0x0000, 'Heanup2', '🔄 开始等待UnifiedPlayerService完全就绪'); // 检查是否是刚启动的应用(数据还没恢复) const currentPlaylist = unifiedService.getPlaylist(); const isJustStarted = currentPlaylist.length === 0; const isDataRestored = unifiedService.isDataRestorationCompleted(); if (isJustStarted || !isDataRestored) { hilog.info(0x0000, 'Heanup2', `🔄 检测到冷启动状态 - 播放列表为空: ${isJustStarted}, 数据未恢复: ${!isDataRestored}`); // 对于冷启动,给予更长的等待时间,并强制检查数据恢复 const isReady = await unifiedService.waitForAllServicesReady(10000, true); if (isReady) { hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService完全就绪(冷启动)'); return true; } // 如果仍未就绪,尝试强制触发数据恢复 hilog.warn(0x0000, 'Heanup2', '⚠️ 冷启动等待超时,尝试强制数据恢复'); await this.forceDataRestoration(unifiedService); // 再次检查服务状态 const retryReady = await unifiedService.waitForAllServicesReady(3000, false); if (retryReady) { hilog.info(0x0000, 'Heanup2', '✅ 强制恢复后服务就绪'); return true; } } else { // 对于已经有数据的情况,使用正常的等待时间 const isReady = await unifiedService.waitForAllServicesReady(5000, true); if (isReady) { hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService完全就绪'); return true; } } // 如果主要服务就绪但数据未恢复,再做一次宽松检查 hilog.info(0x0000, 'Heanup2', '⚠️ 主要检查超时,进行备用检查'); const basicReady = await unifiedService.waitForAllServicesReady(2000, false); if (basicReady) { // 检查是否至少有播放数据 const currentState = unifiedService.getCurrentState(); const playlist = unifiedService.getPlaylist(); if (playlist.length > 0 || currentState.currentIndex >= 0) { hilog.info(0x0000, 'Heanup2', `✅ 基础服务就绪,播放列表: ${playlist.length} 首歌曲`); return true; } } hilog.warn(0x0000, 'Heanup2', '⚠️ Service readiness check timeout, proceeding with limited functionality'); return false; } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ Error waiting for service ready: ${error}`); return false; } } /** * 异步初始化播放器服务,避免阻塞生命周期 */ private initializePlayerServiceAsync(): void { // 使用 setTimeout 将初始化操作移到下一个事件循环 setTimeout(async () => { try { hilog.info(0x0000, 'Heanup2', '🔄 开始异步初始化 UnifiedPlayerService'); await UnifiedPlayerService.getInstance().initialize(this.context); hilog.info(0x0000, 'Heanup2', '✅ UnifiedPlayerService 异步初始化成功'); // 对于冷启动场景,立即尝试数据恢复 const unifiedService = UnifiedPlayerService.getInstance(); if (!unifiedService.isDataRestorationCompleted()) { hilog.info(0x0000, 'Heanup2', '🔄 冷启动检测到数据未恢复,开始预恢复'); await unifiedService.forceDataRestoration(); } // 延迟广播当前状态,确保卡片能接收到初始状态 setTimeout(() => { this.broadcastCurrentPlayerState(); }, 500); // 缩短延迟,让卡片更快收到状态 } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ UnifiedPlayerService 异步初始化失败: ${error}`); } }, 50); // 缩短延迟,让初始化更快开始 } /** * 异步处理前台逻辑 */ private handleForegroundAsync(): void { try { hilog.info(0x0000, 'Heanup2', '🔄 处理前台逻辑'); // 确保播放器服务可用 const playerService = UnifiedPlayerService.getInstance(); if (playerService) { // 广播当前状态给卡片 this.broadcastCurrentPlayerState(); } hilog.info(0x0000, 'Heanup2', '✅ 前台逻辑处理完成'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 前台逻辑处理失败: ${error}`); } } /** * 异步处理后台逻辑 */ private handleBackgroundAsync(): void { try { hilog.info(0x0000, 'Heanup2', '🔄 处理后台逻辑'); // 后台时可以执行一些清理或保存操作 // 但要确保不会阻塞生命周期 hilog.info(0x0000, 'Heanup2', '✅ 后台逻辑处理完成'); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 后台逻辑处理失败: ${error}`); } } /** * 异步处理Want参数,避免阻塞生命周期 */ private handleWantAsync(want: Want): void { setTimeout(async () => { try { this.loadDoWant(want); await this.handleParam(want); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 处理Want参数失败: ${error}`); } }, 200); } /** * 异步执行卡片注册修复 */ private async fixWidgetRegistrationAsync(): Promise { // 延迟3秒执行,确保应用完全启动 setTimeout(async () => { try { const widgetFix = WidgetRegistrationFix.getInstance(); await widgetFix.fixWidgetRegistration(this.context); } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ 卡片注册修复失败: ${error}`); } }, 3000); } /** * 广播当前播放器状态给卡片 */ private broadcastCurrentPlayerState(): void { try { const unifiedService = UnifiedPlayerService.getInstance(); const currentState = unifiedService.getCurrentState(); const currentSong = unifiedService.getCurrentSong(); const playlist = unifiedService.getPlaylist(); const currentIndex = unifiedService.getCurrentIndex(); if (currentSong) { // 构建播放器状态广播数据 const broadcastData: BroadcastData = { playState: { isPlaying: currentState.isPlaying || false, isPaused: currentState.isPaused || true, isLoading: currentState.isLoading || false } as PlayStateBroadcast, currentSong: { id: currentSong.id || '', title: currentSong.name || '暂无播放', artist: currentSong.artist || '未知艺术家', album: currentSong.album || '未知专辑', coverImagePath: currentSong.pixelMapPath || '', duration: currentSong.duration ? Number(currentSong.duration) : 0 } as SongBroadcast, progress: { currentPosition: currentState.currentPosition || 0, duration: currentState.duration || 0, percentage: this.calculatePercentage(currentState.currentPosition || 0, currentState.duration || 0), currentTimeText: this.formatTime(Math.floor((currentState.currentPosition || 0) / 1000)), totalTimeText: this.formatTime(Math.floor((currentState.duration || 0) / 1000)) } as ProgressBroadcast, playlist: { hasNext: currentState.hasNext || false, hasPrevious: currentState.hasPrevious || false, currentIndex: currentIndex, totalCount: playlist.length } as PlaylistBroadcast }; // 发送状态变化事件 const publishInfo: PublishInfo = { data: JSON.stringify(broadcastData) }; // 使用emitter发送事件 const eventData: EventDataWrapper = { data: broadcastData }; emitter.emit({ eventId: 1001 }, eventData); // 使用特定的事件ID hilog.info(0x0000, 'Heanup2', `📡 Broadcasted current player state: ${currentSong.name}, isPlaying=${currentState.isPlaying}`); } else { hilog.info(0x0000, 'Heanup2', '📡 No current song to broadcast'); } } catch (error) { hilog.error(0x0000, 'Heanup2', `❌ Failed to broadcast current player state: ${error}`); } } /** * 计算播放进度百分比 */ private calculatePercentage(current: number, total: number): number { if (total <= 0) return 0; return Math.min(100, Math.max(0, (current / total) * 100)); } /** * 格式化时间显示 */ private formatTime(seconds: number): string { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } }