HarmonyOS应用开发实战:小事记 - Context 类层级体系:从 ApplicationContext 到 UIContext 的职责划分
前言在 HarmonyOS 的 Stage 模型中Context是连接应用、模块、Ability 和 UI 层的核心纽带。每个组件都有其对应的 Context 类型提供不同粒度的能力——从获取应用基本信息到启动其他 Ability从资源管理到 UI 弹框控制。开发者如果混淆了不同 Context 的职责轻则代码逻辑出错重则出现运行时异常。本文以 小事记xiaoshiji_ohos_app 项目中的EntryAbility.ets和SettingsPage.ets为切入点深入解析ApplicationContext、UIAbilityContext、AbilityStageContext和UIContext的继承关系、获取方式与最佳实践。核心特点简单易用API 设计直观上手成本低性能优异底层优化充分运行效率高扩展性强支持自定义配置和扩展本文参考 HarmonyOS 官方文档application-context-stage.md 和 UIAbility 参考。一、Context 类的继承体系1.1 类层级结构HarmonyOS 的 Context 采用分层继承设计每一层在基类基础上扩展特定能力Context基类 ├── ApplicationContext应用级别 ├── AbilityStageContext模块级别 ├── UIAbilityContextAbility 级别 │ └── 通过 getHostContext() 获取 └── ExtensionContext扩展能力级别 ├── BackupExtensionContext ├── ServiceExtensionContext └── FormExtensionContextUIContext是独立的 UI 上下文与上述继承体系无直接关系它属于 ArkUI 框架的 UI 实例上下文。Context 类型作用域获取方式关键能力Context基类全局所有子类继承resourceManager、applicationInfo、area文件分区ApplicationContext应用进程this.context.getApplicationContext()设置颜色模式、语言、监听前后台、清除数据AbilityStageContext模块AbilityStage 的this.context获取模块信息、createModuleContext()UIAbilityContextAbilityUIAbility 的this.contextstartAbility()、connectServiceExtensionAbility()、terminateSelf()UIContextUI 实例getUIContext()弹框、字体、键盘避让、获取宿主 Context1.2 不同类型 Context 不可互转官方文档明确指出不同类型的 Context 具有不同的能力不可相互替代或强行转换。// ❌ 错误UIAbilityContext 没有 setFontSizeScale 方法 let uiAbilityContext this.context as common.UIAbilityContext; uiAbilityContext.setFontSizeScale(1.0); // 编译错误 // ✅ 正确先获取 ApplicationContext let applicationContext this.context.getApplicationContext(); applicationContext.setFontSizeScale(1.0, 1.0);二、ApplicationContext应用全局上下文2.1 获取方式ApplicationContext 是应用级别的全局上下文在整个应用进程中唯一。官方提供了两种获取方式方式一从 API 14 起直接使用静态方法获取import { application } from kit.AbilityKit; let appContext application.getApplicationContext();方式二通过已有的 Context 实例获取兼容所有版本// 在 UIAbility 中获取 export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { let appContext this.context.getApplicationContext(); // 使用 ApplicationContext 设置颜色模式 appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); } }2.2 核心能力详解设置颜色模式— 小事记项目在onCreate中调用了setColorMode// EntryAbility.ets — 使用 ApplicationContext 设置颜色模式 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { try { this.context.getApplicationContext().setColorMode( ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET ); } catch (err) { hilog.error(DOMAIN, testTag, Failed to set colorMode. Cause: %{public}s, JSON.stringify(err)); } }COLOR_MODE_NOT_SET表示跟随系统设置还有COLOR_MODE_LIGHT浅色和COLOR_MODE_DARK深色模式。获取应用文件路径let appContext this.context.getApplicationContext(); let filesDir appContext.filesDir; // 应用文件目录 let cacheDir appContext.cacheDir; // 缓存目录 let tempDir appContext.tempDir; // 临时目录监听应用前后台变化let appContext this.context.getApplicationContext(); appContext.on(abilityLifecycle, (abilityLifecycleInfo) { if (abilityLifecycleInfo.lifecycleState foreground) { console.log(应用进入前台); } else if (abilityLifecycleInfo.lifecycleState background) { console.log(应用进入后台); } });设置应用语言appContext.setLanguage(zh-Hans-CN); // 设置为简体中文2.3 使用场景总结场景使用 ApplicationContext原因设置颜色模式✅ 必须使用应用级配置全局生效设置语言✅ 必须使用应用级配置全局生效获取文件目录✅ 推荐使用路径与应用进程绑定监听前后台✅ 必须使用只有 ApplicationContext 提供on(abilityLifecycle)启动其他 Ability❌ 不可使用需要UIAbilityContext.startAbility()显示弹框❌ 不可使用需要UIContext.showDialog()三、UIAbilityContextAbility 级别上下文3.1 获取方式UIAbilityContext 是每个 UIAbility 实例独有的上下文在 UIAbility 内部通过this.context直接获取// EntryAbility.ets — 直接访问 this.context export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // this.context 的类型是 UIAbilityContext let abilityInfo this.context.abilityInfo; let hapModuleInfo this.context.currentHapModuleInfo; } }在 UI 组件中获取 UIAbilityContext需要通过UIContext.getHostContext()// 在 Component 中获取 UIAbilityContext import { common } from kit.AbilityKit; Entry Component struct SettingsPage { private context this.getUIContext().getHostContext() as common.UIAbilityContext; build() { Button(启动其他应用) .onClick(() { this.context.startAbility({ bundleName: com.example.other, abilityName: MainAbility }); }) } }3.2 核心能力详解启动其他 Ability// 显式启动 this.context.startAbility({ bundleName: com.example.target, abilityName: TargetAbility, parameters: { key: value } }); // 隐式启动 this.context.startAbility({ action: ohos.want.action.view, uri: https://developer.harmonyos.com });连接 ServiceExtensionAbilitylet connectionId this.context.connectServiceExtensionAbility( { bundleName: com.example.service, abilityName: BackgroundService }, { onConnect: (elementName, proxy) { console.log(Service 连接成功); }, onDisconnect: () { console.log(Service 断开连接); } } );销毁自身this.context.terminateSelf((err) { if (err.code) { console.error(terminateSelf failed: ${err.message}); } });3.3 UIAbilityContext 与 ApplicationContext 的协作实际开发中两个 Context 经常配合使用// 在 UIAbility 中协作 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // UIAbilityContext — 记录启动参数 let abilityName this.context.abilityInfo.name; // ApplicationContext — 设置全局配置 let appContext this.context.getApplicationContext(); appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); }四、AbilityStageContext模块级别上下文4.1 定义与获取AbilityStage是模块级别的生命周期入口在 HAP 包加载时创建。它的 Context 是AbilityStageContext提供了模块级别的信息import { AbilityStage } from kit.AbilityKit; export default class MyAbilityStage extends AbilityStage { onCreate(): void { // this.context 是 AbilityStageContext let hapModuleInfo this.context.currentHapModuleInfo; console.log(模块名称: ${hapModuleInfo.moduleName}); console.log(模块描述: ${hapModuleInfo.description}); } }4.2 跨模块 Context 获取在多 Module 工程中可以通过createModuleContext获取其他模块的 Context// 获取其他 Module 的 Context import { application } from kit.AbilityKit; let moduleName feature_module; application.createModuleContext(this.context, moduleName) .then((moduleContext: common.Context) { // 通过 moduleContext 访问该模块的资源 let resourceMgr moduleContext.resourceManager; }) .catch((err: BusinessError) { console.error(获取模块 Context 失败: ${err.message}); });提示如果小事记项目后续扩展为多 Module 架构如添加share功能 HSP 模块就需要通过createModuleContext来跨模块共享数据和资源。五、UIContextUI 实例上下文5.1 与上述 Context 的本质区别UIContext不属于 Context 继承体系它是 ArkUI 框架中的 UI 实例上下文负责 UI 层面的操作。对比维度Context 体系UIContext所属框架kit.AbilityKitkit.ArkUI作用范围应用/模块/Ability 生命周期UI 实例/窗口级别主要能力启动 Ability、文件管理、资源管理弹框、字体、键盘避让、动画获取方式this.context或getHostContext()getUIContext()或window.getUIContext()5.2 获取方式在 UI 组件中获取Entry Component struct HomePage { build() { Button(显示弹框) .onClick(() { // 通过 getUIContext() 获取 UIContext this.getUIContext().getPromptAction().showToast({ message: 操作成功, duration: 2000 }); }) } }通过 Window 获取import { window } from kit.ArkUI; // 在 UIAbility 中获取 Window 的 UIContext onWindowStageCreate(windowStage: window.WindowStage): void { windowStage.getMainWindow().then((mainWindow) { let uiContext mainWindow.getUIContext(); // 使用 UIContext }); }5.3 核心能力详解显示弹框与提示let uiContext this.getUIContext(); // Toast 提示 uiContext.getPromptAction().showToast({ message: 保存成功, duration: 2000 }); // 确认对话框 uiContext.getPromptAction().showDialog({ title: 提示, text: 确定要删除这条记录吗, buttons: [ { text: 取消, color: #9CA3AF }, { text: 确定, color: #FF6B6B } ] }); // 操作菜单 uiContext.getPromptAction().showActionMenu({ title: 请选择操作, buttons: [ { text: 编辑, color: #7B68EE }, { text: 删除, color: #FF6B6B } ] });获取宿主 Context// 在 UI 组件中获取 UIAbilityContext let uiAbilityContext this.getUIContext().getHostContext() as common.UIAbilityContext;设置键盘避让模式this.getUIContext().setKeyboardAvoidMode( KeyboardAvoidMode.RESIZE // 键盘弹出时应用窗口向上避让 );六、实际项目中的 Context 使用模式6.1 小事记项目的 Context 使用分析在EntryAbility.ets中使用了两种 Context 的协作export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // 1. 使用 UIAbilityContextthis.context获取 ApplicationContext let appContext this.context.getApplicationContext(); // 2. 使用 ApplicationContext 设置颜色模式 appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); // 3. 使用 UIAbilityContext 记录日志信息 hilog.info(DOMAIN, testTag, Ability onCreate); } onWindowStageCreate(windowStage: window.WindowStage): void { // 4. 使用 WindowStage 加载页面 windowStage.loadContent(pages/Index, (err) { if (err.code) { hilog.error(DOMAIN, testTag, Failed to load the content. Cause: %{public}s, JSON.stringify(err)); return; } }); } }Context 的职责流转过程如下用户点击应用图标 ↓ 系统创建 UIAbility 实例 ↓ this.context UIAbilityContext ← Ability 级别的上下文 ↓ this.context.getApplicationContext() → ApplicationContext ← 应用级别的上下文 ↓ onWindowStageCreate(windowStage) → WindowStage ← 窗口管理 ↓ windowStage.loadContent(pages/Index) → 加载 UI 页面 ↓ 在 UI 组件中 getUIContext() → UIContext ← UI 实例上下文6.2 推荐的 Context 获取策略代码位置推荐的 Context 获取方式原因UIAbility 内部直接使用this.context类型为UIAbilityContext功能最全UIAbility 内部应用级操作this.context.getApplicationContext()获取应用级能力AbilityStage 内部this.context类型为AbilityStageContext模块级操作Component 组件UI 操作this.getUIContext()直接访问 UI 相关 APIComponent 组件Ability 操作this.getUIContext().getHostContext()获取 UIAbilityContextExtensionAbility 内部this.context类型为ExtensionContext扩展能力上下文6.3 常见错误与避免错误 1在 UI 组件中直接使用 UIAbility 的this.context// ❌ 错误UI 组件中没有 this.context Entry Component struct HomePage { aboutToAppear(): void { let appContext this.context.getApplicationContext(); // 编译错误 } } // ✅ 正确通过 UIContext 获取宿主 Context Entry Component struct HomePage { private context this.getUIContext().getHostContext() as common.UIAbilityContext; aboutToAppear(): void { let appContext this.context.getApplicationContext(); // 正确 } }错误 2混淆 UIContext 与 ApplicationContext// ❌ 错误UIContext 没有 setLanguage 方法 let uiContext this.getUIContext(); uiContext.setLanguage(zh-Hans-CN); // 编译错误 // ✅ 正确获取 ApplicationContext 后调用 let appContext this.getUIContext().getHostContext() .getApplicationContext(); appContext.setLanguage(zh-Hans-CN);七、Context 在性能与内存中的考量7.1 Context 的引用传递Context 持有与泄露是常见的内存问题。ApplicationContext 是单例的而 UIAbilityContext 在 Ability 销毁后应被释放// ❌ 错误在全局单例中持有 UIAbilityContext class GlobalManager { static context: UIAbilityContext; // 可能造成泄露 } // ✅ 正确使用 ApplicationContext 进行全局存储 class GlobalManager { static context: ApplicationContext; // 应用级别不会泄露 }7.2 Context 的等价性判断由于 Context 存在继承关系判断两个 Context 是否相等时需要注意// 两个不同的 UIAbility 实例它们的 context 不同 let context1 ability1.context; let context2 ability2.context; console.log(context1 context2); // false // 但 getApplicationContext() 返回的是同一个对象 let appContext1 ability1.context.getApplicationContext(); let appContext2 ability2.context.getApplicationContext(); console.log(appContext1 appContext2); // true单例八、实战在 SettingsPage 中管理 Context8.1 场景描述在小事记的SettingsPage.ets中需要实现以下功能读取用户配置需要 ApplicationContext 获取文件路径跳转到数据备份页面需要 UIAbilityContext 启动 Ability显示提示弹框需要 UIContext8.2 完整实现// SettingsPage.ets — 三种 Context 的协作使用 import router from ohos.router; import { common } from kit.AbilityKit; import { BottomTabBar } from ../common/BottomTabBar; Entry Component export struct SettingsPage { // 获取 UIAbilityContext用于启动 Ability private uiAbilityContext this.getUIContext().getHostContext() as common.UIAbilityContext; // 获取 ApplicationContext用于文件操作 private appContext this.uiAbilityContext.getApplicationContext(); build() { Column() { // 设置页面 UI Scroll() { Column({ space: 16 }) { this.buildSettingsCard(data) } .padding({ bottom: 20 }) } .layoutWeight(1) BottomTabBar({ currentTab: SettingsPage }) } .width(100%) .height(100%) .backgroundColor(#F8F9FA) } Builder buildSettingsCard(group: string) { Column({ space: 0 }) { if (group data) { Row() { Text(数据备份) Blank() Text() } .height(52) .padding({ left: 20, right: 20 }) .onClick(() { // 使用 UIAbilityContext 的路由能力 router.pushUrl({ url: pages/DataBackupPage }); }) } } .backgroundColor(Color.White) .borderRadius(16) .margin({ left: 20, right: 20 }) } }总结本文从xiaoshiji_ohos_app项目的源码出发深入解析了 HarmonyOS Stage 模型中Context 类层级体系的设计与使用。核心要点如下Context 体系分为五层基类 Context → ApplicationContext / AbilityStageContext / UIAbilityContext / ExtensionContext各层职责分明不可互转UIContext 是独立的 UI 上下文不属于 Context 继承体系专用于 UI 操作弹框、字体、键盘避让获取策略UIAbility 中直接使用this.contextUI 组件中通过getUIContext().getHostContext()获取 Ability 上下文内存管理ApplicationContext 是单例安全的而 UIAbilityContext 在 Ability 销毁后应被释放避免在全局单例中持有下一篇文章将深入解析module.json5 配置详解 Ability 声明、skills 隐式匹配和 extensionAbilities 的配置技巧。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源小事记项目源码xiaoshiji_ohos_app官方文档 - 应用上下文 Contextapplication-context-stage.md官方文档 - UIAbility 参考js-apis-app-ability-uiability官方文档 - ApplicationContextjs-apis-inner-application-applicationcontext官方文档 - UIContextarkts-apis-uicontext-uicontext官方文档 - 应用生命周期application-lifecycle.md官方文档 - Context 获取示例application-context-stage开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

