Let’s say we’re developing a game for mobile and we want to use one of the device functionalities, like reading the data from the light sensor, get the data from the contacts, or send a SMS: UE4 doesn’t provide an API for this, so we have no choice, we have to make this API ourselves. Fortunately, it’s really easy (if we follow this guide)! It’s easier if you’re familiar with the plugin system of UE4, but even if you’re not, this tutorial should be accessible (you should be confident with Android and Java development though).
Android Plugin Template.
Let’s not lose time! We want to make this plugin quickly (we only have ten minutes if you look at the title of this article), so we will use a template for an Android plugin. Unreal Engine, at least in its current version, doesn’t offer a template for a Android plugin. But you can download ours:
Just download this archive, create a “Plugins” directory next to your “Content” directory and unzip the archive inside this “Plugins” Directory. Now, we have a “Plugins/AndroidAPITemplate” folder inside the game directory. Now, we need to start (or restart) the engine so it can build the plugin.
Once the engine is started and the plugin is built, let’s go in “Settings”, then “Plugins”: under the “Mobile” category (at the end) we must see the “AndroidAPITemplate” plugin. Let’s click on the “Enabled” checkbox to enable the plugin. At this point we might have to restart (again) the engine.
Right now, this plugin contain only one function (callable from a blueprint): Show Toast under the category Android API Template. This function simply shows a Toast message with the given text parameter. Let’s make an actor which calls this function in its Begin Play event, then we put this actor in a scene, and send it to the Android phone (or tablet).
As expected, a Toast text is shown at the beginning.
The principle behind this.
Before we go any further, some explanations must be made. Let’s open the project C++ solution.
The functions exposed to blueprints are in the class UAndroidAPITemplateFunctions (in the files Classes/AndroidAPITemplateFunctions.h and Private/AndroidAPITemplateFunctions.cpp). As usual, the header file is giving the prototype of the functions and the meta data (in the UFUNCTION() macro) to allow them to be called by UE4, and in the Cpp file we have the implementation of these functions. Currently, we only have one function whose name is AndroidAPITemplate_ShowToast. Let’s look at its implementation.
void UAndroidAPITemplateFunctions::AndroidAPITemplate_ShowToast(const FString& Content)
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv(true))
{
// First step, we convert the FString (UE4) parameter to a JNI parameter that will hold a String
jstring JavaString = Env->NewStringUTF(TCHAR_TO_UTF8(*Content));
// Then we call the method, we the Java String parameter
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, AndroidThunkJava_AndroidAPI_ShowToast, JavaString);
}
#endif
}
First, we can note that the prototype is a pure classical UE4 prototype, with an FString as parameter. Then we also note that the whole is wrapped in a #if PLATFORM_ANDROID block, so this code won’t be called if we’re another platform. Now, the interresting part comes: we get a reference to the Java environement (which is of type JNIEnv), we convert the FString to a Java String and we use CallVoidMethod to call a method returning void named AndroidThunkJava_AndroidAPI_ShowToast which is a Java method.
And, in AndroidAPITemplate_APL.xml we can see the Java code associated to this function:
public void AndroidThunkJava_AndroidAPI_ShowToast(String toast) {
runOnUiThread(new Runnable() {
public void run() {
CharSequence cs = toast;
Toast.makeText(getApplicationContext(), cs, Toast.LENGTH_LONG).show();
}
});
}
So, to sum up:
- A classical UE4 C++ UFUNCTION is defined
- In the implementation, we get a reference to the Java environement
- We convert all parameters to the Java format (so an FString must become a jstring, a float must become a jfloat and so on)
- We use the FJavaWrapper class to make a call to a Java function defined in AndroidAPITemplate_APL.xml
Adding new functions to this template.
Well, showing Toast texts is fun but not really useful (actually it can be pretty useful because UE4 doesn’t provide an API for this). So let’s try what I was talking about earlier: reading the data from the light sensor (most of phones usually have a light sensor so it must be OK). We will not talk about sending SMS or reading contacts here because it would require us to ask for the user permission, we may see how to do it in another tutorial.
Preparing everything (Java side)
So first, we need to write the Java code of the functionality we want to add. We will do it in AndroidAPITemplate_APL.xml. If we look closely at this file, we can see that it corresponds to a standard Android activity written in Java (yes, it’s Java in Unreal Engine). So like any Activity class, we can add class members, functions or we can override parent functions like onCreate(), onResume(), onPause(), etc. The functions which are defined in gameActivityClassAdditions can be called from the C++ side.
To use sensors, we need to store a reference to the SensorManager and to the Sensor (let’s have a look here for mor information: https://developer.android.com/reference/android/hardware/SensorManager.html). So we add two members to the activity (like the example given on the android SDK documentation: the SensorManager and the Sensor), a SensorEventListener, and a variable to store the measure. All of this goes just before the definition of AndroidThunkJava_AndroidAPI_ShowToast.
private SensorManager mSensorManager;
private Sensor mLight;
private SensorEventListener mSensorListener;
private float mLastLightMeasure;
We will now initialize this class members, but it will be done in the onCreate() method of the activity. So in the of , we add this:
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); mSensorListener = new SensorEventListener() {
onAccuracyChanged(Sensor sensor, int accuracy) {
//
}
public void onSensorChanged(SensorEvent event) {
if(event.sensor == mLight)
mLastLightMeasure = event.values[0];
}
};
This code will initialize the SensorManager, initialize the light sensor, then make a new listener which will store the result of each light related event in the mLastLightMeasure variable. We now need to register this listener, we will do it in the onResume() method, so we put the following code in the of :
mSensorManager.registerListener(mSensorListener, mLight, SensorManager.SENSOR_DELAY_UI);
In the onPause() method we add the code to unregister the listener (so it doesn’t consume resources when the game’s process is not active):
mSensorManager.registerListener(mSensorListener, mLight, SensorManager.SENSOR_DELAY_UI);
Finally, we need to write the function that will return this measure and that will be called from the C++. This function is added next to the existing one, in <gameActivityClassAdditions>:
public void AndroidThunkJava_AndroidAPI_GetLastLightMeasure(float[] light) {
light[0] = mLastLightMeasure;
}
We can note that we are returning the result by parameter (it’s because the FJavaWrapper from UE4 doesn’t provide a CallFloatMethod, so returned values are usually output parameters of void functions).
Now we can move on the C++ part.
Binding Unreal Engine and Android (C++ part)
In AndroidAPITemplateFunctions.h we add the prototype that we want:
UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Keywords = "AndroidAPI ", DisplayName = "Get Last Light Measure"), Category = "AndroidAPI")
static float AndroidAPITemplate_GetLastLightMeasure();
The purpose of this function will be to return the last light measure. In AndroidAPITemplateFunctions.cpp, we will write what we need to call the Java method supposed to give us that value. The provided template already gives us some useful macros. So we just have to follow these steps:
- Add DECLARE_JAVA_METHOD(AndroidThunkJava_AndroidAPI_GetLastLightMeasure); next to the other DECLARE_JAVA_METHOD call.
- Add INIT_JAVA_METHOD(AndroidThunkJava_AndroidAPI_GetLastLightMeasure, “([F)V”); in InitJavaFunctions: the first parameter is the name of the Java function, the second is the Java signature (here it means “Array of float as parameter and void as returned value”).
- Write the implementation of AndroidAPITemplate_GetLastLightMeasure():
float UAndroidAPITemplateFunctions::AndroidAPITemplate_GetLastLightMeasure()
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv(true))
{
jfloatArray Result = Env->NewFloatArray(1);
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, AndroidThunkJava_AndroidAPI_GetLastLightMeasure, Result);
jfloat* ResultArr = Env->GetFloatArrayElements(Result, 0);
const float ResultFloat = ResultArr[0];
Env->DeleteLocalRef(Result);
return ResultFloat;
}
else
{
UE_LOG(LogAndroid, Warning, TEXT("ERROR: Could not get Java ENV\n"));
return 0;
}
#else
return 0;
#endif
}
This function works like the other one. We will make a call to the Java function using FJavaWrapper::CallVoidMethod, but first we need to prepare the parameter for this function, i we have to create a Java array (using NewFloatArray()). After the call, this array will contain the last measure from the light sensor. Then we extract this value from the Java float array, and we delete this array.
Now, we can rebuild this plugin, try to call this function from UE4, and for instance, adjust the luminosity of the game according to the ambient luminosity!
Conclusion
Well, I lied, if you follow this tutorial, it will take you more than 10 minutes 🙂 But I hope we’re not so far. The provided template should be useful for you: it gives you an example of how Android plugins are working, and it gives you a basis to develop your own plugin. If you want to go further, I suggest you to try new things and make different calls to the Android API. In a next tutorial, we may see how to do this for iOS (and it actually might be easier).
Thanks a lot for this!!!!
I can’t compile the base template on Unreal 4.21;
I add the AndroidAPITemplate folder in MyProject/Plugins, add the “AndroidAPITemplate” dependency on MyProject.build.cs (PublicDependencyModuleNames.AddRange(new string [] { “core”, [……],”AndroidAPITemplate”{); but when I try to compile targetting Android I get a “cannot open source file “AndroidAPITemplateClasses.h” in AndroidAPITemplatePrivatePCH.h and other files;
In AndroidAPITemplateFunctions.cpp I got an error about problems with string convertion.
I fixed it with changing the part to this:
void UAndroidAPITemplateFunctions::AndroidAPITemplate_ShowToast(const FString& Content)
{
#if PLATFORM_ANDROID
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv(true))
{
// First step, we convert the FString (UE4) parameter to a JNI parameter that will hold a String
jstring JavaString = Env->NewStringUTF(TCHAR_TO_UTF8(*Content));
// Then we call the method, we the Java String parameter
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis, AndroidThunkJava_AndroidAPI_ShowToast, JavaString);
}
#endif
}
Thank you for sharing your knowledge,
epic regards
I’m trying to compile this plugin for ue4 4.22, after compiling and running on android, after starting the app, ue4’s log says the initial method fetching FAndroidApplication :: GetJavaEnv (true) returns null, you would know the cause of it, if you have the version of this plugin for 4.22 would be great and could make it available, thanks
@Fabio
I build an own Plugin on knowledge Base of this great article, that runs with 4.22 maybe the Problem ist the ‘true’ in FAndroidApplication::GetJavaEnv(). In my initial JaveInterface method I call this without this parameter and it works find.
Thanks! This article inspire me!
Thank you so much for this tutorial.
I have been struggling with making an Android plugin to work with JNI for about three days. There is very little documentation on the net that pieces all the bits together. I have not yet managed to get the toast displaying however I can now get the light sensor showing up in a print to screen blueprint on version 4.23.1
Thank you
Hi thanks for this, It is still very relevant in v4.23 however Im having a little trouble working out how to pass Strings back through JNI. has anyone managed to do this?
Thank you.
jstring JavaString = *(FJavaHelper::ToJavaString(Env, Content));
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
Toast.makeText(this, toast, Toast.LENGTH_LONG).show();
#include “Android/AndroidApplication.h”
When I build the project I have this error
ERROR: Cannot make APK with UPL errors
I use UE 4.23.1 and Visual Studio 2017.
Does someone know how to solve this problem?
is there a version of this working on 4.24?
Thank you very much!
How to translate this Plugins to Version 4.24?
I took the liberty to update the tutorial file for 4.25 and uploaded it to GitHub (https://github.com/VRMonkey/NativeAndroidUE4Plugin).
Please let me know if I should exclude it from there.
I added due credits, of course.
Hi, thanks 😉 that’s great!
Thank you very much! Now I can access bluetooth services!
hi, have you some tutorial how to read data from bluetooth?
How to rebuild the plugin with dependencies
example import com.google.android.gms.ads.MobileAds
Hi, it would be nice to see a breakdown on a plugin that allow us to use Admob Rewarded Video Ad on UE4 (for Android), is probably the most wanted function that all indie devs search for, because UE4 doesnt has it.
I would pay someone to release it for the community for free.
I get the following error:
AndroidSystemIncludes.h(9): [C1083] Cannot open include file: ‘pthread.h’: No such file or directory
Anyone knows whats going on here?
I suggest using this plugin to call java code:
https://github.com/Sovahero/PluginMobileNativeCode
I builded plugin for 4.24 version 🙂 https://github.com/ultracheb/CustomUnrealPlagin/tree/master
Can you, please, give a link to ‘another tutorial’, where how to request permission is explained?