
本文深入解析 ImportantDays 项目中的应用入口EntryAbility包括 UIAbility 的生命周期回调、初始化流程Preferences → Manager → 通知检查、窗口管理、前台提醒检查机制以及应用配置的关联关系。一、UIAbility 概述UIAbility是 HarmonyOS 应用的基本组成单元负责承载 UI 界面和处理生命周期。每个应用至少有一个 UIAbility 作为入口。应用启动 ↓ EntryAbility.onCreate() ↓ EntryAbility.onWindowStageCreate() ↓ 加载 MainEntry 页面 ↓ 用户交互 ↓ EntryAbility.onForeground() / onBackground() ↓ EntryAbility.onWindowStageDestroy() ↓ EntryAbility.onDestroy()二、EntryAbility 完整代码import{UIAbility,AbilityConstant,Want}fromkit.AbilityKit;import{window}fromkit.ArkUI;import{PreferenceUtil}from../utils/PreferenceUtil;import{NotificationUtil}from../utils/NotificationUtil;import{ImportantDayManager}from../viewmodel/ImportantDayManager;exportdefaultclassEntryAbilityextendsUIAbility{asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promisevoid{console.info(EntryAbility onCreate);PreferenceUtil.init(this.context);ImportantDayManager.getInstance().init();consthasPermissionawaitNotificationUtil.checkPermission();if(hasPermission){awaitImportantDayManager.getInstance().checkAndSendReminders();}}onNewWant(want:Want,launchParam:AbilityConstant.LaunchParam):void{console.info(EntryAbility onNewWant);}onDestroy():void{console.info(EntryAbility onDestroy);}onWindowStageCreate(windowStage:window.WindowStage):void{console.info(EntryAbility onWindowStageCreate);windowStage.getMainWindow((err,win){if(err.code){console.error(Failed to get main window:,err);return;}// 沉浸式设置已注释});windowStage.loadContent(pages/MainEntry,(err){if(err.code){console.error(Failed to load content:,err);return;}console.info(Loaded MainEntry successfully);});}onWindowStageDestroy():void{console.info(EntryAbility onWindowStageDestroy);}onForeground():void{console.info(EntryAbility onForeground);ImportantDayManager.getInstance().checkAndSendReminders();}onBackground():void{console.info(EntryAbility onBackground);}}三、生命周期回调详解onCreateasynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promisevoid{console.info(EntryAbility onCreate);PreferenceUtil.init(this.context);ImportantDayManager.getInstance().init();consthasPermissionawaitNotificationUtil.checkPermission();if(hasPermission){awaitImportantDayManager.getInstance().checkAndSendReminders();}}调用时机Ability 实例首次创建时应用冷启动。执行流程1. PreferenceUtil.init(this.context) ↓ 初始化 Preferences 存储 2. ImportantDayManager.getInstance().init() ↓ 加载持久化数据 ↓ 构建 dayMap ↓ 检查并发送提醒 3. NotificationUtil.checkPermission() ↓ 检查通知权限 4. 如果有权限 → checkAndSendReminders() ↓ 发送到期提醒初始化顺序的重要性PreferenceUtil.init() ← 必须最先执行 ↓ ImportantDayManager.init() 依赖 PreferenceUtil ↓ Manager.init() 调用 PreferenceUtil.loadImportantDays()如果顺序反了PreferenceUtil.store为 null数据加载失败。onNewWantonNewWant(want:Want,launchParam:AbilityConstant.LaunchParam):void{console.info(EntryAbility onNewWant);}调用时机Ability 已存在实例通过 WantAgent 或其他方式再次启动时。场景用户点击通知打开应用但应用已在后台运行。当前实现仅打印日志未来可在此解析 Want 携带的参数实现精确跳转。onDestroyonDestroy():void{console.info(EntryAbility onDestroy);}调用时机Ability 实例被销毁时。当前实现仅打印日志数据已在每次操作时持久化无需额外处理。onWindowStageCreateonWindowStageCreate(windowStage:window.WindowStage):void{console.info(EntryAbility onWindowStageCreate);windowStage.getMainWindow((err,win){if(err.code){console.error(Failed to get main window:,err);return;}// win.setWindowLayoutFullScreen(true);// win.setWindowSystemBarProperties({ ... });});windowStage.loadContent(pages/MainEntry,(err){if(err.code){console.error(Failed to load content:,err);return;}console.info(Loaded MainEntry successfully);});}调用时机窗口舞台创建时onCreate 之后。执行流程获取主窗口windowStage.getMainWindow()当前沉浸式设置已注释预留功能加载主页面windowStage.loadContent(pages/MainEntry)加载MainEntry作为入口页面MainEntry使用 Tabs 组织三个 Tab 页面onWindowStageDestroyonWindowStageDestroy():void{console.info(EntryAbility onWindowStageDestroy);}调用时机窗口舞台销毁时应用被关闭。onForegroundonForeground():void{console.info(EntryAbility onForeground);ImportantDayManager.getInstance().checkAndSendReminders();}调用时机应用从后台回到前台时。核心功能每次回到前台都检查提醒确保用户不会错过在后台期间到期的提醒。onBackgroundonBackground():void{console.info(EntryAbility onBackground);}调用时机应用从前台进入后台时。当前实现仅打印日志。四、完整生命周期时序冷启动应用未运行 ↓ onCreate() ↓ 初始化数据 onWindowStageCreate() ↓ 加载页面 onForeground() ↓ 检查提醒 用户交互热启动从后台恢复应用在后台 ↓ 用户点击应用图标 / 通知 ↓ onForeground() ↓ 检查提醒 用户交互通知点击启动通知显示 ↓ 用户点击通知 ↓ WantAgent 触发 ↓ 应用已在运行 ├── 是 → onNewWant() → onForeground() └── 否 → onCreate() → onWindowStageCreate() → onForeground()退出应用用户退出 ↓ onBackground() ↓ onWindowStageDestroy() ↓ onDestroy()五、初始化流程详解第一步Preferences 初始化PreferenceUtil.init(this.context);this.contextAbility 的上下文用于确定存储路径PreferenceUtil.init使用getPreferencesSync同步创建 Preferences 实例必须在ImportantDayManager.init()之前执行第二步数据管理器初始化ImportantDayManager.getInstance().init();init()内部执行init():void{if(this.initialized)return;this.allDaysPreferenceUtil.loadImportantDays();// 依赖 Preferencesthis.rebuildDayMap();this.initializedtrue;this.checkAndSendReminders();// 初始化时也检查提醒}注意init()内部已经调用了checkAndSendReminders()但此时可能没有通知权限。第三步权限检查与提醒consthasPermissionawaitNotificationUtil.checkPermission();if(hasPermission){awaitImportantDayManager.getInstance().checkAndSendReminders();}由于init()中的checkAndSendReminders()可能在没有权限时执行这里再次检查权限并调用确保有权限时一定发送提醒。双重检查的设计考量// init() 内部的检查可能无权限this.checkAndSendReminders();// ↓ checkAndSendReminders 内部也检查权限// ↓ if (!hasPermission) return;// onCreate 中的显式检查consthasPermissionawaitNotificationUtil.checkPermission();if(hasPermission){awaitImportantDayManager.getInstance().checkAndSendReminders();}实际上checkAndSendReminders()内部已有权限检查onCreate中的显式检查是冗余的。但这种双重检查确保了可靠性——即使内部检查逻辑发生变化外部检查仍然保障。六、窗口管理获取主窗口windowStage.getMainWindow((err,win){if(err.code){console.error(Failed to get main window:,err);return;}// 沉浸式设置已注释});沉浸式状态栏预留/*win.setWindowLayoutFullScreen(true); win.setWindowSystemBarProperties({ statusBarContentColor: #333333, navigationBarContentColor: #333333 });*/这段代码被注释了但保留了沉浸式全屏的方案setWindowLayoutFullScreen(true)设置全屏布局setWindowSystemBarProperties设置状态栏和导航栏文字颜色加载主页面windowStage.loadContent(pages/MainEntry,(err){if(err.code){console.error(Failed to load content:,err);return;}console.info(Loaded MainEntry successfully);});pages/MainEntry对应MainEntry.ets文件中的Entry组件。七、与 module.json5 的关联{module:{mainElement:EntryAbility,abilities:[{name:EntryAbility,srcEntry:./ets/entryability/EntryAbility.ets,skills:[{entities:[entity.system.home],actions:[action.system.home]}]}]}}配置说明字段值说明mainElementEntryAbility应用入口 AbilitysrcEntry./ets/entryability/EntryAbility.ets源文件路径skillsentity.system.homeaction.system.home声明可从桌面启动WantAgent 与配置的对应// WantAgent 中的配置{bundleName:com.importantdays.app,abilityName:EntryAbility,action:action.system.home}必须与app.json5的bundleName和module.json5的abilities[0].name一致。八、前台提醒检查机制为什么每次回前台都检查场景 1. 用户早上 8 点打开应用设置了一个 3 天后提醒的重要日 2. 用户退出应用 3. 三天后重要日进入提醒范围 4. 用户下午 2 点打开应用 5. onForeground → checkAndSendReminders → 发送通知鸿蒙应用在后台时无法主动发送通知除非使用后台任务因此每次回到前台时检查是务实的解决方案。检查逻辑asynccheckAndSendReminders():Promisevoid{constneedReminderthis.getDaysNeedReminder();// needReminder 所有 shouldRemind() 返回 true 的重要日consthasPermissionawaitNotificationUtil.checkPermission();if(!hasPermission)return;for(constdayofneedReminder){consttitleday.isToday()?今天${day.title}:即将到来${day.title};constcontentday.getDisplayText();awaitNotificationUtil.publishBasic(title,content,this.getNotificationId(day.dayID));}}重复通知问题每次回前台都会发送通知可能导致重复通知。但由于使用稳定的通知 ID基于 dayID 哈希相同 ID 的通知会覆盖而非追加。九、总结EntryAbility的设计体现了以下原则初始化有序Preferences → Manager → 通知检查依赖关系清晰生命周期完整所有回调都有实现即使只是日志前台检查每次回前台检查提醒确保不遗漏错误处理窗口加载和内容加载都有错误检查配置一致与 app.json5 和 module.json5 保持对应EntryAbility是应用的入口点它的正确初始化是整个应用正常运行的基石。