UE5 Android SDK 对接实践指南

1,652 阅读4分钟

前言

之前我写过一篇 UE4 与 Android 对接实现数据交互的文章帮助了不少的开发者,时间过了这么久, UE4 也早已升级到了 UE5,之前写的文章想必有些内容也已经过时了。于是咱们今天就更新一下,来看看 UE5 如何来对接 Android SDK。

配置

升级到 UE5 之后,Android Stduio 的版本也需要进行升级,可以参考以下图片的说明: image

我目前的引擎版本是 UE5.0, 所以对应的我需要升级 Android Studio 4.0, 升级完成以后,注意以下事项:

  1. 安装 UE5 推荐的 SDK 和 NDK 版本
  2. 卸载 Android Studio 默认安装的高版本 SDK,不然会导致不兼容

如图,取消勾选高版本的 SDK

image

image

确保安装的是 UE 官网上推荐的版本。

然后在 UE5 的编辑器中,找到设置,然后搜索 Package game data inside .apk,并勾选 Package game data inside .apk 不然打包运行会报错,提示 no obb found and no store key ...

image

继续打开我们的项目代码,在主工程或者插件的 .cs 文件中加入如下配置:

.cs 配置

if (Target.Platform == UnrealTargetPlatform.Android)
{
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Launch"
// ... add private dependencies that you statically link with here ...\
}
);
}

如果你使用的是插件,则在主工程的 .cs 文件中引入你的插件:

在 .cs 中引用

PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Projects",
"UMG",
// ... add other public dependencies that you statically link with here ...
"xxxxxx Android(插件名)"
}
);

如果你使用到了 UPL,则需要在主工程或者插件中加入如下配置:

.cs 配置

if (Target.Platform == UnrealTargetPlatform.Android)
{
string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory+"/Android", Target.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(PluginPath, "xxxxxxxxxx\_APL.xml"));
}

注: xxxxxxxxxx_APL.xml 是对应的配置文件。 如果你是直接在 GameActivity.java 中集成逻辑的,可以忽略 UPL 这种方式。 UPL 的方式也是在 GameActivity.java 中去动态的插入 java 代码。

C++ To Java

那如何在UE5中用 C++ 中去调用 Java 呢!

我们目前知道 JNI 是可以实现 C++ 去调用 Java 代码的,在 UE5 中其实也用到了 JNI,JNI 我在这就不多做介绍了,想了解的可以自行的去查找资料。

第一步

引入 Android 平台所需的头文件

#if PLATFORM_ANDROID
#include "Android/AndroidApplication.h"
#include "Android/AndroidJNI.h"
#endif

注: PLATFORM_ANDROID 这个宏不能省略,需要用这个宏来包裹 Android 平台的逻辑

第二步

使用 JNI 来调用 Java,首先获取对应的类别,然后获取类中的方法,最后调用。

通过 JNIEnv* Env = FAndroidApplication::GetJavaEnv() 来得到 JNI 指针

然后通过 FJavaWrapper::FindMethod 来得到 jmethodID, 例如:

jmethodID GetPackageNameMethodID = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_InitName", "()V", false);

其中 UE5 中提供了胶水层 GameActivity.java 这个类来调用 Android 原生逻辑。 AndroidThunkJava_InitName 是我定义的 Java 方法,()V 是函数签名,函数签名根据你方法的返回值以及参数来确定。

最后通过 FJavaWrapper::CallVoidMethod 来执行 C++ 调用 Java 方法。 除了 CallVoidMethod 还有 FJavaWrapper::CallObjectMethod 用于调用返回值为对象的 Java 方法。

参考代码如下:

#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
jmethodID GetPackageNameMethodID = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_InitName", "()V", false);
if(GetPackageNameMethodID != nullptr)
{
UE_LOG(LogTemp, Warning, TEXT("Success to find method AndroidThunkJava_InitName"));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, GetPackageNameMethodID);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to find method AndroidThunkJava_InitName"));
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed get env"));
}
#endif

Java To C++

第一步

在 java 的类中去声明一个以 public native 开头的方法,譬如在 GameActivity.java 中声明 public native static void LoginCallBack(int result, String msg);

但是不用在该 java 类中去实现此 native 方法。

第二步

在 java 逻辑中去调用此 native 方法,这一步就是去 调用 C++ 层了。

第三步

回到 C++ 中去实现这个函数,如下:

JNI_METHOD void Java_com_lucky_android_LuckySDK_LoginCallBack(JNIEnv *env, jclass clazz, jint result, jstring msg) {
int32 FCode = static_cast<int32>(code);
FString FMsg = FJavaHelper::FStringFromParam(env, msg);

       ...

}

其中 Java 为语言,com_lucky_android LuckySDK 是类名, LoginCallBack 为方法

第四步

当前,你已经在 UE 中收到了 Java 调用你 C++ 函数的消息,自然而然的你就可以用 Delegate 的 ExecuteIfBound 方式或者其他方式,将收到的参数传给接下来要执行的逻辑。

结尾

好了,本次的分享到这里就结束了,在这里我提到了以下这些话题:Android Studio, UPL,JNI, 函数签名以及 Delegate, 感兴趣的的小伙伴们可以自行去搜索加深业务知识哦!

往期推荐

游戏反作弊系统接入:Part 1

游戏反作弊系统接入:Part 2

请你喝杯 ☕️ 点赞 + 关注哦~

最后,创作不易,如果对大家有所帮助,希望大家点赞支持,有什么问题也可以在评论区里讨论😄~**