一文带你走进HarmonyOS APP开发 里的 GPM到底是啥
你通过告诉系统“我是谁、我在哪、我多重要”,再通过把系统的温度/负载倾向拿回来,最后在你的画质/帧率预算里做“可控降级/回弹”——谁能把这个闭环接稳,谁的 30 分钟续航与掉帧曲线就会明显好看一圈。
GPM 在 HarmonyOS NEXT 语境里,更多是指「游戏专属的性能调度与管理通道」——它不是你随手写一个 ArkUI 应用就能蹭到的“系统默认加速”,也不会因为你打了个
<game>标签就自动生效;你需要通过官方提供的 Game Service Kit(游戏场景感知/设备状态反馈) 把游戏信息喂给系统,系统才能据此做更贴合游戏负载的资源与温控策略。
至于另一个同名缩写 AGC 的“GPM(游戏性能管理/采集上报)”,那是另一套事(偏线上数据采集与控制台可视化),后面也会点到,免得术语撞车。
1) GPM ≠ 系统帮你偷偷超频哦
很多团队第一次听到 Game Performance Manager,脑子里出现的画面往往是:
“系统给游戏开了后门,优先级拉满,帧率稳住,功耗还能变低——反正我是游戏嘛。”
现实要老实得多:系统需要证据。它得知道“你现在到底在不在游戏”“你在哪个场景(大厅/匹配/团战/Boss)”“你期望的帧率与负载大概多高”,否则它也只能按通用策略兜底(通常意味着更保守,也更难压出你这颗 SoC 的全部合理性能)。
所以在 HarmonyOS NEXT 里,这条路的“接入成本”表现为:
- 不是“改一行配置就全局生效”的隐式能力;
- 而是你要在工程里引入
@kit.GameServiceKit,调用gamePerformance相关接口,按协议上报 包信息/场景信息,并监听 设备状态变化(thermal/负载反馈),形成一段“游戏告诉系统 → 系统调度 → 设备状态回传 → 游戏再决策”的闭环。
另外,如果你口中的 GPM 指的是 AGC 的游戏性能管理(数据采集上报):官方在 HarmonyOS 5.0 及以上 的说明里直接写了——游戏无需集成SDK,只要用户在“手机设置 > 系统和更新 > 用户体验改进计划”打开开关,就能做现网采集并上报 AGC 控制台;但你若想拿到“大厅/团战等场景维度”,就要补 游戏场景感知(也就是上面那套 gamePerformance)来标注场景。
这两层很容易混,写方案时一定要先对齐:你说的是调度通道,还是采集上报?(下文以“调度与管理闭环”为主,因为它是“你必须接、而且接得好才有收益”的那部分。)
2) 它到底管什么的
把它拟人一下:
- 游戏说:“我是游戏(bundleName/appVersion),现在进了【团战】sceneID=7,重要性 importanceLevel=高,我打算按 60 帧跑。”
- 系统说:“收到,我知道你是游戏了,我会按游戏策略走调度/资源管理;但温度在爬升、GPU 负载偏高,我先给你一个状态通知。”
- **游戏(你)**听劝:把后处理降一档、把同屏特效密度降一点、必要时把目标帧率降到 55/50 的“可控档”,避免硬顶到 thermal throttling 后变成不可预测的卡顿雪崩。
这就是所谓 GamePerformance / 游戏场景感知 能干的事:
- 给系统更准的上下文(init + updateGameInfo)
- 订阅设备状态变化(on
deviceStateChanged),拿到系统侧的温度/负载倾向反馈,再反过来调整你的画质管线
3) 什么原理
要点只有两句:
- 你不 init + 不上报场景,系统就只能“猜”你是游戏;猜的结果通常是“按通用策略走”,性能上限不一定差,但通常不够贴脸。
- 你不监听 deviceStateChanged,就等于系统在跟你喊‘温度/负载要翻车了’,但你没装耳朵’。
4) 代码怎么接:最小可用,但“看起来像正规军写的”(ArkTS / Stage 模型)
4.1 依赖与前置(这一步很多人跳,后期踩坑)
- 你的工程已经是 Stage 模型(HarmonyOS NEXT 基本就是 Stage 主场)。
- 能引用
@kit.GameServiceKit(它承载gamePerformance/ 场景感知能力)。
4.2 启动即 init(EntryAbility / 越早越好)
// EntryAbility.ts
import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit';
import gamePerformance from '@kit.GameServiceKit'; // 按文档模块导入方式引用
const BUNDLE_NAME = 'com.yourstudio.yourgame'; // 一定换成你真实的 bundleName
const APP_VERSION = '1.0.0';
export default class EntryAbility extends UIAbility {
async onWindowStageCreate(windowStage: window.WindowStage) {
// 1)最早可行位置:先让 gamePerformance 知道你是谁
try {
await gamePerformance.init({
messageType: 0, // 按文档约定:初始化类型
bundleName: BUNDLE_NAME,
appVersion: APP_VERSION,
} as gamePerformance.GamePackageInfo);
console.info('[GPM] gamePerformance.init ok');
} catch (e) {
// 真机/版本/权限/能力不支持都可能走到这,别崩,记日志
console.warn('[GPM] gamePerformance.init failed', e);
}
// 2)立刻订阅设备状态变化(thermal/负载倾向)
this.listenDeviceState();
// 3)进入大厅时再补一次 updateGameInfo(见下一节)
// windowStage.loadContent('pages/Lobby');
}
private listenDeviceState() {
try {
// 注册 deviceStateChanged:系统会把温度/状态倾向变化回传给你
gamePerformance.on('deviceStateChanged',
(deviceInfo: gamePerformance.GamePerformance_DeviceInfo | any) => {
// 这里别做重型逻辑,只做“状态机切换”:
// - 读到温升档位/负载信号 → 切换画质档位、限帧、降级粒子预算
this.handleDeviceState(deviceInfo);
});
} catch (e) {
console.warn('[GPM] on deviceStateChanged register failed', e);
}
}
private handleDeviceState(deviceInfo: any) {
// 重要:先防御——不同版本/设备返回的字段可能不完全一致
if (!deviceInfo) return;
// 典型可看字段(以 C API 文档里的概念对齐):
// - thermalLevel / temperature trend
// - GPU 负载倾向(若设备支持;Mali 可能拿不到 GPU perf 信息,文档有提示)
console.info('[GPM] deviceStateChanged', JSON.stringify(deviceInfo));
// 例:如果你约定 thermalLevel >= 2 表示“偏热,准备降配”
// if (deviceInfo.thermalLevel >= 2) {
// GraphicsBudget.switchTo('conservative');
// FrameRatePolicy.requestMaxFps(50); // 用你自己的帧率控制点
// }
}
// 离开游戏/登出时:至少把监听清掉
async onDestroy() {
try {
gamePerformance.off('deviceStateChanged');
} catch (_) {}
}
}
4.3 场景切换:大厅 vs 战斗(updateGameInfo 才是“区分对待”的关键)
// 你自己的场景管理器里调用
function reportScene(isFight: boolean) {
try {
const sceneInfo: gamePerformance.GameSceneInfo = {
messageType: 2, // 按文档:上报场景信息
sceneID: isFight ? 7 : 1, // 你跟策划约定好编码表
importanceLevel: isFight ? 4 : 2, // 战斗更高
// subDescription 建议唯一,方便后端/工具侧聚合
subDescription: isFight ? 'fight_main' : 'lobby_idle',
} as gamePerformance.GameSceneInfo;
gamePerformance.updateGameInfo(sceneInfo)
.then(() => console.info('[GPM] scene reported:', sceneInfo.subDescription))
.catch((e: any) => console.warn('[GPM] updateGameInfo fail', e));
} catch (e) {
console.warn('[GPM] updateGameInfo not available', e);
}
}
如果你做的是 Unity/Unreal 的 Native 游戏,同一套语义对应的是 C API:
game_performance.h那一层(HMS_GamePerformance_Init / RegisterThermalLevelChangedCallback等),概念不变:init → 注册 thermal 回调 → 按场景更新信息 → 反注册。
5) 实际开发里“接 vs 不接”的差异案例
案例 A:不接 GPM/场景感知(只用通用 UI 应用思路跑游戏)
现象通常是:
- 前期帧率漂亮,但 8–12 分钟后出现**“阶梯式掉帧 + 手指跟手感变差”**(thermal 上来以后调度缩频,你的特效/后处理还在硬顶)。
- 你以为是“ shader 太贵”,抄起 Profiler 一顿改,但根因其实是策略层不知道你是高强度战斗,所以没有更早切换到“高性能但可持续”的参数组合。
案例 B:接了,但只 init 不 updateGameInfo / 不监听 deviceStateChanged
这属于“买了票没进场”:
- 系统知道你是游戏进程,但你没给它场景差异化信息,它只能按“平均游戏”给策略,结果往往是:大厅被过度当作战斗养着(功耗吃亏),或战斗仍被当大厅轻负载养着(发热吃亏)。
案例 C:接得正(init + 场景编码 + deviceStateChanged 回传决策)
你会得到一个很朴素的收益:把“被动卡顿”变成“主动降级”——
- 温升/负载信号一到,你先把“非致命画质项”(动态阴影距离、粒子密度、后处理 bloom/AA 档位、远景植被LOD偏移)退一格;
- 还压不住,再动“帧率上限/分辨率比例”这种更硬的杠杆;
- 温度回落后,再按档位回弹(别一次全开满,防止来回抖)。
这就是 GPM 想促成的形状:不是系统替你做画质决定,而是它把“设备当下扛不扛得住”的信号给你,你来做更靠谱的自适应。
6) HarmonyOS 6 / API 22 适配:别把“能编过”当成“接对了”
① Stage 模型 + 能力声明是前提
HarmonyOS NEXT 方向就是 Stage,API 22 也不会带你回退 FA;你只要保证:
module.json5里的 ability 类型是UIAbility,生命周期按onWindowStageCreate / onDestroy这类走;- 如果用到的系统能力需要显性声明(不同版本会有微调),别靠“真机刚好有就偷跑”,按官方能力声明规范补齐(否则未来小版本就可能沉默失效)。
② @kit.GameServiceKit 的可用性取决于系统版本/设备能力
SystemCapability.GameService.GamePerformance 是从 5.0.2(14) 起在 API 参考里覆盖的(你能在文档树里看到 game_performance.h 与 thermalLevel 回调定义)。
所以 API 22 时代的现实做法就是:能力探测 + 降级:
// 伪防护:别假设一定存在
if (typeof gamePerformance?.init === 'function') {
// 走 GPM 流程
} else {
// 走“无GPM兜底”:固定画质、保守帧率、别裸奔
}
③ Native 游戏(C/C++ 侧)走 game_performance.h,但 init/注册回调必须在你能拿到上下文的生命周期里
如果你用的是 Unity/UE/Cocos 的 OH 适配分支,真正“干活”的地方往往在 native loop;但 init 与 thermal 回调注册 应该绑到:引擎初始化完成、游戏进程身份确定之后,而不是某个随机渲染帧里。
另外文档也直说了:Mali 系列 GPU 可能无法采集 GPU 性能信息,调用相关接口时可能拿不全 GPU 字段——你的策略别依赖“必须有 GPU 负载值”,要用 thermalLevel/trend 做主判,GPU 字段只当“增强信息”。
④ 别把 AGC-GPM 的“采集开关”当成调度开关
再次提醒防混:
- 如果你要做的是 “系统调度协作 + 设备状态自适应” → 走
gamePerformance(GameServiceKit) - 如果你要做的是 “线上性能数据进 AGC 控制台看大盘” → 那套 GPM 在 HO 5.0+ 甚至可以 不集成 SDK(靠用户开启体验改善计划做现网采集),场景维度再补场景感知。
两件事可以并存,但不要写进同一个 Jira 里当“同一个接入任务”,否则评审会上一定会吵起来。
7) 总结一下下哦
GPM 在 HarmonyOS NEXT 的本质不是“系统给你的魔法开关”,而是一个需要你显式接入的协商通道:
你通过 gamePerformance.init/updateGameInfo 告诉系统“我是谁、我在哪、我多重要”,再通过 on('deviceStateChanged') 把系统的温度/负载倾向拿回来,最后在你的画质/帧率预算里做“可控降级/回弹”——谁能把这个闭环接稳,谁的 30 分钟续航与掉帧曲线就会明显好看一圈。
更多推荐

所有评论(0)