
简介此份Unity接入华为SDKHMS的Demo压缩包面向需要在Unity工程中集成华为账号、游戏、推送等服务的开发者可作为从零接入时的重要工程参照。包内共2000个文件以bin、class、info、meta等编译运行文件为主同时包含jar/dll库依赖、java与C#示例脚本及Android相关配置压缩后约28.82MB便于直接导入Unity项目分析与复用。目前已有1842人学习下载是社区中较受关注的HMS接入样例。资源内含可运行的示例工程与核心调用代码涵盖SDK初始化、登录、权限与构建配置等常见环节目录结构接近真实项目有助于开发者快速定位关键实现并规避版本与脚本后端等坑点。1. Unity接华为SDK到底在接什么一个Demo背后的三类能力做完一个Unity游戏要上架华为应用市场第一个打回理由多半是未接入华为账号登录与支付。去找资料时看到的Unity接入华为SDK demo大多是一个半成品工程或者文档版本的碎片拼图。华为SDK不是单一库而是Account Kit、IAP Kit、Push Kit等一组能力的集合一个Demo通常先把账号、支付、推送三条链路打通。这篇笔记给两类人看刚接手Unity安卓渠道、要把华为SDK接进现有工程的客户端开发以及做过其他渠道SDK、第一次碰HMS生态的从业者。我会按实际操作顺序写环境准备为什么最卡人最小初始化怎么跑通登录支付推送的落地代码以及一份从编译期到运行期的避坑清单。2. 接华为SDK前的环境准备账号体系、包名与证书指纹三件套在Unity里接华为SDK最容易劝退人的其实是第一个小时你以为马上要写代码实际上要先在AppGallery ConnectAGC控制台上把账号、应用、证书全部配齐。这三样东西没对齐后面就算Unity工程代码全对跑起来也是要么编译失败要么运行时一启动就退出。我把这章拆成三个小节按顺序做一次就能绕开最基础的那批坑。2.1 在AppGallery Connect创建应用包名决定一切华为SDK的服务端是跟着包名走的。你在AGC控制台创建应用时填的包名必须和Unity工程最终打包的Android包名完全一致一个字母都不能差。常见做法是先定包名再建应用而不是反过来。Unity里包名在Player Settings——Android——Other Settings——Package Name里修改我一般会在工程刚创建时就把这个值写成com.company.gamename这样的格式避免后期改包名导致AGC侧全部配置作废。创建应用的入口是AppGallery Connect控制台的我的应用页面选择应用类型为游戏还是应用。这里的选择会影响后续审核流程游戏类应用要额外提供版号和软著信息。地区选择也要注意国内发布选中国站海外发布选对应海外站点不同站点的华为SDK配置不互通。创建过程中要求填证书指纹这就用到本机的keystore了。如果你还没有正式签名证书可以先用Unity自动生成的debug keystore顶着但到提审阶段还得换正式证书指纹也要跟着改。我的建议是第一天就生成正式签名证书后续所有环节都用它省得返工。生成证书并查看指纹的命令如下keytool -genkeypair -v \ -keystore ./mygame.keystore \ -alias mygame \ -keyalg RSA -keysize 2048 -validity 10000 \ -storepass your_store_password \ -keypass your_key_password \ -dname CNMyGame, OUDev, OCompany, LCity, SProvince, CCN这条命令生成一个RSA签名证书validity 10000天约等于27年对游戏发布足够。keytool生成的密码要记牢Unity打包、AGC配置指纹、换电脑打包都要用到丢了只能重新生成证书换签名代价非常大。生成后用下面命令查看SHA-256指纹把整串指纹填到AGC应用的证书指纹输入框里。keytool -list -v -keystore ./mygame.keystore -alias mygame -storepass your_store_password | grep SHA256:这里有个新手容易忽略的细节Unity里keystore在Player Settings——Publishing Settings里填写Unity打包时用这个证书签名APK。AGC侧证书指纹的作用是校验APK签名是否合法同时参与运行时鉴权。如果两边指纹不一致登录时大概率报错而且错误码不是一眼能看懂的那种。提示证书指纹、包名、agconnect-services.json三者必须来自同一个AGC应用混用任何一个都会在运行时以奇怪的错误码暴露出来。2.2 SHA-256证书指纹与agconnect-services.json配置AGC应用创建完成后在开发——常规开发配置页面里有证书指纹的填写入口。把上一步keytool查出来的SHA256整串填进去华为控制台会做归一化带不带冒号都能识别。填完指纹后在同一页面下载agconnect-services.json文件。这个JSON是华为SDK的身份证明包含应用ID、产品ID、API Key等一整套运行时鉴权信息。拿到文件后放到Unity工程的Assets/Plugins/Android/res/values/目录下。注意如果Plugins/Android下没有res/values这个层级自己新建目录名必须是这个名字不能换路径。HMS Core的Unity插件在构建时会读取这个路径下的json放错地方会导致工程能编译但运行时初始化失败而且报错非常隐蔽往往是某个Kit的静态方法抛NullPointerException。这个JSON是分环境的。如果你的Unity游戏同时出华为渠道版和其他安卓渠道版需要根据构建目标切换json文件。常见做法是在构建脚本里按渠道复制或者用Unity的预定义符号控制文件导入行为。不要让多条渠道的json同时存在于工程里因为后导入的文件会覆盖先导入的而Unity不会给你任何提示。2.3 Unity工程的Android导出配置JDK/SDK/签名华为SDK对Unity工程的Android基础环境有硬性要求minSdkVersion不低于21targetSdkVersion一般跟随Unity版本默认值但要高于华为应用市场当前要求的最低版本。在Player Settings——Other Settings里把Minimum API Level设为Android 5.0API 21以上。JDK版本方面Unity 2020以后自带OpenJDK可以直接用。如果你自己电脑装过其他JDK构建时Unity可能优先使用系统JAVA_HOME导致编译报class file version错误这时在Player Settings的Android配置里勾选Use Unitys embedded JDK和Use Unitys embedded SDK即可。另外Scripting Backend建议选IL2CPP华为审核更认可IL2CPP构建的包体而且华为SDK的Java层和C#层互调在IL2CPP下更稳定Mono编译的包跑HMS偶尔会出现线程相关的奇怪问题。签名配置和证书指纹是联动的。Publishing Settings里选好keystore、alias和密码后Unity每次打包都用它签名。这里有一个坑如果你曾经用debug keystore打过包之后再换正式证书手机上必须先卸载旧包再安装否则系统会因为签名不一致拒绝覆盖安装报INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES。另外AndroidManifest能不改就不改HMS插件通常自动合并权限。如果确实需要自定义Manifest在勾选Custom Main Manifest之前先想清楚写错会引起权限合并冲突反而比不写更麻烦。3. 把HMS Core装进Unity工程导入配置与最小初始化环境配置完成之后就是真正的导入操作。你需要在Unity工程里把华为SDK装进去并跑通最小初始化。我给两种接入方式的选择逻辑、配置文件落位的检查方法以及一段能验证初始化成功的C#代码。做完这章你应该能在设备日志里看到一条清晰的初始化记录。3.1 两种接入方式Unity Plugin包 vs 手动AAR华为官方维护了HMS Core Unity PluginUnity Asset Store可以搜到也可以从华为开发者联盟的Unity插件页面获取。插件按Kit模块化导入比如只需要账号和支付只导入Account和IAP两个模块。另一种方式是把华为SDK的AAR文件放进Assets/Plugins/Android自己写Java桥接代码再通过Unity的AndroidJavaObject做互调。对多数Unity项目我建议用官方Plugin不需要为每个Kit维护一份Java桥。华为SDK的Java接口变更频繁Plugin会适配主流Unity版本的Android构建系统。手动AAR适合已有成熟Android代码、只需在Unity复用的团队但你要自己处理Gradle依赖和Manifest合并一行写错就编译不过。官方Plugin导入后工程里应当能看到如下目录结构Assets/Plugins/Android/ ├─ res/values/agconnect-services.json ├─ AndroidManifest.xml # 插件自动合并 └─ libs/ # 手动集成时AAR放这里这个布局是Unity Android构建的标准输入。Plugin导入后会把AAR依赖加进构建产物你只需要确认res/values下的json文件在位。手动集成时AAR要自己管理同时必须在mainTemplate.gradle里加flatDir和implementation fileTree声明否则gradle找不到这些库文件构建会报依赖解析失败。3.2 配置文件放置与AndroidManifest合并检查导入插件后的第一步是检查生成的AndroidManifest。Unity把Player Settings和插件库的Manifest合并最终构建产物在Temp目录或导出工程里可以直接查看。如果Manifest缺少HMS Core需要的权限比如INTERNET、READ_PHONE_STATE初始化会静默失败登录支付都会表现出看起来没反应的状态。我检查Manifest的习惯是让Unity导出一次Gradle工程在导出的unityLibrary/src/main/AndroidManifest.xml里搜Huawei、hms、agconnect关键词确认插件是否参与合并。搜不到就是插件没装好需要回到导入步骤检查包体完整度。另一个细节是application标签的name属性。部分HMS Kit需要自定义Application类Unity默认没有这个类Plugin会通过Manifest合并注入。如果你自己开了Custom Main Manifest并覆盖了application name插件的初始化逻辑会被冲掉表现是包能装上但SDK功能全部不可用而且没有明显的崩溃日志。排查这类问题最快的方式就是打开最终APK反查Manifest不要在Unity工程文件里凭感觉猜。注意确认插件合并成功后再往下走。在Manifest缺失权限的状态下调试登录浪费的时间远比你想象的多。3.3 最小初始化代码HMSService与启动检查配置做完后用最小初始化代码验证SDK是否真的能用。这里用官方Plugin的C# API不需要手写AndroidJavaObject。using Huawei.Hms.Core; using UnityEngine; public class HmsManager : MonoBehaviour { void Awake() { // 检查设备是否支持HMS Core华为手机正常情况下返回true if (!HMSService.Exists()) { Debug.LogWarning(当前设备不支持HMS Core降级走游客模式); return; } // 初始化HMS服务框架加载agconnect-services.json配置 HMSService.Initialize(); Debug.Log(HMS Core 初始化调用完成); } }逻辑分两层HMSService.Exists()检测设备上是否装了HMS Core APK以及SDK版本是否满足最低要求。华为手机出厂自带HMS Core非华为手机如果没有安装这个调用返回false游戏必须降级到不依赖华为能力的模式。第二层Initialize()把agconnect-services.json加载进来初始化各Kit的公共依赖。注意这个初始化是异步的调用完不能立刻使用Account Kit或Push Kit后续每个Kit使用前要单独做能力校验。这里不需要传额外参数所有运行时信息都来自json配置。到这里如果设备日志里能看到初始化调用完成且没有异常抛出说明接入环境已经打通可以接第一项实际功能了。4. 从Demo到可用账号登录与支付的落地代码初始化跑通后进入实际业务接入。这一章把账号登录、应用内支付、推送Token这三个最常见的华为SDK能力写透。每段代码都是可以抄进Unity工程改参数就能跑的Demo级代码但代码背后的设计逻辑我会讲清楚因为直接抄代码的人最容易在回调时机和线程切换上翻车。4.1 华为账号登录SignIn与静默登录的取舍华为账号登录的典型交互是游戏启动时先尝试静默登录如果玩家之前授权过直接拿到身份信息如果静默登录失败再拉起华为账号授权页。这个流程的代码如下using Huawei.Hms.Account; using Huawei.Hms.Support; using Huawei.Hms.Core; using UnityEngine; public class HuaweiLogin : MonoBehaviour { private AccountAuthService authService; void Start() { // 构建华为账号授权参数请求openid、昵称和头像 HuaweiIdAuthParams authParams new HuaweiIdAuthParamsHelper() .SetIdToken() .SetProfile() .SetAuthorizationCode() .CreateParams(); authService AccountAuthManager.GetService(authParams); TrySilentSignIn(); } void TrySilentSignIn() { authService.SignIn() .AddOnSuccessListener(user { Debug.Log(静默登录成功: user.DisplayName , uid user.Uid); // 把authorizationCode发给游戏服务器由服务端换取access_token }) .AddOnFailureListener(e { Debug.Log(string.Format(静默登录失败: {0}, {1}, e.ErrorCode, e.ErrorMessage)); // 用户需要重新授权拉起华为账号授权页 authService.GetSignInIntent() .AddOnSuccessListener(intent { // 通过Unity的Activity回调机制拉起授权页面 }); }); } }静默登录的意义在于无感登录但有限制如果用户明确拒绝过授权静默登录会持续失败这时必须走显式授权流程。上面代码中GetSignInIntent()返回的是一个IntentUnity侧需要通过StartActivityForResult机制把它拉起官方Plugin封装了对应接口在AndroidActivityCallBack里接收返回结果。HuaweiIdAuthParamsHelper里可叠加的Scope决定了你能拿到什么信息。SetIdToken()拿JWT格式的ID Token适合服务端快速验证玩家身份。SetAuthorizationCode()拿授权码需要服务端配合OAuth 2.0流程换access_token。如果只做客户端展示不需要服务端业务只保留SetProfile()拿昵称头像就够。不需要的信息就不要请求华为审核会以过度申请权限打回。4.2 内购接入查询商品、拉起支付、发货回调华为应用内支付的复杂度比登录高一个档次因为涉及商品管理、支付回调、发货确认、防重放四件事。客户端通常分三步查询商品、拉起支付、处理支付结果。先看查询商品的代码using Huawei.Hms.Iap.Api; using Huawei.Hms.Iap.Entity; using Huawei.Hms.Core; using System.Collections.Generic; using UnityEngine; public class HuaweiIap : MonoBehaviour { private IIapClient iapClient; void Start() { iapClient IapManager.GetIapClient(); QueryProducts(); } void QueryProducts() { // 查询非消耗型商品比如去广告、解锁章节 ProductInfoReq request new ProductInfoReq(); request.PriceType ProductType.IN_APP_NONCONSUMABLE; request.ProductIds new Liststring() { remove_ads, unlock_story }; iapClient.QueryProductInfo(request) .AddOnSuccessListener(result { foreach (ProductInfo info in result.ProductInfoList) { Debug.Log(string.Format(商品: {0}, 价格: {1} {2}, info.ProductName, info.ProductPrice, info.Currency)); } }) .AddOnFailureListener(e { Debug.Log(查询商品失败: e.ErrorCode); }); } }PriceType是华为IAP的商品类型枚举IN_APP_CONSUMABLE消耗型比如金币道具IN_APP_NONCONSUMABLE非消耗型比如去广告IN_APP_SUBSCRIPTION订阅型。商品在AGC后台创建时必须和客户端PriceType一致否则查询结果为空。ProductIds必须在AGC后台商品管理先创建好传不存在的ID不会报错但查询结果列表里会缺失。拉起支付的代码如下这段是坑最密集的地方因为支付结果是异步回调而且理论上可能重复回调void PurchaseProduct(string productId) { // 构造购买请求传入商品ID和开发者自定义的payload PurchaseIntentReq request new PurchaseIntentReq(); request.ProductId productId; request.PriceType ProductType.IN_APP_NONCONSUMABLE; request.DeveloperPayload server_timestamp_here; iapClient.CreatePurchaseIntent(request) .AddOnSuccessListener(result { // result返回支付Intent拉起华为支付页面 StartActivityForResult(result.PurchaseIntent); }) .AddOnFailureListener(e { Debug.Log(拉起支付失败: e.ErrorCode); }); }DeveloperPayload值得多说一句华为支付的成功结果里会原样带回这个字符串服务端可以拿它做幂等判断防止同一笔购买被重复发货。常见做法是把用户ID、时间戳和随机数拼起来做哈希服务端发货前校验这个负载是否已处理过。很多团队Demo阶段省掉这步上线后遇到支付回调重放就多发道具属于事故级的血泪教训。另外支付成功后客户端不要直接发货。正确姿势是收到PurchaseResult里的PurchaseToken连同订单号发给服务器服务器调用华为IAP验签接口确认订单真实、状态是已购买且未消费再发货。4.3 推送Token让推送不再悬空推送是三个模块里最简单的但有一个容易踩空的点Push Kit的Token获取依赖推送开关打开否则返回空值。下面代码把开推送和取Token串起来using Huawei.Hms.Push; using Huawei.Hms.Core; using UnityEngine; public class HuaweiPush : MonoBehaviour { void Start() { // 打开推送通道结果通过回调返回 HmsMessaging messaging HmsMessaging.GetInstance(); messaging.TurnOnPush(new TaskCompletionCallbacks()); // 获取推送TokenToken是推送消息到达设备的唯一凭据 string token PushTokenGetter.GetToken(); if (!string.IsNullOrEmpty(token)) { Debug.Log(推送Token: token); // 上报给游戏服务器用于运营推送 } else { Debug.LogWarning(Token为空推送未开启); } } }PushTokenGetter.GetToken()本身是同步方法但返回结果受TurnOnPush异步结果影响所以实际工程应该在TurnOnPush的onSuccess回调里再取Token否则很可能拿到空字符串。Token不是永久有效的华为不保证token长期不变游戏每次启动都应该重新获取并上报服务端做覆盖写入。推送测试也有人说玄学其实是机制不同。华为Push Kit控制台提供推送测试入口可以向指定设备发一条测试推送前提是这台设备运行过App且上报过有效Token。如果你在测试机上收不到推送先查Token是否为空再查AGC控制台的消息状态多数是配置问题不是SDK问题。5. 华为SDK接入的避坑清单从编译失败到线上闪退这一章是排障实战。我挑五类最常见的Unity接华为SDK问题按现象——原因——解决写清楚。这些问题覆盖从导入SDK到上线运营的完整时间线每一类都是我在真实项目里盯过至少一次的情况。5.1 现象导入SDK后Unity工程直接构建失败Unity构建报错典型的是Unable to merge manifest或AAR metadata类。大概率不是代码问题而是Manifest合并冲突。Unity 2019之后的Android构建对Manifest合并策略更严格多个库声明相同权限但级别不同gradle会直接中断构建。我处理过的案例里最常见的触发点是工程里同时有华为SDK和另一个渠道SDK它们都带了com.google.android.gms的某个依赖但版本不同。Gradle合并时如果不指定统一版本冲突就会在manifest merge阶段爆出来。解决方式先把工程里所有Android库统一升级并对齐到华为SDK要求的版本或者在mainTemplate.gradle里显式写resolutionStrategy把冲突版本强制锁到某一个。另一个容易被忽略的原因是Unity的Gradle模板太老。Unity 2019到2021的模板差异很大如果你从老版本工程升级上来mainTemplate.gradle可能还留着旧的依赖写法华为SDK要求的AGP版本在旧模板下会报MethodTooLargeException这类构建崩溃重新生成模板通常能根治。5.2 现象运行时找不到HmsInstance或Agconnect类APK装到真机后打开直接闪退logcat里有ClassNotFoundException指向com.huawei.hms或com.huawei.agconnect包。这说明运行时缺少华为SDK的类但编译却通过了这种情况最迷惑人。最常见原因是混淆配置。Unity构建开启Minify后HMS的类如果没被keep住Release包运行时就会找不到类。解决方式是在proguard-user.txt里补华为SDK的keep规则华为官方文档有对应配置。这里有一个备份排查角度用解压工具打开打的Release包在classes.dex里搜com/huawei/hms路径搜不到说明这个包压根没打进HMS代码问题不在混淆而在依赖导入环节。另外Unity的Managed Stripping Level开得过高时反射调用的类会被误剪。HMS不少接口内部用了反射关掉Managed Stripping Level或者在link.xml里加保护才能解决这一步比配proguard更隐蔽也更难查。5.3 现象登录拉起一闪而过返回错误码907135000或52499300华为账号登录拉起授权页后一闪而过或直接返回错误码。907135000属于账号服务异常最常见的是AGC证书指纹和APK签名不一致或者agconnect-services.json是从另一个应用下载的。52499300通常是scope描述无效或授权参数设置错误。解决方式先核对证书指纹、json、包名三件套然后检查HuaweiIdAuthParamsHelper里是否请求了未审核通过的scope。华为账号服务在授权前会检查scope权限未审核通过的自定义scope会直接失败。我的排查习惯是先把Demo里的scope清理到最小集合只留profile和openid走通后再逐步加每加一个重新测试一次避免多个因素同时出问题的时候没法定位。5.4 现象支付成功但游戏不发道具客户端确实收到支付成功回调但道具就是不到账。问题几乎都出在发货链路。华为IAP的正确流程是客户端收到成功回调把PurchaseToken和订单号发给服务器服务器调华为IAP查询或验签接口确认订单真实、状态是已购买且未消费再发货并标记订单完成。Demo通常简化为客户端到账即发货这是提审和线上运营的雷区因为攻击者可以伪造回调。解决方式是服务端验签后发货。客户端收到Success回调后先展示支付成功等待发货同时把订单信息异步上报不要立刻给道具。服务端验签时注意顺序先按orderId查华为服务端拿到真实订单状态确认无误再发货。不要用客户端传来的PurchaseToken直接发货要以自己服务端查询到的状态为准。5.5 现象非华为手机上初始化就崩游戏在华为手机上一切正常换到小米、OPPO上直接崩溃或者初始化静默失败。原因在于HMS Core SDK在工作时需要设备上安装HMS Core APK非华为手机出厂不带这个组件。解决方式有两种。第一种是用华为提供的HMS Core APK分发能力SDK会引导用户安装。第二种是业务降级在HMSService.Exists()返回false时走不依赖HMS的逻辑。很多游戏把华为渠道版和其他安卓版分开出包华为渠道版从华为应用市场安装时设备上必然有HMS Core这类问题在华为渠道版本上其实不常出现。如果你做了全渠道版本想在各种安卓设备上跑就必须做降级判断并且要把这个降级分支写进测试用例否则哪天切到非华为设备就翻车。6. 验证与进阶把Demo做成能上架的模块最后给一套验证方法和两个进阶习惯。从Demo到能上架差的不是代码健壮性是一套能自证的检查逻辑。6.1 一张自检表从Demo到发布的最小检查项上线前至少过一遍这张表我每次发版都会和QA逐项勾检查项验证方法通过标准包名一致性AGC后台包名 vs Unity Player Settings包名 vs 已安装APK包名三者完全一致证书指纹Release包用正式keystore签名安装对比SHA-256与AGC保存的指纹一致登录链路真机走静默登录显式登录拿到uid和头像昵称支付链路真机购买后服务端能收到订单且验签通过发货在5秒内完成初始化降级卸载HMS Core后启动游戏走游客模式不崩溃混淆检查开启Minify构建Release登录支付各跑通一遍不出现ClassNotFoundException表中的每一项都对应前面章节踩过的坑。我见过Demo跑通就上线发布、第一周就被华为审核打回的团队原因通常是证书指纹不一致或支付流程缺服务端验签。自检表不是形式是发布前的安全网。6.2 一个习惯把SDK版本和异常码打进日志最后分享一个很小的习惯但它救过我很多次。工程里维护一个静态类记录当前华为SDK版本号、AGC应用ID、Unity版本初始化时输出到日志。线上反馈问题先让用户提供日志里的版本信息再判断是SDK太旧还是配置串了。public static class HmsBuildInfo { // 每次升级华为SDK插件后同步更新 public const string SdkVersion 6.9.0.300; public const string AGCAppId your_app_id_from_json; public static void LogAll() { Debug.Log(string.Format(HMS SDK: {0}, AGCAppId: {1}, Unity: {2}, SdkVersion, AGCAppId, Application.unityVersion)); } }很多线上问题靠这行日志定位。比如玩家手机上的HMS Core版本过旧导致登录失败但游戏没有提示升级玩家就会觉得点了没反应。日志里带上版本信息之后客服可以把问题归到不同的原因模板减少盲目排查。接入华为SDK技术上不复杂复杂度全在生态约束里。包名、指纹、权限、验签、降级每一个都是Demo里看不见、上线绕不开的内容。我的习惯是每次接新渠道SDK前先把自检表抄一遍对照着做等收到审核通过通知的那一刻才觉得这些功夫花得值。希望帮到你。本文还有配套的精品资源点击获取