相关新闻

为什么你的AI广告歌被起诉?揭秘3类“看似免费实则高危”的商用授权协议(附律师审核清单)

为什么你的AI广告歌被起诉?揭秘3类“看似免费实则高危”的商用授权协议(附律师审核清单)

更多请点击: https://kaifayun.com 第一章:为什么你的AI广告歌被起诉?——一场正在爆发的版权信任危机 当某快消品牌用生成式AI创作的30秒广告歌上线一周后,突然收到三份来自不同作曲家的律师函——指控其旋律、和声进行与节奏动…

2026/7/26 19:28:26 阅读更多 →
HarmonyOS应用开发实战:小事记 - oh-package.json5 依赖管理:@ohos 与 @kit 的模块化演进

HarmonyOS应用开发实战:小事记 - oh-package.json5 依赖管理:@ohos 与 @kit 的模块化演进

前言 HarmonyOS 的依赖管理系统经历了从 ohos 原生模块到 kit Kit 化模块的重大演进。oh-package.json5 作为项目的依赖声明文件,管理着从测试框架到业务库的所有三方依赖。理解 ohos 与 kit 的模块化设计理念、依赖版本管理策略和多模块工程的依赖配置&#xff0c…

2026/7/26 16:15:34 阅读更多 →
HarmonyOS应用开发实战:小事记 - 应用包结构:HAP/HSP/HAR 的三层架构与 deliveryWithInstall 策略

