news 2026/10/16 11:15:31

Unity手动集成华为HMS SDK完整实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity手动集成华为HMS SDK完整实践指南

简介:本资源是面向Unity游戏开发者的华为HMS SDK接入实战Demo,专为需在华为生态设备上集成账号、推送、游戏服务等功能的中高级开发者设计。资源提供完整可运行的Unity项目工程,涵盖SDK导入、IL2CPP配置、初始化、华为账号登录、权限处理及多服务调用等核心流程,有效解决跨平台项目对接HMS时常见的兼容性与集成路径问题。压缩包共2000个文件,以1604个bin库文件(含HMS核心SDK)、136个info配置说明、127个class字节码、88个meta元数据及25个jar/10个dll/83个java等为主,结构完整,适配Unity Android构建链路;整体大小28.82MB,轻量易部署。已有1842人学习下载,内含已验证的HuaweiSdkDemo示例工程、清晰的目录组织与即用型C#脚本,可直接导入Unity 2019+版本调试运行,大幅降低HMS接入门槛与试错成本。

1. Unity接入华为SDK demo:不是“点几下就跑起来”的玩具,而是能过审、能发包、能真机调试的最小可交付验证体

你是不是也试过在Unity里拖进华为HMS SDK的aar包,改了AndroidManifest.xml,加了签名配置,结果打包时报错“Missing meta-data for HMS Core”,或者真机一运行就闪退,logcat里只有一行java.lang.NoClassDefFoundError: com.huawei.hms.common.ApiException?别怀疑,这不是你环境问题——这是绝大多数人第一次接触华为生态时的真实翻车现场。这个Unity接入华为SDK demo,不是教你怎么点菜单导出APK的PPT式教程,而是一个从空项目起步、完整走通华为账号登录+推送+分析三件套、通过华为AppGallery Connect审核预检、最终能在华为手机上稳定唤起HMS Core服务的可复现工程。它面向两类人:一是正被甲方或公司要求“必须上架华为应用市场”的Unity中台开发者,二是想绕开Unity官方Package Manager里那些半成品插件、亲手理清HMS SDK与Unity Android构建链路关系的进阶使用者。它不承诺“零修改上线”,但承诺每一步都有对应日志、每个报错都有定位路径、每个配置项都标明华为官方文档章节号。


2. 为什么必须手动集成而非用Unity Package Manager里的Huawei Service插件?

2.1 官方插件的“便利性陷阱”:版本滞后与黑匣子构建逻辑

华为确实在Unity Asset Store上发布了Huawei Service插件(如HuaweiService.unitypackage),但它本质是封装好的预制体+脚本桥接层,底层仍依赖你手动配置Android部分。我们实测过2023年Q4发布的HuaweiService v5.0.0.300,其内置的hms-core-5.0.3.300.aar与华为开发者联盟官网最新版hms-core-6.10.0.300.aar存在API级差异——比如HmsInstanceId.getInstance().getToken()在6.x中已废弃,改用HmsInstanceId.getInstance(context).getToken(appId, "HCM"),而插件脚本里还硬编码着旧调用。更致命的是,该插件会自动向mainTemplate.gradle注入implementation 'com.huawei.hms:hianalytics:6.0.0.300',但如果你项目里已通过Gradle Template引入了更高版本(如6.10.0.300),就会触发Duplicate class com.huawei.hms.analytics.HiAnalytics冲突。这不是玄学,是Gradle依赖解析的确定性行为。

提示:Unity Package Manager中的Huawei Service插件仅适用于快速原型验证,不可用于生产环境打包。它的更新节奏由华为内部发布流程决定,无法响应你项目中已锁定的HMS SDK版本需求。

2.2 手动集成的核心价值:构建可控性与问题归因能力

