原生和SDK接入
前言
在游戏开发过程中,无论是做手游还是端游还是小游戏,我们或多或少都会需要接入第三方SDK去支持一些原生功能,不会全部都自己从0开发(比如广告SDK,统计SDK,支付SDK等),本章节就是为了深入SDK接入实战,打通SDK接入流程,同时深入Unity+原生开发,了解原生开发过程中的理论和实践知识。
原生开发
原生开发是指除了Unity提供的官方功能,我们还能在不同平台自己进行原生功能开发。
Android原生开发
Android我们通过自定义MainActivity和编写原生Android功能代码实现原生功能,然后在Unity测通过AndroidJavaClass去访问原生Android Activty和调用原生代码功能。Untiy支持我们自己导出**AAR(包含代码和资源)或者Jar(仅仅包含代码)**然后放到Plugins/Android/libs目录下直接使用,接下来我将深入从0实战如何搭建一个能够自定义开发原生功能流程框架搭建。
Unity导出Gradle工程
为了方便参考Unity能正确使用的Gradle工程相关设置,在搭建我们自己的原生Android工程前,我通过代码打包给Unity Android设置好相关打包配置,然后通过Unity自带的Gradle打包导出一个Android工程。
导出后我使用Android Studio打开发现报错:
这是因为Unity 2022.3.62f3导出的Gradle工程的JDK默认使用的是JAVA_HOME指向的,而之前我为了配置Jenkins打包将JAVA_HOME指向了最新的Java 21。但Unity 2022.3.62f3导出的Gradle工程使用的是Gradle 7.5.1,Gradle 7.5.1不支持运行在Java 21上,所以导致出问题。
所以我们需要将导出Gradle工程的JDK指向Unity对应版本的JDK(对于我本地来说是以下路径):
1 | G:\Software\UnityAllVersions\2022.3.62f3\2022.3.62f3\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK |
修改后重新打开Gradle工程经历漫长的Gradle依赖下载后会发现工程能正确打开了:
接下来我们就能创建我们的原生Android工程,并参考导出的Gradle工程进行配置设置了。
Unity 2022.3.62f3用的Gradle版本是7.51,Android Gradle Plugin是7.4.2,JDK是11
Note:
- Gradle相关东西大部分都需要翻墙下载,请确保网络环境支持
- Gradle 是通用构建系统。它不只用于 Android,也能构建普通 Java、Kotlin、Groovy 等项目
- Android Gradle Plugin,简称 AGP,是运行在 Gradle 上的 Android 构建插件
创建原生Android工程
Android工程分为两大类,一类是Application(用于打包APK),另一类是library(用于导出AAR或Jar)
我们安装好Android Studio后,File->New->New Project->新建一个Empty Activity的NativeFramworkAndroidProject Android工程:
创建后会发现工程里有很多kotlin相关的内容,比如MainActivity.kt,app/build.gradle里有很多kotlin相关内容,这个好像是因为Android官方最新推的就是kotlin所以默认都带了。我们只是想扩展Unity的原生MainActivity去扩展编写原生功能,并不是想完全当做Android原生开发,所以我希望的还是走Android+java相关的原生开发方式,后续创建Android Library后会完全放弃并删除Android App相关。
创建完Android工程后我发现后台任务一直提示ImportingNativeFrameworkAndroidProject” Gradle Project,我打开View->Tool Window->Build看到好像在处理SDK 36相关的东西(AI说是工程默认用的AGP 9.0所以会去找SDK 36),但我本机还没安装SDK 36:
为了让项目Import成功后使用New Module创建Android Library这里需要先打开Tools->SDK Manager->勾选SDK版本并安装(SDK 36):
这里只是为了让Android工程导入通过,后续我会根据Unity导出的Gradle工程去严格修改Android相关工具配置!
安装完成后打开NativeFrameworkAndroidProject的Android工程经历漫长的导入,最终Android工程导入完成打开成功了:
Note:
- 创建Android工程的Build configuration language选项要选Groovy DSL,使用Groovy语言来编写.gradle文件(考虑到Unity导出Gradle工程也是用的Groovy),虽然Android官方推荐选Kotlin DSL
- 主要包名要和我们游戏里的包名保持一致
- Minimus SDK最好也保持和项目设置一致
确保正确的Gradle,Android Gradle Plugin和JDK
接下来我们先确保前面提到的Gradle,Android Gradle Plugin和JDK使用和Unity对应版本一致先。
在修改各个目标文件之前,我们先看下AI给出的项目结构和各文件的作用说明:
保持根gradle.properties内容和导出Gradle工程gradle.properties一致:
1
2
3
4
5
6
7
8
9
10
11
12org.gradle.jvmargs=-Xmx4096M
org.gradle.parallel=true
unityStreamingAssets=UnityServicesProjectConfiguration.json, google-services-desktop.json
# Android Resolver Properties Start
android.useAndroidX=true
android.enableJetifier=true
# Android Resolver Properties End
unityTemplateVersion=7
android.useAndroidX=true
android.enableJetifier=true
org.gradle.welcome=never
android.aapt2FromMavenOverride=G\:\\Software\\UnityAllVersions\\2022.3.62f3\\2022.3.62f3\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\SDK\\build-tools\\34.0.0\\aapt2.exe我们会在build.gradle里指定buildToolsVersion版本,但如果不强制指定aapt2工具,Android Gradle Tool会选用默认依赖的相关工具导致出错,为了确保跟Unity版本使用工具一致这里还是需要明确指定aapt2FromMavenOverride工具
保持JDK版本一致
将项目的Gradle JDK设置(File->Settings->Build,Execution,Deployment->Build Tools->Gradle->Gradle JDK)成我们Unity对应版本需要的JDK路径:
保持Gradle版本一致
打开Android Project根目录下的gradle-wrapper.properties保持和Unity导出的Gradle工程设置一致如下:
1
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
保持Android Gradle Plugin版本一致
打开我们Android Project根目录下的build.gradle文件修改成如下:
1
2
3
4
5// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
}如果发现Sync Gradle报错如下:
1
org.gradle.api.GradleException: Error resolving plugin [id: 'com.android.application', version: '9.0.1']
这是因为我们创建的Android工程里的libs.version.toml里还起订了Android Gradle Plugin的版本信息,将libs.versions.toml里AGP版本修改到7.4.2:
1
2[versions]
agp = "7.4.2"真正关联上Application和Library使用哪个Android Gradle Plugin版本的配置是在libs.version.toml:
再次Sync Gradle报错如下:
1
2problem occurred evaluating project ':app'.
> Could not find method compileSdk() for arguments [build_6jjk1t0mf4mcnif7jl7frtd5s$_run_closure1$_closure3@519d74c7] on extension 'android' of type com.android.build.gradle.internal.dsl.BaseAppModuleExtension.这是因为我们将Android Gradle Plugin版本改到7.4.2后,不识别app/build.gradle(unitynativeframework/build.gradle里同理)里的以下写法:
1
2
3compileSdk {
version = release(36)
}需要修改成如下:
1
compileSdkVersion 36
最终终于通过了Sync Gradle同步。
我们通过View->Tool Windows->Gradle->Execute Gradle Task输入**:unitynativeframework:assembleRelease**执行Android Library生成AAR,报错如下:
根据AI的说法是我们虽然指定了AGP版本7.4.2,但没有显示指定Build Tools的版本,所以他默认去找配套的30.0.3版本Build Tools了,同时发现找不到,所以解决问题的关键是要配置跟Unity版本配套的Build Tools版本,在对应build.gradle里分别指定以下文本:
1
buildToolsVersion '34.0.0'
Note:
- 注意将部分build.gradle里指定的minSdk和targetSdk也同步成我们目标需要的值
添加Android Library
接下来我们创建一个Android Liabrary:
添加Unity对应版本的classes.jar到Android Library的lib目录下:
添加自定义的MainActivity.java文件:
1 | package com.tonytang.unitynativeframework; |
在Android Library的build.gradle里添加以下配置,将classes.jar仅编译但不导出避免和Unity的classes.jar出现双份冲突:
1 | dependencies { |
Unity对应版本的classes.jar路径在对应版本安装目录下,不确实哪个可以直接拷贝导出的Gradle工程里的classes.jar
将导出的Gradle工程下的unityLibrary的AndroidManifest.xml拷贝到Unity项目Plugins/Android目录下作为基准AndroidManifest.xml使用,但要将android:name=”com.unity3d.player.UnityPlayerActivity”修改成我们自己的包名android:name=”com.tonytang.unitynativeframework.MainActivity”,这一步是将默认的Unity MainActivity修改成我们自定义的MainActivity的关键:
为什么我们的Android Library工程不需要配置像Unity导出的Gradle工程相关的NDK配置?为什么 Unity 导出工程需要 NDK?
Unity 导出的 unityLibrary/build.gradle 不只是普通 Android Library,它包含:
- Unity Player 运行时;
- IL2CPP 生成的 C++;
- Unity 原生库;
- 游戏程序集和资源;
- 多个 CPU 架构的
.so; - IL2CPP 编译任务。
而我们编译Android Library的工程只有Android Java代码,是构建一个纯Java Android Library的AAR所以不需要使用NDK工具,如果未来需要包含C++或者.so或者使用JNI啥的才需要NDK。
导出Android Library AAR
打开Gradle窗口(View-> Tool Windows -> Gradle),准备导出Library AAR:
点击Execute Gradle Task并输入:unitynativeframework:assembleRelease
等待执行完成后发现AAR生成成功:
导出成功后我们将导出的unitynativeframework-release.aar放到Unity工程的Plugins/Android/libs目录下等待使用。
为什么Build Gradle Task输入:unitynativeframework:assembleRelease会有效?
因为assembleRelease 就是 Android Gradle Plugin 自动创建的任务,不需要你手写。
assemble:装配、打包构建产物。
Release:构建 release 变体。
对于Android Library来说,
1 | assembleRelease |
对 Android Application 来说:
1 | assembleRelease |
Task的名称来源于build.gradle里:
1 | buildTypes { |
以上配置Android Gradle Plugin就会创建assembleRelease的任务。
Unity访问原生代码
Android原生访问代码功能实例:
AndroidNativeManager.cs
1 | ****** |
然后在按钮点击的时候调用:
GameLauncher.cs
1 | /// <summary> |
打包安装运行:
从日志可以看出我们成功实现了导出自定义AAR+指定我们自定义的MainActivity作为游戏启动Activity的功能。
我们点击按钮执行调用原生Android的javaMethod方法:
从截图可以看出我们成功调用了我们在Android的MainActivity里自定义的javaMethod方法,同时我们通过UnityPlayer.UnitySendMessage的方式成功回调到了Unity测的NativeMessageHandler.resUnityMsg()方法和传参
至此我们想要实现搭建Android Library导出AAR(含自定义MainActivity入口)的框架流程就算正式打通了。
IOS原生开发
IOS原生开发同理,IOS也有属于自己的程序启动入口(UnityAppController.mm),结合以前的学习(详情参考:Unity原生])我们可以知道要想自定义IOS原生入口编写功能,我们需要编写一个继承至UnityAppController的类作为程序入口,目前IOS好像支持Objective-C和Swift,以下是以Objective-C为例:
AppController.h
1 | // 自定义Unity AppCOntroller |
AppController.mm
1 | //自身的头文件 |
通过上面的代码,我们完成了下面两件事:
- 自定义Unity IOS程序入口
- 添加了自定义的View(绑定到自定义UIViewController上)到rootView上
成功绑定到自定义UIViewController上后,我们就能通过自定义的UIViewController去和IOS打交道了。
UnityViewController.h
1 | //自定义的UIViewController |
UnityViewController.mm
1 | //包含自身头文件 |
可以看到通过自定义的UIViewController,我们就可以直接编写对应原生功能(e.g. 权限申请)代码了。
SDK
SDK 是「Software Development Kit」的縮寫,中文稱為「軟體開發工具套件」
很多跨平台功能需要处理原生的东西,且这些功能可以说是对大部分游戏都需求 统一的,所以很多时候这些功能(比如广告SDK,统计SDK,支付SDK等)会被做成SDK供我们直接集成使用。
Firebase
Firebase 是一组面向移动端的云服务和运营工具。它把账号、数据存储、云函数、崩溃收集、数据分析、远程配置、推送等常见能力组合在一起,并提供 Unity/C++ SDK。
Firebase能提供很多我游戏开发中会用到的一些SDK功能,比如崩溃统计,数据大大点,消息推送,登录授权等。
在游戏开发过程中如果我们的游戏走海外移动端,基本都会选Firebase。但在国内受限于网络的原因,部分Firebase功能我们需要选择其他替代品。
AI给出的国内外推荐服务选择:
| 能力 | 海外版 | 中国大陆版 |
|---|---|---|
| 崩溃监控 | Firebase Crashlytics | Bugly、国内 APM、Sentry |
| 数据分析 | Firebase Analytics | 数数、神策、火山、友盟或自建 |
| 远程配置 | Firebase Remote Config | 国内 CDN/配置中心/自建 |
| Android 推送 | FCM | 厂商推送或聚合推送 |
| iOS 推送 | FCM/APNs | 优先评估直接 APNs |
| 登录 | Firebase Auth | 国内账号、渠道账号、自研 |
| 云存档 | Firestore | 国内后端和数据库 |
| 云函数 | Cloud Functions | 国内云函数或自建服务 |
| 文件存储 | Firebase Storage | 国内对象存储和 CDN |
| 实时战斗 | 专用游戏服务器 | 专用游戏服务器 |
Note:
- Firebase在PC端支持不太完善
Firebase Unity接入
接下来以实战Unity接入Firebase的崩溃监控和数据功能为例。
Firebase接入条件限制:
安装 Unity 2021 LTS 或更高版本。更早的版本也可能兼容,但不享受积极支持。
(仅限 Apple 平台)安装以下各项:
- Xcode 16.2 版或更高版本
- CocoaPods 1.12.0 或更高版本
确保您的 Unity 项目满足以下要求:
- 对于 iOS - 目标为 iOS 15 或更高版本
- 对于 tvOS - 目标为 tvOS 15 或更高版本
- 对于 Android - 目标 API 级别为 23 (Marshmallow) 或更高版本
设置一台实体设备或使用模拟器运行您的应用。
对于 Apple 平台 - 设置实体设备或使用 iOS 或 tvOS 模拟器。
您是要用 Cloud Messaging?
对于 Android - 模拟器必须使用包含 Google Play 的模拟器映像。
使用您的 Google 账号登录 Firebase
登录Firebase创建项目
创建Firebase项目成功后可以看到我们创建的项目:
在Firebase中注册应用
打开我们创建的Firebase项目:
点击添加应用后选择对应平台,这里以Android平台为例:
根据要求下载google-services.json文件并放到项目Assets目录下:
google-services.json内容:
1 | { |
可以看到根据我们注册应用传入的项目包名,Firebase生成了project_number,mobilesdk_app_id,api_key等相关的值。
添加Firebase Unity SDK
可以看到里面包含了各种Firebase提供的SDK包,这里我以**数据统计SDK(FirebaseAnalytics.unitypackage)**作为实战SDK。
将FirebaseAnalytics.unitypackage导入Unity。
导入过程中会问一些是否激活特定额外功能,这个根据需求选择,我目前都选择了No,但最后提示Enable Android Auto-resolution时要选择Enable,让他自行解决下Android的一些依赖冲突:
AI的说法是这一步会根据项目所有第三方插件配置文件进行分析,去下载相关依赖AAR,更新Unity的Gradle模版等操作。
FirebaseApp.androidlib不是Firebase Analytics SDK本体,它是Firebase项目配置资料库(比如AndroidManifest.xml(定义Firebase的Android Activity)和google-services.xml(定义一些Android资源icon名称))
mainTemplate.gradle 这是Unity Android 构建中的主 Android Library 模块 Gradle 模板,主要用于生成unityLibrary/build.gradle。
settingsTemplate.gradle是根Gradle工程,主要负责配置一些内容去决定哪里寻找插件和依赖、工程包含哪些模块。
gradleTemplate.properties是Unity 生成gradle.properties的模版,它控制整个 Gradle 构建进程的属性。
确认Google Play服务版本要求
需要再项目启动时找个时机添加一下CSharp代码:
1 | using Firebase.Extensions; |
FireBaseInitilization()里的代码就是Firebase Analytics检查Google Play服务版本要求的核心代码,注意看我们在打点登录事件调用是放在检查通过以后,原因是在Google Play服务版本要求检查通过之前,我们是不允许使用打点功能的。
打包测试Firebase Analytics
打包失败提示如下:
字面意思我们设置的Android最低版本是22,但Firebase Analytics要求Android最低版本是23,所以修改我们打包时设置的Android最低版本到23即可:
1 | PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel23; |
再次触发打包,依然报错:
根据AI的说法是Unity 2022.3自带的AGP 7.4.2/D8版本较久。旧D8在解析时出错,建议我将minSdkVersion设置成24后终于打包成功了。
安装测试可以看到Firebase Analytic的Google Play服务检查通过了:
Note:
- 我使用的Unity版本是2022.3.62f3,Unity Firebase SDK版本是13.15.0
Unity版Firebase Analytics使用入门
Unity接入Firebase Analytics成功后,我们就能使用Firebase Analytics进行数据打点。
定义一个FBAParameters去定义我们Firebase Analytics自定义打点的参数名常量定义:
1 | /// <summary> |
比如我打点一个登录事件打点,打点数据参数是用户设备UID:
1 | /// <summary> |
同时在打一个DIY的调用本地方法按钮点击次数统计:
1 | /// <summary> |
打包后验证:
可以看到登录日志打点已经出发了,紧接着我点了两次调用Java方法按钮去触发原生方法按钮点击统计打点。(因为代码有点问题反复修改代码测试了多次,导致部分事件统计了多次)
我们打开Firebase对应项目,搜索Events(如果刚发送的没能立刻看到可以搜索Realtime Analytics):
可以看到无论是官方定义的事件明还是我们自定义的事件名都成功发送统计到了Firebase Analytics后台。
但奇怪的一点是我在Firebase Analytics Events页面上好像只有部分事件能看到我传递的自定义参数:
总的来说,Firebase Analytics的功能集成和使用算是基本成功,Firebase Analytics的接入告一段落。