HarmonyOS应用开发实战:小事记 - 应用包结构:HAP/HSP/HAR 的三层架构与 deliveryWithInstall 策略

前言 HarmonyOS 的应用包结构采用了分层模块化设计,将代码和资源组织为 HAP(HarmonyOS Ability Package)、HSP(HarmonyOS Shared Package)和 HAR(HarmonyOS Archive)三种包格式。这种设计使得应…

2026/7/26 21:54:22 阅读更多 →

最新新闻

79-QLoRA原理深入-4bit量化-NF4-双重量化-bitsandbytes配置

79-QLoRA原理深入-4bit量化-NF4-双重量化-bitsandbytes配置

文章目录【79.PythonAI】QLoRA原理深入:4-bit量化LoRA,24G显存也能微调7B模型导入语1 ~> QLoRA的三项核心技术1.1 显存账本2 ~> NF4:为正态分布量身定做的4-bit编码2.1 为什么不能简单地均匀切分2.2 NF4的定义2.3 关键:存储…

2026/7/26 23:55:50 阅读更多 →
78-LLaMA-Factory微调实战-零代码训练-LoRA参数配置-训练曲线解读

78-LLaMA-Factory微调实战-零代码训练-LoRA参数配置-训练曲线解读

文章目录【78.PythonAI】用LLaMA-Factory一条命令开始微调:零代码也能做模型训练导入语1 ~> 训练链路总览2 ~> 环境搭建2.1 安装(conda隔离,避免污染主环境)2.2 常见安装坑3 ~> 数据集注册3.1 放置文件3.2 在 dataset_in…