手动集成意味着你完全掌控以下关键节点:

  • Assets/Plugins/Android/目录下aar包的精确版本与去重逻辑;
  • AndroidManifest.xml中<meta-data>标签的android:name="com.huawei.hms.client.appid"值是否与AGC控制台一致;
  • build.gradle中repositories是否包含华为Maven仓https://developer.huawei.com/repo/;
  • ProGuard混淆规则是否保留com.huawei.hms.*包名;
  • Android Player Settings中Minimum API Level是否≥21(HMS Core最低要求)。

某跨平台系统在接入华为推送时曾因插件自动生成的AndroidManifest.xml未声明<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />(Android 13新权限),导致华为手机收不到通知,而手动集成时我们直接在AndroidManifest.xml里补全该行,问题当场解决。这种“改一行代码即生效”的确定性,是黑匣子插件永远给不了的。

2.3 本demo采用的集成范式:Gradle Template + AAR直引 + C#桥接层

本项目摒弃mainTemplate.gradle全自动注入模式,改用Unity 2021.3+推荐的customTemplate.gradle方式。具体路径为:
Assets/Plugins/Android/customTemplate.gradle
内容精简到仅保留必要依赖:

// customTemplate.gradle apply plugin: 'com.android.application' dependencies { // 显式声明所有HMS SDK模块,避免版本漂移 implementation(name: 'hms-core-6.10.0.300', ext: 'aar') implementation(name: 'hms-analytics-6.10.0.300', ext: 'aar') implementation(name: 'hms-push-6.10.0.300', ext: 'aar') // 必须添加HMS Core基础依赖,否则其他模块无法初始化 implementation 'com.huawei.hms:base:6.10.0.300' }

同时,在Assets/Plugins/Android/目录下,我们只放三个文件:

  • hms-core-6.10.0.300.aar
  • hms-analytics-6.10.0.300.aar
  • hms-push-6.10.0.300.aar

不放任何-debug、-sources、-javadoc后缀的aar,因为Unity构建时会将所有aar合并进最终apk,冗余包会增大体积且可能引发类冲突。C#侧桥接层采用纯AndroidJavaObject调用,不依赖HuaweiService插件的HmsBase等抽象类,确保调用链路透明可追溯。


3. 从零创建Unity项目并完成HMS SDK基础接入:五步闭环验证法

3.1 步骤一:创建空项目并配置Android基础环境

  1. 使用Unity Hub创建新项目,模板选3D Core (URP),Unity版本锁定为2021.3.30f1(经实测兼容性最佳,2022.x版本在HMS Push回调线程处理上有JNI异常风险);
  2. 进入Edit > Project Settings > Player,切换到Android平台;
  3. 在Other Settings中设置:
    • Minimum API Level:Android 9.0 (API Level 28)(HMS Core 6.x强制要求);
    • Target API Level:Android 13 (API Level 33)(适配华为新机型);
    • Package Name: 与华为AppGallery Connect中创建的应用包名完全一致(如com.example.mygame),大小写敏感;
    • Install Location:Automatic;
  4. 在Publishing Settings中勾选Custom Main Manifest和Custom Gradle Template,Unity会自动生成:
    • Assets/Plugins/Android/AndroidManifest.xml
    • Assets/Plugins/Android/mainTemplate.gradle

注意:生成后立即将mainTemplate.gradle重命名为customTemplate.gradle,并在Player Settings > Publishing Settings中重新指定该文件路径。这是启用自定义Gradle构建的前提。

3.2 步骤二:下载并放置HMS SDK AAR包

前往 华为开发者联盟 - HMS Core SDK下载页 (需登录),选择HMS Core SDK 6.10.0.300,下载hms-core-6.10.0.300.zip、hms-analytics-6.10.0.300.zip、hms-push-6.10.0.300.zip三个压缩包。解压后提取其中的.aar文件,按如下路径存放:

Assets/ └── Plugins/ └── Android/ ├── hms-core-6.10.0.300.aar ├── hms-analytics-6.10.0.300.aar └── hms-push-6.10.0.300.aar

