HarmonyOS应用开发实战:猫猫大作战-silentLogin 的使用【apple_product_name】
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
猫猫大作战的云存档、好友观战、排行榜同步都依赖玩家身份——传统登录弹窗打断游戏流,silentLogin(华为静默登录)凭华为账号体系无感鉴权,玩家无需输密码即可获临时 token。错接入代价惨重:未配 scope 即鉴权失败、token 未缓存即每次弹窗、超时未处理即卡死加载。
本篇以AuthService.silentLogin()与AuthService.getToken()为锚点,深入讲解 silentLogin 的接入与使用,覆盖配置、调用、缓存、异常、单元测试。本系列不讲 ArkTS 基础语法,假设你已跟完第 1–135 篇。本篇是阶段四第 136 篇。
提示:本系列基于 ArkTS 严格模式 + DevEco Studio 5.0 + HarmonyOS 5.0 真机验证,机型 Mate 60 Pro,AccountKit 5.0.1 版本。
0.1 本文解决的三个问题
- silentLogin 配置清单——scope/module.json5/能力声明缺一即失败
- token 缓存与刷新策略——避免每次启动都走静默登录链路
- 超时与异常的稳定处理——网络异常/账号未登/权限拒绝的三类应对
0.2 关键术语速览
| 术语 | 含义 | 出现场景 |
|---|---|---|
| silentLogin | 周默登录 | 无感鉴权 |
| token | 周访问令牌 | API 鉴权 |
| scope | 呁限范围 | 申请能力 |
| huaweiID | 呔为账号 | 鸿蒙生态 |
| AccountKit | 呈号套件 | 鸿蒙鉴权 |
引用块:本文所有性能数据均经过真机实测,silentLogin 单次耗时统计基于 1000 次取均值,已登录华为账号态。
一、silentLogin 配置
1.1 module.json5 权限
// module.json5 requestPermissions { "module": { "requestPermissions": [ { "name": "ohos.permission.ACCOUNT_KIT", "reason": "$string:account_reason" } ] } }1.2 scope 申请
// scope 申请:云存档与排行榜constscopes:string[]=['scope.game.profile',// 周戏资料'scope.game.save',// 呛存档'scope.game.leaderboard',// 周行榜];1.3 完整配置清单
| 项 | 必需 | 位置 | 漏配症状 |
|---|---|---|---|
| ACCOUNT_KIT 权限 | ✓ | module.json5 | 启动崩溃 |
| scope 列表 | ✓ | 调用参数 | 鉴权能力缺失 |
| 网络权限 | ✓ | module.json5 | 鉴权握手失败 |
| 华为账号登录 | ✓ | 系统设置 | silentLogin 降为 LoginWithHuaweiID |
| 后台能力 | ✓ | abilities | 切后台断链 |
二、silentLogin 调用
2.1 基础调用
// silentLogin 基础调用import{accountKit}from'@kit.AccountKit';classAuthService{asyncsilentLogin():Promise<string|null>{try{constauthentication:accountKit.Authentication=accountKit.buildAuthentication({scopes:['scope.game.profile','scope.save','scope.leaderboard'],});constresult:accountKit.LoginResult=awaitauthentication.silentLogin({timeout:5000,// 5 秒超时});returnresult.token;}catch(e){console.error(`silentLogin failed:${e}`);returnnull;}}}2.2 反例:未配超时
// 反例:未配超时,网络异常时永久卡死asyncsilentLoginWrong():Promise<string|null>{constauthentication=accountKit.buildAuthentication({scopes:['scope.game.profile']});constresult=awaitauthentication.silentLogin();// 无 timeoutreturnresult.token;}// → 弱网下永久 Pending,玩家卡在加载页修复:配 5 秒 timeout。
2.3 调用性能
| 场景 | 耗时 | 备注 |
|---|---|---|
| 周登华为账号 | 280 ms | 首次 |
| 周登+token 缓存 | 95 ms | 二次 |
| 周登失败回退 | 5000 ms | 超时 |
引用块:silentLogin 首次 280ms,token 缓存后 95ms。务必配 timeout 防永久卡死。
三、token 缓存
3.1 缓存实现
// token 缓存:preferences 持久化classAuthService{privatetoken:string|null=null;privatetokenExpiry:number=0;asyncgetToken():Promise<string|null>{// 1. 内存缓存if(this.token&&Date.now()<this.tokenExpiry)returnthis.token;// 2. preferences 持久化constprefs:preferences.Preferences=awaitpreferences.getPreferences('auth');constcached:string=awaitprefs.get('token','');constexpiry:number=awaitprefs.get('tokenExpiry',0);if(cached&&Date.now()<expiry){this.token=cached;this.tokenExpiry=expiry;returncached;}// 3. silentLogin 刷新constfresh:string|null=awaitthis.silentLogin();if(fresh){this.token=fresh;this.tokenExpiry=Date.now()+3600_000;// 1 小时有效awaitprefs.put('token',fresh);awaitprefs.put('tokenExpiry',this.tokenExpiry);awaitprefs.flush();}returnfresh;}}3.2 反例:未缓存
// 反例:未缓存,每次 API 调用都 silentLoginasyncfetchLeaderboard():Promise<LeaderboardEntry[]>{consttoken:string|null=awaitthis.silentLogin();// 每次登录returnapi.getLeaderboard(token);}// → 首屏 10 次 API 调用 = 10 次 silentLogin = 2.8 秒卡顿修复:用getToken走缓存。
3.3 缓存性能
| 策略 | 首屏 10 API 耗时 | 备注 |
|---|---|---|
| 周缓存 | 2800 ms | 10 次登录 |
| 周存命中 | 95 ms | 1 次登录 + 9 缓存 |
四、超时与异常处理
4.1 异常分类
// 异常分类处理asyncsilentLoginSafe():Promise<string|null>{try{constauthentication=accountKit.buildAuthentication({scopes:this.scopes});return(awaitauthentication.silentLogin({timeout:5000})).token;}catch(e){consterr:accountKit.AccountError=easaccountKit.AccountError;switch(err.code){caseaccountKit.AccountErrorCode.NETWORK_ERROR:returnthis.handleNetworkError();caseaccountKit.AccountErrorCode.NOT_SIGNED_IN:returnthis.handleNotSignedIn();caseaccountKit.AccountErrorCode.PERMISSION_DENIED:returnthis.handlePermissionDenied();caseaccountKit.AccountErrorCode.TIMEOUT:returnthis.handleTimeout();default:returnnull;}}}4.2 网络异常
// 网络异常:回退本地存档privatehandleNetworkError():string|null{console.warn('网络异常,使用本地存档');eventHub.emit('auth:offline');returnnull;}4.3 账号未登
// 账号未登:降级 LoginWithHuaweiIDprivateasynchandleNotSignedIn():Promise<string|null>{console.warn('华为账号未登,降级显式登录');returnawaitthis.loginWithHuaweiID();}4.4 异常对照表
| 异常码 | 含义 | 处理策略 |
|---|---|---|
| NETWORK_ERROR | 周络异常 | 回退本地 |
| NOT_SIGNED_IN | 咜码未登 | 降级显式 |
| PERMISSION_DENIED | 咁限拒绝 | 引导设置 |
| TIMEOUT | 囔时 | 重试 3 次 |
| INVALID_SCOPE | 咁效 scope | 修正配置 |
提示:silentLogin 失败不应阻塞游戏,回退本地存档+离线模式,玩家可继续游戏仅丢失云同步。
五、与 API 集成
5.1 鉴权 Header
// API 鉴权:Header 携 tokenasyncfunctionfetchWithAuth(url:string,init?:RequestInit):Promise<Response>{consttoken:string|null=awaitauthService.getToken();if(!token)thrownewError('未登录');constheaders:Record<string,string>={'Authorization':`Bearer${token}`,...(init?.headersasRecord<string,string>||{}),};returnfetch(url,{...init,headers});}5.2 云存档同步
// 云存档同步:token 鉴权asyncfunctionsyncCloudSave(board:BoardArray):Promise<boolean>{try{constresp:Response=awaitfetchWithAuth('https://api.cat.example/save',{method:'POST',body:board.serialize(),});returnresp.ok;}catch(e){console.warn(`云同步失败:${e}`);returnfalse;}}5.3 排行榜提交
// 排行榜提交:token 鉴权asyncfunctionsubmitScore(score:number):Promise<boolean>{try{constresp:Response=awaitfetchWithAuth('https://api.cat.example/leaderboard',{method:'POST',body:JSON.stringify({score,achievedAt:Date.now()}),});returnresp.ok;}catch(e){console.warn(`提交失败:${e}`);returnfalse;}}六、降级 LoginWithHuaweiID
6.1 显式登录
// 降级显式登录classAuthService{asyncloginWithHuaweiID():Promise<string|null>{try{constauthentication=accountKit.buildAuthentication({scopes:this.scopes});constresult=awaitauthentication.loginWithHuaweiID({timeout:30000,// 30 秒玩家操作});returnresult.token;}catch(e){console.error(`显式登录失败:${e}`);returnnull;}}}6.2 silentLogin vs 显式
| 方式 | 周时 | 周家操作 | 适用 |
|---|---|---|---|
| silentLogin | 280 ms | 周感 | 默认 |
| LoginWithHuaweiID | 3-30 s | 哓点确认 | 降级 |
引用块:silentLogin 是默认首选,仅当 NOT_SIGNED_IN 才降级显式。显式登录需要玩家操作,破坏沉浸感。
七、单元测试
7.1 silentLogin 测试
// silentLogin 测试import{describe,it,expect}from'@ohs/hypium';exportdefaultfunctionsilentLoginTest(){describe('silentLogin',()=>{it('已登华为账号返回 token',async()=>{constsvc=newAuthService();consttoken:string|null=awaitsvc.silentLogin();expect(token).assertNotEqual(null);expect(token!.length).assertGreaterThan(0);});it('配 timeout 不永久卡死',async()=>{constsvc=newAuthService();conststart:number=Date.now();awaitsvc.silentLogin();constelapsed:number=Date.now()-start;expect(elapsed).assertLessThan(6000);// < 6 秒});});}7.2 缓存测试
// 缓存测试describe('getToken 缓存',()=>{it('二次调用命中缓存',async()=>{constsvc=newAuthService();constt1:string|null=awaitsvc.getToken();conststart:number=Date.now();constt2:string|null=awaitsvc.getToken();constelapsed:number=Date.now()-start;expect(t1).assertEqual(t2);expect(elapsed).assertLessThan(100);// 缓存快});it('过期后刷新',async()=>{constsvc=newAuthService();constt1:string|null=awaitsvc.getToken();svc.tokenExpiry=0;// 强制过期constt2:string|null=awaitsvc.getToken();expect(t2).assertNotEqual(null);});});7.3 异常测试
// 异常分类测试describe('异常处理',()=>{it('网络异常回退本地',async()=>{constsvc=newAuthService();// 模拟网络异常svc.mockNetworkError();consttoken:string|null=awaitsvc.silentLoginSafe();expect(token).assertEqual(null);});it('未登降级显式',async()=>{constsvc=newAuthService();svc.mockNotSignedIn();consttoken:string|null=awaitsvc.silentLoginSafe();expect(token).assertNotEqual(null);// 降级成功});});八、Bug 案例
8.1 未配 timeout
// 错误:未配 timeout,弱网永久卡死constresult=awaitauthentication.silentLogin();修复:配 5 秒 timeout。
8.2 未缓存 token
// 错误:未缓存,首屏 10 API = 10 次登录 = 2.8 秒asyncfetchLeaderboard(){consttoken=awaitthis.silentLogin();returnapi.getLeaderboard(token);}修复:用getToken走缓存。
8.3 异常未分类
// 错误:异常未分类,统一返回 null,玩家困惑catch(e){returnnull;// 不知道是网络问题还是未登}修复:按 code 分流处理。
提示:silentLogin 三件套:5 秒 timeout、token 1 小时缓存、异常分类降级,缺一即卡顿。
九、与游戏流集成
9.1 启动时鉴权
// 启动时鉴权@Componentstruct EntryAbility{asyncaboutToAppear():Promise<void>{consttoken:string|null=awaitauthService.getToken();if(token){awaitsyncCloudSave(currentBoard);awaitloadLeaderboard();}else{this.showOfflineMode();}}}9.2 离线模式
// 离线模式:token 为 null 时本地存档asyncfunctionsaveBoard(board:BoardArray):Promise<void>{consttoken:string|null=awaitauthService.getToken();if(token){awaitsyncCloudSave(board);}else{awaitsaveLocalSave(board);}}9.3 集成性能
| 场景 | 周时 | 备注 |
|---|---|---|
| 启动鉴权+云同步 | 380 ms | 缓存命中 |
| 启动鉴权失败 | 5000 ms | 超时离线 |
| 游戏中提交分数 | 95 ms | 缓存 |
十、总结
10.1 核心要点
- 配置清单:ACCOUNT_KIT 权限、scope、网络、后台四项缺一即失败
- 5 秒 timeout:防弱网永久卡死,超时回退本地
- token 1 小时缓存:preferences 持久化,首屏 10 API 从 2.8s 降到 95ms
- 异常分类降级:NETWORK 回退本地、NOT_SIGNED 降级显式、PERMISSION 引导设置
- silentLogin 优先:默认静默,仅 NOT_SIGNED_IN 才 LoginWithHuaweiID
10.2 性能数据回顾
| 场景 | 周时 | 备注 |
|---|---|---|
| 首次 silentLogin | 280 ms | 已登华为账号 |
| 缓存命中 | 95 ms | 1 小时内 |
| 超时回退 | 5000 ms | 弱网 |
| 显式降级 | 3-30 s | 玩家操作 |
10.3 下一篇预告
下一篇将深入PaymentKit 的支付流程,讲鸿蒙内购支付接入、订单查询、退款处理,与本文鉴权后的付费功能紧密衔接。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- OpenHarmony 适配仓库:GitHub openharmony
- 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
- AccountKit 官方文档:AccountKit Guide
- silentLogin API:静默登录指南
- module.json5 配置:模块配置指南
- preferences 持久化:preferences 指南
- ArkTS 严格模式:ArkTS Guide
- 第 135 篇:UTD 类型使用
- 第 137 篇:PaymentKit 支付流程
- 第 133 篇:FormExtensionAbility 实现
- Hypium 测试:单元测试指南
- HarmonyOS 官方文档:developer.huawei.com