看到 1002000001 这个错误码的时候,我第一反应不是翻代码,而是先看一眼签名配置和 AGC 后台。因为“system internal error”这个返回,十有八九不是客户端逻辑写错了,而是某个环境条件没满足,被 SDK 统一收敛成了内部错误。鸿蒙游戏接入 Game Service Kit 时,这个错误码可以说是新手必踩、老手也偶尔翻车的典型。本文不会只给你一个“重启手机”的万能答案,我会从登录链路、AGC 配置、签名指纹、设备环境、网络链路和混淆规则几个方向,结合真实案例把排查过程摊开讲。无论你是第一次接触游戏服务,还是已经被这个错误码折磨了几个小时,顺着后面的排查顺序走一遍,都能省下很多时间。
1. 先看懂 1002000001 到底想告诉你什么
1.1 错误码体系里的位置:1002 段是游戏服务专属
Game Service Kit 的错误码不是乱来的,它一般是一个多段结构,前几位通常表示错误所在的业务域。1002 这个段基本就是游戏服务自己的结果码区间,后面的 000001 才表示具体异常子类。1002000001 对应的英文文案是 system internal error,直译是“系统内部错误”,看起来像手机系统坏了,实际上范围宽得很:客户端、账号服务、游戏服务器、网络链路,任何一环出现非预期状态,都有可能被映射成这个码。
我自己的理解更倾向于把它当成一个“边界异常收敛后的兜底错误码”。也就是说,SDK 在执行登录请求时已经触发了某种内部异常,但没有拿到更细的二级分类,只能给出一个通用错误。理解这一点很重要,因为排查它更像排查环境,而不是排查业务逻辑。你把它当成“请求没有按预期完成”的信号,而不是“某个字段写错了”的错误提示,方向才不会跑偏。
还有一个小细节:如果是网络异常,SDK 可能会在同一回调里附带一段英文尾巴,比如 timeout、certificate verify failed、not configured 之类的关键词。这些尾巴才是定位的关键,只看五位数加一句 system internal error 等于拿了个“系统异常”就开始瞎猜,很难有进展。
1.2 不要一上来就重写代码
这个错误码最容易引发一个连锁反应:开发同学一看到 system internal error,立刻怀疑自己代码写错了,然后逐段重写初始化、换 SDK 版本、改线程调度,折腾半天发现还是复现。我处理过很多个类似工单,最后九成问题根本不在当前代码逻辑里,而是 AGC 平台配置、签名指纹、账号环境或网络链路。
所以看到一个通用内部错误码,先稳住。把它分成两筐来想:一筐是“配好环境就能解决”,另一筐是“需要看调用链数据才能解决”。如果你本地测试一直复现,正式渠道没人报,基本就是签名、环境或网络差异;如果线上持续报,就要先区分是登录前的初始化失败,还是登录后的某个接口失败。这两个时机的排查入口完全不一样,下面所有内容都围绕这个分类来展开。
2. 排查前先把登录链路和初始化姿势过一遍
2.1 一条登录请求要在多个节点之间走一圈
游戏服务登录没法在客户端独立完成。大致链路是:游戏进程发起登录,SDK 检查本地基础服务,拉起华为账号能力,拿到用户授权后通过 AGC 鉴权,最终向游戏服务云端接口换取游戏侧凭证。这条链路里任何一个节点出问题,最终都可能以 1002000001 这种“内部错误”的形式出现在你面前。
具体到鸿蒙上,除去游戏进程本身,至少涉及三块:HMS Core 相关能力是否可用、账号服务是否处于正常登录态、AGC 上应用配置和云端服务是否有效。用一个生活类比:你想去办一张会员卡,结果你走进了一个没有办公窗口的分店,或者忘了带身份证,或者门牌号写错了,前台只会告诉你“业务办理失败”,而不是告诉你具体哪个环节失败。这和 1002000001 的情况很像。
所以排查顺序不能乱来。先确认前置条件,再看调用链。前置条件里最容易出错的是签名、包名、应用ID、服务开关这几项,它们不在代码运行时报语法错误,而是在你调用登录接口时变成“内部错误”反馈给你。这也是为什么很多人在本地“明明能打开游戏”,却总是登不上。
2.2 初始化顺序和调用时机往往被忽略
很多项目会把初始化放在入口类的早期阶段,但鸿蒙的 Ability 生命周期不完全等同于传统移动端,不同入口的启动路径也不一样。更稳的做法是:在主入口的 onStart/onWindowStageLoad 完成后再触发 Game Service Kit 的初始化,并且不要在每个页面重复初始化。重复初始化在本地可能没感觉,但在某些系统版本上会触发内部状态重置,导致登录请求上下文丢失,然后返回这种内部错误。
登录的调用时机也很关键。不要在刚初始化完就立刻发起登录,SDK 可能还需要同步本地配置。正常情况下初始化回调成功后,再去做静默登录或拉起登录动作。我这里给一个伪代码示意,目的不是让你照抄 API,而是强调一定要打印完整返回体:
// 伪代码示意,具体以当前 Game Service Kit 版本 API 为准 const loginResult = await gameServiceKit.login() if (loginResult.retCode === 1002000001) { // 不要只看 retCode,一定要打印完整返回上下文 console.info(`code=${loginResult.retCode}, msg=${loginResult.rtnMsg}`) console.info(`requestId=${loginResult.requestId}`) console.info(`trace=${loginResult.traceLogger}`) }别小看这段日志。很多工单最后能定位,靠的就是 rtnMsg 里带着的“超时”“证书校验失败”或“账户未授权”这类附加信息。日志是第一生产力,这句话在游戏服务排查里尤其适用。
2.3 完整返回体比错误码值钱
我见过太多人只打印 resultCode,然后在 switch 里写一堆针对 1002000001 的弹窗文案,这没有意义。如果是签名问题,弹一千次“系统繁忙”也解决不了。正确做法是至少在联调阶段把返回对象整体格式化输出到日志,尤其是错误子结构、扩展错误码、错误级别这些额外字段。不同 SDK 版本字段名可能不同,但只要你能在日志里搜到下面任一关键词,优先级就很清晰了:
- certificate 或 sign:签名/证书相关
- timeout 或 read timed out:网络超时
- not configured 或 service not enabled:服务未开通/未使能
- user not logged in:账号状态异常
- denied 或 unauthorized:授权或权限问题
实在找不到这些关键词,再按照下一章逐项排查,肯定会命中其中一个。
3. 最常见的几类根因:按优先级排查
3.1 AGC 配置不匹配:优先怀疑
Game Service Kit 强依赖 AppGallery Connect 平台,一般简称 AGC。你的应用包名、应用 ID、Client ID、签名指纹都要在 AGC 后台和当前包保持一一对应。这里最容易被坑的有三件事:
- AGC 上根本没有开通游戏服务能力,直接调用会让 SDK 认为所需服务未配置,抛内部错误;
- AGC 里看到的包名和工程里的包名不完全一致,比如多了
.debug后缀,或者底层包名改过但 AGC 没同步; - 同一个开发者账号下配置了多个应用,复制粘贴时把另一个应用的 client_id 填了进来,SDK 拿到的应用标识和当前安装包不是对应关系。
所以第一步永远是进入 AGC 控制台,打开项目下的应用信息,核对包名、应用 ID、签名指纹三项。别觉得这些配置看起来“不会影响运行时”,实际上它们对运行时最敏感。一个很常见的场景是:项目从一台电脑迁移到另一台电脑,重新生成签名文件后就开始报 1002000001,这就是配置一致性被打破了。
3.2 签名指纹不一致:调试包最容易踩
鸿蒙应用编译后会带签名,AGC 侧会校验安装包携带的证书指纹。同一个应用存在多套证书时,调试证书和发布证书指纹往往不一样。只要 AGC 没有把你正在用的证书指纹加进去,SDK 访问游戏服务时就会因为身份校验失败而返回内部错误。
注意,本地能装上不代表没问题。安装不检查 AGC 指纹,登录才检查。查指纹的方式在本地就能完成,拿到签名文件后执行:
keytool -list -v -keystore release.keystore -alias release -storepass ****** | findstr /i "SHA256"鸿蒙签名体系的证书指纹也支持从构建产物或 devtools 配置里查看,本质一样:找到正在签名的证书,拿它的 SHA256,再和 AGC 后台填的那一串逐字对比。不要小看一个字母或者一个冒号大小写。如果你用自动化构建流水线打包,尤其要确认 CI 里选的 keystore 和 AGC 配置是否匹配,不要放一个旧的 debug.keystore 在流水线里跑一天。
注意:调试版和发布版建议在 AGC 后台分别维护指纹。否则“本地 debug 签名跑得挺好,上架包一出来就报 1002000001”的问题会反复出现。
3.3 设备侧 HMS Core 与账号状态
配置和签名都没问题,就要看手机本身了。第一,HMS Core 是否安装、版本是否过老。部分低版本 HMS Core 对新的 Game Service 接口协议不兼容,会导致请求传到一半就失败。第二,华为账号是否已登录,是否在授权页被用户拒绝过。账号在“取消授权”后,SDK 下次登录时可能拿不到可靠用户态,某些版本也会归类为系统内部错误。第三,设备时间是否与网络时间同步,偏差过大时 token 校验会失败,表现同样是 1002000001。
还要提醒一句:模拟器和部分不带完整 HMS Core 的定制系统,非常容易踩这个错误。很多人图方便在模拟器上联调,却忘了模拟器没有厂商账号基础设施,最终自然会报内部错误。不要拿模拟器作为游戏服务联调的唯一环境,至少准备一台能正常登录华为账号、系统干净的真机。
3.4 网络链路或抓包工具在中间使绊子
Game Service Kit 的登录请求要走 HTTPS,一旦中间设备对 TLS 握手进行拦截或者篡改,客户端校验不过,也会收敛成 system internal error。我遇到过一个典型案例:开发者为了调试接口,开启了抓包工具并安装了自定义 CA 证书,结果第二天在自己的电脑上连登录都登不上,代码一行没改。关掉抓包、卸掉自定义证书后问题马上消失。
排查时可以先做两个对比:一是切换 Wi-Fi 和移动数据链路;二是在不启用任何抓包工具、不安装任何自定义证书的情况下重试。如果问题只在特定网络或特定设备上出现,基本可以确定是中间链路干扰,而不是游戏服务本身的问题。公司内部网络如果加了严格出口校验策略,需要让网络管理员把游戏服务相关域名加入白名单。这里不要轻易把网络层问题甩给技术支持,先给出可复现条件,效率会高很多。
3.5 混淆规则把 SDK 类“优化”掉了
如果你的项目开启了代码混淆或裁剪,某些情况下 SDK 内部类会被错误移除或改名,导致运行时无法完成 RPC 调用,返回内部错误。这类问题有一个特征:Debug 不开混淆时一切正常,一打 Release 包就出现 1002000001,且日志里能看到 ClassNotFoundException 或 NoSuchMethodError 的蛛丝马迹。
解决方案是给 GameServiceKit 相关包名加 keep 规则。以传统 ProGuard 风格为例,可以写成:
-keep class com.huawei.game.** { *; } -keep class com.huawei.hms.game.** { *; } -keepclassmembers class com.huawei.game.** { *; }鸿蒙工程里的 obfuscation 配置语法不同,但思路一致:把 SDK 暴露的入口类和回调类全部保留,不参与重命名和裁剪。改完后打一次 Release 包验证,问题通常不会再出现。每次升级 SDK 版本,也要顺手看一下新版文档里是否新增了需要 keep 的 class,旧配置不一定能覆盖新内部结构。
4. 真实排查案例:从报错到定位只用了三步
4.1 案例A:Debug 签名包在上线前集体报错
一位朋友负责接入游戏服务,本地用 debug 签名联调了两周都顺利。某天要提交测试包,用发布签名打了一个预发布包装到自己手机上,结果登录直接 1002000001。他第一反应是服务端问题,找后端查了半天也没结果。我给了他三步操作:
- 用 keytool 查发布签名文件的 SHA256;
- 去 AGC 后台对比签名指纹;
- 确认 AGC 上游戏服务开关已打开。
结论就是发布签名指纹没配。把指纹更新到 AGC 后台,再登录就通了。这类问题在 Game Service 接入里太常见,所以每次看到 1002000001,我的第一顺位永远是核对签名和 AGC 配置,而不是打开代码一行行读。
4.2 案例B:线上特定网络反复上报
另一个案例是已经上线的产品,正式环境偶尔出现 1002000001,集中在某个园区网络或某类认证网络内。本地复现不了,换数据链路就正常。我们当时把重点放在网络链路上,起初怀疑是网络转发设备对 TLS 握手做了拦截。让用户在出口设备上放行游戏服务相关域名后问题消失。
这个案例的启示是:1002000001 不代表一定是厂商服务出问题。看日志里有没有 TLS 握手失败记录,配合 requestId 和出错时间点,能更快判断是中间链路的问题还是云端服务问题。如果在网络侧无法立刻改配置,客户端可以先增加一次重试,并给用户一个相对友好的提示,减少“登录失败”带来的负面体验。
4.3 案例C:SDK 升级后突然回归
还有一个典型情况:从旧版本游戏服务 SDK 升级到新版本后,原本正常的登录突然报 1002000001,而且只有 Release 包出现。最后定位到两个原因叠加:新版 SDK 增加了内部类,旧混淆规则没有覆盖到;同时新版 SDK 对初始化完成时机要求更严格,项目还在旧的生命周期位置调用登录。
把初始化回调与登录调用改成链式串联,再补上 keep 规则,问题解决。这个案例说明,每次 SDK 升级都不能只是替换文件,要重新走一遍初始化、生命周期和混淆配置的检查项。很多回归问题不是 SDK 本身坏了,而是你的工程环境还停留在上一版假设里。
5. 问题速查表与一键式排查顺序
5.1 常见原因的对照表
把上面这些经验整理成一张速查表,遇到问题先对号入座:
| 报错场景 | 可能原因 | 验证/处理动作 |
|---|---|---|
| 本地调试、多个包全部不可用 | 签名指纹/包名不一致 | keytool 查 SHA256,和 AGC 后台对比 |
| 本地正常,线上偶发 | 网络链路/TLS 拦截 | 切网络复现,查 TLS 失败日志 |
| 仅模拟器异常 | HMS Core 不完整 | 换干净真机 |
| Release 包才出现 | 混淆裁剪/初始化时机 | 补 keep 规则,检查生命周期 |
| SDK 升级后出现 | 新配置、新类未覆盖 | 查 release notes,更新 keep 规则 |
| 设备时间不对 | token 校验失败 | 校准时间后重试 |
表格只是帮你快速分类,具体处理动作还是要回头看前文。你可以在项目 wiki 里也放一张类似表格,新同学接到工单后不至于两眼一抹黑。
5.2 我建议的排查动作顺序
如果时间紧张,就按下面顺序来,不要跳步:
- 打印完整返回体和异常日志,留意 rtnMsg、requestId、trace 字段;
- 核对 AGC 应用信息:包名、应用 ID、签名指纹、游戏服务开关;
- 换一台能正常登录华为账号的真机,切换网络重试;
- 关闭抓包工具、移除自定义证书,再试一次;
- 打一次 Release 包,确认是不是混淆或构建差异;
- 把日志、时间点、网络信息整理好,再决定是否上报支持。
这个顺序基本覆盖了 90% 的 1002000001。前四步通常五分钟能做完,但能过滤掉绝大部分配置和环境问题。
6. 一些文档里不会写清楚的排查心得
6.1 日志要打全,更要会看时间线
遇到内部错误,先判断是“请求还没到服务端就失败”,还是“拿到响应之后解析失败”。判断方法很简单:看日志里有没有 HTTP 耗时记录、TLS 握手失败堆栈、序列化异常等节点。把时间线捋顺,比盯着错误码本身有用得多。很多时候你发现,回调返回失败前几毫秒有一条网络连接重置日志,那问题显然在网络侧,和业务代码无关。
6.2 先自己复现一次,再谈定位
不要一看到错误就往“游戏服务挂了”上想。我自己常用的二分法排查是这样的:用一台干净的设备,全新安装应用商店,登录好华为账号,再装当前报错的 Release 包。如果同样报错,说明是配置、签名或服务端问题;如果正常,那基本是本机环境问题。这样一分,排查范围立刻缩小一半。
6.3 与厂商技术支持沟通时,准备好三样东西
如果真的到了需要上报支持的环节,至少准备三样材料,否则来回几个工作日都未必有结论:
- 应用包名、版本号、AGC 应用 ID;
- 完整日志,包含 requestId 和出错时间点;
- 可复现的步骤、设备型号、系统版本、网络信息。
信息越全,定位越快。我看到很多低效工单,就是只有一个“登录失败”截图,这确实很难推进。
最后分享一点私人体会。我现在再看到 system internal error,反而没有开始做这个错误排查时那么紧张了。因为这个码意味着 SDK 已经把问题抛出来了,链路还在,我们要做的只是顺着日志把断点找出来。真正难查的反而是那些毫无回调、完全静默的失败。遇到 1002000001,耐心、按顺序、看日志,基本都能解决。希望这篇整理能帮你少走几步弯路。