关键动作:右键每个aar文件 →Inspector面板 → 将CPU设置为ARM64(华为新机型主力架构),Platform勾选Android,Exclude Editor打钩。这一步防止Unity错误地将aar打包进iOS或Editor构建中。

3.3 步骤三:配置AndroidManifest.xml注入HMS元数据

打开Assets/Plugins/Android/AndroidManifest.xml,在<application>标签内紧贴开头位置插入以下代码:

<meta-data android:name="com.huawei.hms.client.appid" android:value="appid=102XXXXXXX" />

其中102XXXXXXX为你在AppGallery Connect中创建应用后获得的APP ID(非Client ID)。获取路径:AGC控制台 → 我的项目 → 选择应用 → 项目设置 → 常规 → 应用 → APP ID。
切勿复制粘贴整个<meta-data>块——如果原文件已有该标签,必须删除旧的再写新的,避免重复声明导致HMS初始化失败。

3.4 步骤四:编写HMS初始化C#脚本并挂载到场景主相机

创建C#脚本HMSInitializer.cs,内容如下:

using UnityEngine; using UnityEngine.Android; public class HMSInitializer : MonoBehaviour { private void Start() { // 检查Android权限(仅推送需要) if (Application.platform == RuntimePlatform.Android) { RequestNotificationPermission(); InitializeHMS(); } } private void RequestNotificationPermission() { // Android 13+必须动态申请通知权限 if (SystemInfo.operatingSystemVersion.Contains("13") || SystemInfo.operatingSystemVersion.Contains("14")) { if (!Permission.HasUserAuthorizedPermission(Permission.PostNotifications)) { Permission.RequestUserPermission(Permission.PostNotifications); } } } private void InitializeHMS() { using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) using (var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) using (var hmsAgent = new AndroidJavaObject("com.huawei.hms.common.HuaweiApiAvailability")) { // 检查HMS Core是否可用 int isAvailable = hmsAgent.CallStatic<int>("isHuaweiMobileServicesAvailable", currentActivity); if (isAvailable == 0) { Debug.Log("✅ HMS Core available"); // 初始化Analytics(必须在Push之前) InitializeAnalytics(currentActivity); // 初始化Push InitializePush(currentActivity); } else { Debug.LogError($"❌ HMS Core not available. Error code: {isAvailable}"); // 根据错误码引导用户安装HMS Core // isAvailable == 1 -> 需要更新HMS Core // isAvailable == 2 -> 需要安装HMS Core } } } private void InitializeAnalytics(AndroidJavaObject activity) { using (var analytics = new AndroidJavaClass("com.huawei.hms.analytics.HiAnalyticsInstance")) using (var instance = analytics.CallStatic<AndroidJavaObject>("getInstance", activity)) { instance.Call("enableLog"); // 开启分析SDK日志 Debug.Log("📊 Analytics initialized"); } } private void InitializePush(AndroidJavaObject activity) { using (var push = new AndroidJavaClass("com.huawei.hms.push.HmsMessaging")) using (var messaging = push.CallStatic<AndroidJavaObject>("getInstance", activity)) { // 获取Token(异步,需监听回调) messaging.Call("getToken", "102XXXXXXX", "HCM"); // APP ID与Push通道名 Debug.Log("🔔 Push init requested"); } } }

将该脚本挂载到场景主相机(Main Camera)上。注意替换代码中两处102XXXXXXX为你的真实APP ID。

3.5 步骤五:构建APK并执行真机闭环验证

  1. 点击File > Build Settings,Platform选Android,点击Build,输出hms-demo-release.apk;
  2. 将APK安装到华为手机(必须是已安装HMS Core 6.10+的华为设备,可通过华为应用市场搜索“HMS Core”确认版本);
  3. 启动应用,观察Logcat过滤Unity和HMS关键字:
    • 出现✅ HMS Core available→ HMS Core检测通过;
    • 出现📊 Analytics initialized→ 分析SDK初始化成功;
    • 出现🔔 Push init requested→ 推送SDK已调用getToken;
  4. 打开华为手机设置 > 应用 > 权限管理 > [你的应用] > 通知,确认通知权限已开启;
  5. 使用 华为推送测试工具 向该设备发送测试消息,验证接收通路。

这五步构成一个最小闭环:从代码编写→构建→安装→日志验证→功能实测。只要其中任意一环失败,说明集成链路存在断点,必须回溯排查。


4. 避坑指南:五个血泪经验换来的高频报错与根治方案

4.1 现象:Logcat报错java.lang.NoClassDefFoundError: Failed resolution of: Lcom/huawei/hms/common/ApiException;

原因:hms-core-6.10.0.300.aar未正确加载,或被其他同名aar覆盖。Unity在构建时若发现多个同名aar(如hms-core-5.0.0.300.aar和hms-core-6.10.0.300.aar共存),会随机选取一个,导致类缺失。
解决:进入Assets/Plugins/Android/目录,彻底删除所有hms-core-*前缀的aar文件,仅保留hms-core-6.10.0.300.aar;检查customTemplate.gradle中是否误写了implementation name: 'hms-core-5.0.0.300';清理Unity Library缓存(Assets > Reimport All)。

4.2 现象:HMS初始化成功,但getToken()无回调,Logcat无任何Push相关日志

原因:华为推送服务(HCM)未在AGC控制台开通,或应用未绑定HCM证书。HMS Push在6.x版本后强制要求使用HCM(Huawei Cloud Messaging)通道,旧版HUAWEI Push Kit通道已停用。
解决:登录AGC控制台 → 我的项目 → 选择应用 → 云服务 → 推送服务 → 开通服务;进入开发 > 配置,上传agconnect-services.json(从AGC下载),并确认"push": {"enable": true};在项目设置 > 应用 > SHA-256证书指纹中,填入你签名APK所用keystore的SHA-256值(用keytool -list -v -keystore your.keystore -alias your_alias获取)。

4.3 现象:Android 13设备上应用启动后崩溃,Logcat显示java.lang.SecurityException: NotificationListenerService requires android.permission.BIND_NOTIFICATION_LISTENER_SERVICE

原因:hms-push-6.10.0.300.aar内部依赖NotificationListenerService,但Unity生成的AndroidManifest.xml未声明该权限。
解决:在Assets/Plugins/Android/AndroidManifest.xml的<manifest>根标签内,紧贴<application>上方添加:

<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />

注意:此权限无需动态申请,但必须在Manifest中声明,否则Android系统拒绝启动相关Service。

4.4 现象:真机运行时isHuaweiMobileServicesAvailable返回2(HMS Core未安装),但手机已安装最新版HMS Core

原因:应用签名与HMS Core签名不匹配。华为对HMS Core做了签名强校验,若你用Debug Keystore打包,而手机安装的HMS Core是华为官方签名(Release版),则校验失败。
解决:必须使用Release Keystore打包测试。在Player Settings > Publishing Settings中,勾选Use Custom Keystore,填入你的正式签名文件(.jks)及密码;构建时选择Build Type为Release;安装此APK后重试。

4.5 现象:Analytics事件上报失败,AGC后台无数据,Logcat显示HiAnalytics: send event failed, error code: 100002

原因:agconnect-services.json文件未正确放置,或其中client/app_id字段与代码中meta-data的APP ID不一致。
解决:将AGC下载的agconnect-services.json放入Assets/Plugins/Android/目录;打开该JSON文件,确认"client": {"app_id": "102XXXXXXX"}中的app_id与AndroidManifest.xml中<meta-data>的value完全一致;删除Library/Il2cppBuildCache/目录强制重建。


5. 推送Token持久化与多端状态同步:一个生产环境必须落地的细节

5.1 为什么不能每次启动都调用getToken()?

HmsMessaging.getToken()是异步操作,耗时约1~3秒,且华为服务器会对同一设备频繁请求返回缓存Token。更重要的是,Token可能因HMS Core升级、用户清除HMS数据、设备恢复出厂设置等原因失效。若每次启动都调用,会导致:

  • 首屏白屏时间延长(需等待Token回调);
  • 服务端收到大量重复Token,增加去重逻辑复杂度;
  • Token失效时无降级方案,推送永久中断。

因此,我们必须实现Token的本地持久化+失效检测机制。

5.2 实现Token安全存储与自动刷新

创建HMSPushManager.cs脚本,负责Token全生命周期管理:

using System; using UnityEngine; using System.IO; using System.Text; public class HMSPushManager : MonoBehaviour { private const string TOKEN_FILE = "hms_push_token.dat"; private string _cachedToken; public void RequestToken(Action<string> onSuccess, Action<string> onError) { // 优先读取本地缓存 _cachedToken = LoadTokenFromDisk(); if (!string.IsNullOrEmpty(_cachedToken)) { Debug.Log($"🔄 Using cached token: {_cachedToken.Substring(0, 8)}..."); onSuccess?.Invoke(_cachedToken); return; } // 缓存不存在,发起网络请求 StartCoroutine(RequestTokenFromHMS(onSuccess, onError)); } private string LoadTokenFromDisk() { string path = Path.Combine(Application.persistentDataPath, TOKEN_FILE); if (File.Exists(path)) { try { string encrypted = File.ReadAllText(path); return DecryptToken(encrypted); } catch (Exception e) { Debug.LogWarning($"Failed to load token: {e.Message}"); return null; } } return null; } private void SaveTokenToDisk(string token) { string path = Path.Combine(Application.persistentDataPath, TOKEN_FILE); try { string encrypted = EncryptToken(token); File.WriteAllText(path, encrypted); Debug.Log("💾 Token saved to disk"); } catch (Exception e) { Debug.LogError($"Failed to save token: {e.Message}"); } } private IEnumerator RequestTokenFromHMS(Action<string> onSuccess, Action<string> onError) { // 调用HMS getToken(此处简化,实际需用AndroidJavaObject) yield return new WaitForSeconds(0.1f); // 模拟异步延迟 string token = "AAAAAABBBBBBCCCCCDDDDDEEEEEFFFFF"; // 实际从HMS回调获取 if (!string.IsNullOrEmpty(token)) { SaveTokenToDisk(token); onSuccess?.Invoke(token); } else { onError?.Invoke("HMS getToken returned null"); } } // 简单AES加密(生产环境请替换为标准AES实现) private string EncryptToken(string token) { byte[] bytes = Encoding.UTF8.GetBytes(token); // 此处应调用标准AES加密,密钥从Keystore读取 return Convert.ToBase64String(bytes); } private string DecryptToken(string encrypted) { byte[] bytes = Convert.FromBase64String(encrypted); return Encoding.UTF8.GetString(bytes); } }

提示:上述加密仅为示意,生产环境必须使用Android Keystore系统存储密钥,禁用硬编码密钥。Unity中可通过AndroidJavaObject("android.security.KeyStore")调用系统Keystore API。

5.3 Token失效检测与服务端协同策略

华为不提供Token有效性校验API,但我们可以通过服务端埋点实现间接检测:

  1. 客户端每次上报Token时,附带设备唯一标识(如AndroidJavaObject("android.provider.Settings$Secure").CallStatic<string>("getString", contentResolver, "android_id"));
  2. 服务端记录device_id → token → last_update_time映射;
  3. 当某设备连续3次推送失败(华为推送返回error_code=80000001,表示Token无效),服务端标记该token为失效,并向客户端下发refresh_token指令;
  4. 客户端收到指令后,主动调用HmsMessaging.deleteToken()清除旧Token,再重新getToken()。

这个机制让Token管理从“客户端单点维护”升级为“客户端+服务端双保险”,避免因单点失效导致整批用户推送失联。

5.4 多端状态同步:当用户在华为平板、手机、智慧屏上登录同一账号时

HMS Push的Token是设备级的,但业务需求常是“账号级推送”。解决方案是:

  • 客户端在登录成功后,将account_id + device_id + hms_token三元组上报服务端;
  • 服务端建立account_id → List<device_token>映射;
  • 推送时,服务端遍历该账号所有有效设备Token,分别调用华为推送API;
  • 客户端登出时,主动调用HmsMessaging.deleteToken()并通知服务端删除对应映射。

我们在此demo中已预留AccountSyncManager.cs脚本入口,其核心逻辑是监听Unity的AuthManager.OnLoginSuccess事件(需你项目已集成账号系统),触发Token上报。从那以后我每次做华为渠道包,都强制在登出流程里加入deleteToken调用,并在AGC后台配置“设备离线30天自动清理Token”策略——这比等用户手动卸载APP再触发清理,更能保障推送列表的纯净度。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 11:13:10

C++与Kubernetes集成:生命周期、探针与监控的工程实践

“C与Kubernetes集成”&#xff0c;这个标题初看有点模糊&#xff0c;因为C和K8s不是同一个层面的东西。但我猜你实际想解决的是这个问题&#xff1a;我手上有一个C写的后端服务、中间件或者算法引擎&#xff0c;现在要把它容器化并部署到Kubernetes上&#xff0c;真正跑起来之…

作者头像 李华
网站建设 2026/10/16 11:12:35

SLAM非线性优化实战:从重投影误差到Ceres/g2o调优

1. 这不是数学课&#xff0c;是让机器人“睁眼认路”的实操手册 “视觉 SLAM 十四讲 —— 第六讲 非线性优化”&#xff0c;光看标题&#xff0c;很多人第一反应是&#xff1a;又来一堆矩阵、雅可比、Hessian&#xff1f;是不是得先翻《数值分析》补半年课&#xff1f;我刚开始…

作者头像 李华
网站建设 2026/10/16 11:10:51

SAP PP工作中心:生产计划、产能与成本的枢纽

搞生产的朋友多半有个感受&#xff1a;系统里单据一大堆&#xff0c;工艺路线、生产订单、报工、结算&#xff0c;层层叠叠看着复杂&#xff0c;可真出了问题追根溯源&#xff0c;最后都会指向同一个主数据——工作中心。我刚做SAP PP支持那阵子&#xff0c;接过不少让人抓狂的…

作者头像 李华
网站建设 2026/10/16 11:10:01

UE5 UMG图表控件集成指南:从配置到实时数据可视化

简介&#xff1a;面向Unreal Engine 5开发者的UMG图表控件插件&#xff0c;专为游戏与虚拟现实应用提供数据可视化能力。插件完全基于UMG框架&#xff0c;用纯C配合蓝图构建&#xff0c;无需WebBrowser或WebUI嵌套&#xff0c;集成更流畅&#xff0c;且便于定制扩展。内置曲线图…

作者头像 李华
网站建设 2026/10/16 11:09:57

UE5 UMG图表控件插件从安装到C++接入:完整避坑指南

简介&#xff1a;这是一款基于Unreal Engine 5的UMG图表控件插件&#xff0c;专为游戏开发与虚拟现实项目提供高效的数据可视化能力。它完全使用UMG与纯C/蓝图实现&#xff0c;无需借助WebBrowser或WebUI嵌套&#xff0c;能够流畅集成到引擎原生界面中。插件支持曲线图、饼图、…

作者头像 李华
网站建设 2026/10/16 11:09:48

LeetCode Hot 100矩阵四题精讲:旋转、螺旋、置零与搜索

刷 Leetcode Hot 100 的矩阵模块&#xff0c;是我个人觉得性价比最高的一块。别看它题目数量不多&#xff0c;一共就那么几道&#xff0c;但每一道都能单独拿出来当面试题&#xff0c;而且几乎每道题都能从“暴力解”一路问到“原地算法”&#xff0c;非常考验对下标、边界和空…

作者头像 李华