2026/7/26 23:55:50 阅读更多 →
AI核心技术解析:RAG、MCP、Agent与Function Call实战指南

AI核心技术解析:RAG、MCP、Agent与Function Call实战指南

1. 走进AI技术核心:四大关键概念解析最近在技术社区里经常看到同行们讨论RAG、MCP、Agent和Function Call这些AI领域的热门概念。作为从业者,我发现很多刚接触AI开发的朋友对这些术语的理解还停留在表面。今天我就结合自己的项目经验,带大家深…

2026/7/26 23:55:50 阅读更多 →
移动端(非uniapp项目) PDA 扫码踩坑:input 聚焦屏蔽软键盘完整解决方案

移动端(非uniapp项目) PDA 扫码踩坑:input 聚焦屏蔽软键盘完整解决方案

目录 第一章 前言 第二章 完整代码实现 第三章 核心实现原理:inputMode 控制软键盘 第四章 PDA 扫码硬件工作原理补充 第五章 踩坑总结 & 兼容注意事项 第一章 前言 业务场景:移动端 PDA 仓储扫码项目(H5项目非uniapp项目&#xff…

2026/7/26 23:55:50 阅读更多 →
实时新闻地图:基于OpenAI嵌入与HNSWLib的新闻聚类可视化实战

实时新闻地图:基于OpenAI嵌入与HNSWLib的新闻聚类可视化实战

在信息爆炸的时代,如何快速把握新闻动态的全貌成为开发者和数据分析师面临的共同挑战。传统的新闻聚合方式往往滞后且分散,而基于实时数据构建的可视化地图能够提供更直观的洞察。本文将完整拆解一个实时新闻周期地图项目的技术实现,从数据采…

2026/7/26 23:55:50 阅读更多 →
CC2510Fx定时器深度解析:从PWM到DSM音频的实战指南

CC2510Fx定时器深度解析:从PWM到DSM音频的实战指南

1. 项目概述:为什么需要深入理解定时器?在嵌入式开发,尤其是无线通信和实时控制领域,定时器(Timer)的地位堪比心脏之于人体。它不仅是系统节拍的来源,更是实现精准延时、PWM(脉冲宽度…

2026/7/26 23:54:50 阅读更多 →

日新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/26 0:00:31 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/26 0:00:31 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/26 0:00:31 阅读更多 →

月新闻