简介:本资源是面向Unity开发者的华为HMS SDK接入示例工程,适合需要在华为设备上集成账号、游戏、推送等服务的移动游戏与应用开发者参考。压缩包共约2000个文件,以bin、info、class、meta、java、xml、png、jar、cs、dll等为主,涵盖Java层实现、C#脚本、Android清单配置、资源贴图与依赖库,整体约28.82MB,结构接近真实Unity工程目录。资源围绕HMSManager初始化、登录、推送等接口调用展开,包含HuaweiSdkDemo示例代码与IL2CPP打包配置参考,可帮助读者理解SDK导入、权限声明与真机测试的完整链路。目前已有1842人学习下载,适合希望快速跑通华为SDK接入流程、减少版本兼容与配置踩坑的开发者对照使用。
1. 从一次登录回调失败说起:这套 Unity 华为 SDK demo 到底能干什么
如果你在 Unity 里接过华为渠道的登录,大概率经历过这种场面:编辑器里点登录按钮毫无反应,真机装完包点下去直接闪退,logcat 里翻半天只看到一句ClassNotFoundException。这不是你代码写错了,而是 Unity 的 C# 层和华为 HMS SDK 的 Java 层之间隔着一道 JNI 墙,demo 的价值就在于把这堵墙的每一块砖都标好了位置。这套 Unity 接入华为 SDK demo 覆盖了账号登录、支付拉起、初始化配置这几条主链路,用 C# 封装调用 Android 原生接口,适合两类人:一是第一次接华为渠道、需要一份能跑通的参照工程;二是接过但被回调时序和混淆配置坑过、想回头补课的老手。它不解决所有问题,但能让你少走至少两天的弯路。
2. 拆开 demo 看结构:Unity 侧封装与 Android 原生桥接怎么对上
2.1 工程目录里哪些文件真正参与编译
拿到 demo 先别急着打开 Unity,用文件管理器把目录扫一遍,心里有个数。典型的 Unity 华为 SDK demo 会包含这几个关键区域:
| 路径 | 作用 | 是否参与打包 |
|---|---|---|
Assets/Plugins/Android/ | 存放 HMS 的 aar/jar 和 AndroidManifest | 是 |
Assets/Scripts/Huawei/ | C# 封装层,负责调用 Java 接口 | 是 |
Assets/Plugins/Android/AndroidManifest.xml | 声明权限、AppID、Activity | 是 |
Assets/Plugins/Android/libs/ | 华为 SDK 的 jar/aar 文件 | 是 |
ProjectSettings/ | 包名、最低 API 等级等 | 是 |
这里最容易翻车的是AndroidManifest.xml的合并。Unity 在打包时会把自己的 Manifest 和 Plugins 下的 Manifest 做 merge,如果你在别处也有一份 Manifest,AppID 的 meta-data 可能被覆盖掉。我一般会先确认最终 APK 里的 Manifest 长什么样,用 Android Studio 的 Build > Analyze APK 打开看一眼,比在 Unity 里猜靠谱得多。
2.2 C# 调用 Java 的三种写法与选型
demo 里 C# 调 Java 通常走AndroidJavaClass和AndroidJavaObject,但具体写法有讲究。下面这段是初始化 HMS 的典型封装:
// HuaweiSDKManager.cs using UnityEngine; public class HuaweiSDKManager : MonoBehaviour { private AndroidJavaClass _hmsAgentClass; private AndroidJavaObject _currentActivity; void Awake() { // 只在 Android 平台执行,编辑器下直接跳过 #if UNITY_ANDROID && !UNITY_EDITOR // 获取 UnityPlayer 的当前 Activity,后续所有需要 Context 的调用都靠它 using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { _currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); } // 反射拿到华为 SDK 的初始化入口类 _hmsAgentClass = new AndroidJavaClass("com.huawei.hms.api.HuaweiApiAvailability"); #endif } public void Init() { #if UNITY_ANDROID && !UNITY_EDITOR // 调用华为 SDK 的初始化方法,传入 Activity 和回调监听 _hmsAgentClass.CallStatic("getInstance", _currentActivity); Debug.Log("HMS init invoked"); #endif } }逻辑说明:AndroidJavaClass用于调用静态方法,AndroidJavaObject用于实例方法。currentActivity是 Unity 播放器的 Activity,华为 SDK 的很多接口需要它作为 Context 参数。#if UNITY_ANDROID && !UNITY_EDITOR这个宏定义必须加,否则在编辑器里运行会直接抛异常,因为编辑器没有 Android 运行时。
参数说明:getInstance是华为 SDK 的静态方法名,不同版本可能叫init或getInstance,以你实际引入的 aar 为准。CallStatic的第一个参数是方法名,后面跟参数列表,类型要匹配,传错类型不会报编译错误,但运行时会崩。
2.3 回调怎么从 Java 层传回 C# 层
这是整个接入里最绕的一环。华为 SDK 的登录结果是在 Java 的OnActivityResult里回来的,而 Unity 的 C# 层拿不到这个回调,demo 通常用两种方案打通:
第一种是UnitySendMessage,Java 层通过UnityPlayer.UnitySendMessage("GameObjectName", "MethodName", "message")把结果发给场景里的某个 GameObject。这种写法简单,但要求那个 GameObject 在场景里一直存在,且方法名不能写错,写错了就是静默失败,logcat 里连个警告都没有。
第二种是 C# 侧注册一个AndroidJavaProxy,实现 Java 接口,把代理对象传给华为 SDK。这种写法更类型安全,但代码量大,demo 里一般只在支付回调这种关键路径上用。
我一般会先跑通UnitySendMessage方案,确认链路通了,再决定要不要换成 Proxy。因为UnitySendMessage的调试成本低,出问题看 logcat 就能定位。
3. 从零跑通 demo:环境配置、签名与真机验证的完整链路
3.1 Unity 版本与 Android 构建支持的选择
demo 本身对 Unity 版本不挑,但华为 SDK 对 Android API 等级有要求。我实测下来,Unity 2021.3 LTS 配 Android API 30 以上比较稳。在 Unity Hub 里安装 Android Build Support 时,记得勾上 OpenJDK 和 Android SDK & NDK Tools,不然后面打包会提示找不到 JDK。
打开 demo 工程后,先到Edit > Project Settings > Player > Android里确认三件事:包名(Package Name)不能是默认的com.Company.ProductName,必须改成你自己的;Minimum API Level 至少 24;Target API Level 选 Automatic 或 30 以上。包名和华为 AppGallery Connect 里注册的应用包名必须完全一致,差一个字符都会导致初始化失败。
3.2 华为 AppGallery Connect 侧要配什么
去 AppGallery Connect 创建应用,拿到agconnect-services.json文件,把它放到Assets/Plugins/Android/目录下。这个文件里包含了 AppID、ClientID 和 API Key,华为 SDK 初始化时会读它。很多人漏掉这一步,结果真机上一直提示907135000错误码,其实就是配置文件没放对位置。
然后在AndroidManifest.xml里加上 AppID 的 meta-data:
<application> <meta-data android:name="com.huawei.hms.client.appid" android:value="appid=你的AppID" /> <meta-data android:name="com.huawei.hms.client.cpid" android:value="cpid=你的CPID" /> </application>注意value里的appid=前缀不能省,这是华为 SDK 的格式要求。CPID 在部分接入场景下才需要,如果只做登录可以先不加。
3.3 签名配置与真机安装
Unity 打包 Android 时默认用 debug 签名,但华为 SDK 的部分接口要求正式签名。在Player Settings > Publishing Settings里勾上 Custom Keystore,选你的 keystore 文件,填别名和密码。如果只是本地验证,debug 签名也能跑通登录,但支付相关的一定要用正式签名。
打包出 APK 后,用adb install装到真机上。这里有个血泪经验:不要用 Unity 的 Build And Run 直接跑,那个走的是另一套安装流程,有时候会跳过签名校验。我一般手动adb install -r app.apk,然后adb logcat -s Unity HuaweiAgent过滤日志,看初始化有没有报错。
3.4 验证登录链路的三个检查点
装好之后点登录按钮,按这个顺序排查:
第一,看 logcat 里有没有HMS init success之类的日志,没有的话说明初始化就没过,回去检查agconnect-services.json和 AppID。
第二,看有没有拉起华为账号的登录界面,没拉起的话大概率是AndroidManifest.xml里缺了HMSActivity的声明。
第三,登录界面拉起后点授权,看 C# 层有没有收到回调。没收到的话,检查UnitySendMessage的 GameObject 名字和方法名是否和 Java 层写的一致。
4. 避坑与排查:接入华为 SDK 时最容易翻车的五个点
4.1 编辑器里能跑、真机上闪退
现象:在 Unity 编辑器里点运行一切正常,打包到真机一打开就闪退。
原因:编辑器走的是 Mono 运行时,真机走的是 IL2CPP 加 Android 运行时,AndroidJavaClass在编辑器里被宏定义跳过了,但真机上如果华为 SDK 的 aar 没正确引入,就会在new AndroidJavaClass那一行抛ClassNotFoundException。
解决:确认Assets/Plugins/Android/下所有 aar 文件的 Inspector 里 Android 平台是勾选的,且 CPU 架构(ARMv7/ARM64)都勾上。然后用adb logcat看崩溃堆栈,定位到具体缺哪个类。
4.2 登录回调收不到,日志里也没有报错
现象:华为账号登录界面正常拉起,用户授权后界面关闭,但 C# 层没有任何反应。
原因:UnitySendMessage的目标 GameObject 在场景切换时被销毁了,或者方法名拼写不一致。Java 层调用UnitySendMessage时如果找不到目标,不会抛异常,只会静默失败。
解决:把接收回调的 GameObject 做成DontDestroyOnLoad,并且方法名用常量字符串管理,不要手写。在 Java 层加一行Log.d("HuaweiCallback", "send message to " + gameObjectName),确认消息发出去了。
4.3 混淆配置漏了导致 release 包崩溃
现象:debug 包跑得好好的,打了 release 包之后登录直接崩。
原因:华为 SDK 的某些类被 ProGuard 混淆掉了,运行时反射找不到。
解决:在proguard-user.txt里加上华为 SDK 的 keep 规则:
-keep class com.huawei.** { *; } -keep class com.huawei.hms.** { *; } -dontwarn com.huawei.**这个文件放在Assets/Plugins/Android/下,Unity 打包时会自动合并。注意-dontwarn也要加,否则 ProGuard 会因为找不到某些可选依赖而报错中断。
4.4 AppID 配对了但初始化返回 907135000
现象:确认agconnect-services.json已放入,AppID 也填了,但初始化回调返回错误码907135000。
原因:这个错误码通常表示 AppID 与包名不匹配,或者agconnect-services.json里的 AppID 和 Manifest 里写的不一致。
解决:打开agconnect-services.json,找到app_id字段,和 Manifest 里com.huawei.hms.client.appid的 value 逐字符比对。另外确认打包用的包名和 AppGallery Connect 里注册的包名完全一致,包括大小写。
4.5 支付拉起后无法回到游戏
现象:支付界面能拉起,用户完成支付后点返回,游戏卡在黑屏或直接重启。
原因:华为支付 SDK 需要你在AndroidManifest.xml里声明一个单独的 Activity 来处理返回,demo 里如果没配这个 Activity,系统会回到默认的 launcher Activity,导致 Unity 重新加载。
解决:检查 Manifest 里是否有com.huawei.hms.activity.BridgeActivity的声明,并且它的android:configChanges要包含orientation|screenSize|keyboardHidden,否则旋转屏幕时 Activity 会重建。
5. 进阶技巧:用日志分级和回调超时机制把问题钉死在现场
5.1 给华为 SDK 的日志加一层过滤开关
华为 SDK 自己的日志量很大,直接看 logcat 会被淹没。我习惯在 C# 封装层加一个日志开关,把关键节点的日志单独打一个 tag:
public static class HmsLog { private const string Tag = "HmsUnity"; public static bool Verbose = false; public static void I(string msg) { if (Verbose) Debug.Log($"[{Tag}] {msg}"); } public static void E(string msg) { Debug.LogError($"[{Tag}] {msg}"); } }然后在每个关键调用前后加HmsLog.I("before login")和HmsLog.I("after login")。这样在 logcat 里用adb logcat -s HmsUnity就能看到完整的调用链,不会被华为 SDK 的内部日志干扰。Verbose开关在 release 包里关掉,避免性能损耗。
5.2 给登录回调加一个超时兜底
华为 SDK 的回调在某些网络环境下可能永远不回来,用户点了登录之后界面一直转圈。我一般会加一个协程做超时检测:
private IEnumerator LoginTimeout(float seconds) { float elapsed = 0f; while (elapsed < seconds) { if (_loginCallbackReceived) yield break; elapsed += Time.deltaTime; yield return null; } // 超时后重置 UI 状态,给用户一个重试按钮 HmsLog.E("login callback timeout"); OnLoginFailed("timeout"); }逻辑说明:_loginCallbackReceived在收到 Java 层回调时置为 true,协程每帧检查一次,超时后走失败流程。参数seconds一般设 15 到 20 秒,太短会误杀慢网络下的正常回调,太长用户等不及。
5.3 用 adb 命令快速抓取关键日志
真机调试时,我常用的组合是:
adb logcat -c && adb logcat -s HmsUnity HuaweiApiAvailability AndroidRuntime-c先清空旧日志,-s后面跟多个 tag 表示只显示这些 tag 的日志。AndroidRuntime用来抓崩溃堆栈,HuaweiApiAvailability是华为 SDK 初始化相关的 tag。这样一屏就能看到从初始化到登录回调的完整链路,不用在几万行日志里翻。
5.4 一个我踩过的坑:回调线程不是主线程
华为 SDK 的回调有时候在子线程里触发,如果你在回调里直接操作 Unity 的 UI 或 GameObject,会抛UnityException: ... can only be called from the main thread。我当时的做法是在 C# 回调入口处用一个线程安全的队列把消息存起来,在Update里取出来处理:
private static readonly Queue<Action> _mainThreadQueue = new Queue<Action>(); public static void Enqueue(Action action) { lock (_mainThreadQueue) { _mainThreadQueue.Enqueue(action); } } void Update() { lock (_mainThreadQueue) { while (_mainThreadQueue.Count > 0) { _mainThreadQueue.Dequeue()?.Invoke(); } } }Java 层回调过来时,不要直接改 UI,而是Enqueue(() => { /* 更新 UI */ })。这个习惯从那以后我每次接原生 SDK 都强制走一遍,不管对方文档有没有提线程问题。希望帮到你。
本文还有配套的精品资源,点击获取