Download

Android Java Libraries in UE4 Game (OUYA SDK, Google Play Game Services, etc.)

I’ve also submitted a PR for adding an Android input callback.
https://github.com/EpicGames/UnrealEngine/pull/2314

Here’s the C++ plugin project:

Header:

Implementation:

This relates to JAR handling because I add special controller remapping in the JAR and use this callback to pass Android input to a JAR, which gets remapped and then passed back to the UE4 plugin.

The result is that I can add support to the framework for new controllers and mappings without needing to rebuild/republish the UE4 games and apps.

Thanks for all this detail. Now, I want to use some functions of a JAR file in GameActivity.java. What should I do? What files need I to modify? please give me some suggestions. Thank you again.lib.pnglib.pnglib.png lib_dir.png src.png src_dir.png

You should just need to place your JAR file:
https://github.com/tgraupmann/UnrealEngine/tree/4.10-Cortex/Engine/Build/Android/Java/libs

And then you import your package right in the GameActivity.
https://github.com/tgraupmann/UnrealEngine/blob/4.10-Cortex/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java#L77

Although that requires building UE4 from source and my previous example shows how to add your JAR from a UE4 plugin that would work in the retail version of UE4.

That is assuming they accept my changes. I submitted a PR against the 4.11 branch. Does anyone know if they prefer that or if I submit against the master branch instead?

Thanks!

Can I ask what functions are you calling in GameActivity.java and from what methods? I’m adding to the PR which adds a listener to expose more Java events to UE4 plugins.

Of course, I need to add a bunch of comments for each of these Activity methods.

You can see with these added callbacks, you’ll have access to invoke your JAR/Java methods from your UE4 plugin without modifying the engine’s GameActivity.java.

Here is the logcat showing the example log lines.

I have two outstanding PRs.

Added a callback for the JNI_OnLoad event to be used by UE4 plugins - https://github.com/EpicGames/UnrealEngine/pull/2313
Add Android Input callback - https://github.com/EpicGames/UnrealEngine/pull/2314

The result of all this is that I’ll be able to release a Cortex/OUYA plugin to the marketplace. So a game developer would just need to get an example project like Tappy Chicken and then add the Cortex plugin from the marketplace. The user builds for Android and the game would work with a controller on the Forge TV Android console. And that’s without touching any code.

Thank you very much! I have solved my problem. The problem is that I imported a wrong package. ;):wink:

I merged both PRs into a new branch while I wait for approval.
The new branch - https://github.com/tgraupmann/UnrealEngine/tree/4.11-Cortex

Now I’ll focus on rewriting the OUYA/Cortex plugin as a UE4 plugin instead of embedding the plugin into the UE4 engine source.
The old way - https://github.com/tgraupmann/UnrealEngine/tree/4.10-Cortex

I’ve created an Example Project that uses a UE4 plugin to load JAR/Java classes.

The example project referenced my plugin “OuyaSDKPlugin” in the build script.

I’ve created my UE4 plugin here:

I placed the JAR for the plugin here:

I placed the Java source for the plugin here:

I can build successfully, so that’s good. Now I just have to figure out how to get the plugin to initialize.

I need to figure out how to get the StartupModule() method in the UE4 plugin loading which should put something in the logcat.

I can see that the plugin is enabled using the menu item Edit->Plugins and slicking on Project I see the plugin has enabled checked.

The type of plugin that I’m creating is referred to as an “Installed Plugin” in the docs.

Is there anything special needed to get a UE4 Plugin to load in Android?

I’ve added logging in the UE4 Plugin StartupModule().

The UE4 editor log shows the message:
LogOuyaSDKPlugin: *** OuyaSDKPlugin has loaded. ***

But when the game loads on Android I’m not seeing the entries appear in the logcat.

Hi tgaupmann,

The Android Plugin Language is the proper way to do what you are trying to do here. The GameActivity.java can be patched by the plugin and copying of dependencies (assets, libs, jars) can be done with it on a conditional basis. Also, there is no need to hook into JNI_OnLoad. Here is an example from earlier GearVR.cpp:


// call out to JNI to see if the application was packaged for GearVR
bool AndroidThunkCpp_IsGearVRApplication()
{
	bool bIsGearVRApplication = false;
	if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
	{
		static jmethodID Method = FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_IsGearVRApplication", "()Z", false);
		bIsGearVRApplication = FJavaWrapper::CallBooleanMethod(Env, FJavaWrapper::GameActivityThis, Method);
	}
	return bIsGearVRApplication;
}

In your OuyaSDKPlugin.Build.cs you will want to add:


			if (Target.Platform == UnrealTargetPlatform.Android)
			{
				string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath);
				AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(PluginPath, "OuyaSDKPlugin_APL.xml")));
			}

Then you can make an OuyaSDKPlugin_APL.xml in the same directory as the OuyaSDKPlugin.Build.cs. Look at GearVR_APL.xml in Engine/Plugin/Runtime/GearVR/Source/GearVR for an example. The top comment block in AndroidPluginLanguage.cs documents the XML-based language.

As for the loading issue, try adding Android to the white-list in the .uplugin (take a look at GearVR.uplugin).

Thanks for the hints. I’ll take a look!

https://github.com/EpicGames/UnrealEngine/blob/4.11/Engine/Plugins/Runtime/GearVR/GearVR.uplugin

https://github.com/EpicGames/UnrealEngine/blob/4.11/Engine/Plugins/Runtime/GearVR/Source/GearVR/GearVR.Build.cs

https://github.com/EpicGames/UnrealEngine/blob/4.11/Engine/Plugins/Runtime/GearVR/Source/GearVR/GearVR_APL.xml

I’ll adapt to your suggestions. Thanks for the feedback!

With the whitelist option, I can see logging now!

I can see my void FOuyaSDKPlugin::StartupModule() is being invoked now!

It appears that the module is loaded after the JNI_OnLoad event and so FAndroidApplication::GetJavaEnv() will be the way to get the JNI environment after all.

I’ll incorporate that change next.

BOOM!

Looks like something failed to find the class from the JAR and Java.

Since I’m using the JNIEnv outside the JNI_OnLoad event, I think that’s the reason why the class lookup fails. You have one chance to look up non-system classes in that event.

Later, in another thread I could invoke methods on those classes with something like.

Looking at the design of the AndroidJNI.cpp I see you are doing GearVR lookups in that class. With a JNI_OnLoad event callback that would allow all the GearVR code to operate within it’s own plugin.

The class lookups fail whether I use JNIEnv directly or use the FJavaWrapper helper methods.

The class lookup does succeed if I used the callbacks from the game code.

Unfortunately, the JNI_OnLoad event seems like the ONLY time certain classes can be looked up. (I left some details about this in the previous post.)

Using the callback method and using a global variable constructor to register the JNI_OnLoad callback is fast enough to register the event and detect the classes successfully, all from a UE4 plugin.

There are some issues with bundling JAR/Java in a UE4 plugin, however. The Java and JAR file is not detected when provided by the plugin.

I had to move the JAR/Java into the game module.
https://github.com/tgraupmann/UE4_Plugin_Cortex_App_Store/blob/master/ExampleProject/Build/Android/libs/ouya-sdk.jar
https://github.com/tgraupmann/UE4_Plugin_Cortex_App_Store/blob/master/ExampleProject/Build/Android/src/tv/ouya/sdk/PluginTestGameActivity.java
https://github.com/tgraupmann/UE4_Plugin_Cortex_App_Store/blob/master/ExampleProject/Build/Android/src/tv/ouya/sdk/TestOnGameActivityListener.java

Here is the UE4 plugin code using a global variable constructor to register the JNI_OnLoad callback.

I’ll try to incorporate the other suggestions to minimize how much code is in the PRs.

I’ll have to look into that. Maybe that’s how I can avoid needing to copy the JAR/Java to the game module…

The AndroidPluginLanguage is quite powerful. The best docs can be found here.
https://github.com/EpicGames/UnrealEngine/blob/4.11/Engine/Source/Programs/UnrealBuildTool/Android/AndroidPluginLanguage.cs

The best example can be found here:
https://github.com/EpicGames/UnrealEngine/blob/4.11/Engine/Plugins/Runtime/GearVR/Source/GearVR/GearVR_APL.xml

I was able to create my own UE4 plugin APL.xml file.

And reference the APL.xml from the UE4 plugin build script.

And now I have the JAR and JAVA being used directly from the UE4 plugin.

I’ll see if I can make use of the injected Java using the AndroidPluginLanguage next…

Reducing the number of changes in the PR…
https://github.com/EpicGames/UnrealEngine/compare/4.11...tgraupmann:4.11-Cortex?expand=1

I have the changes I need slimmed down to the Android JNI_OnLoad event callback and Android Input callback.
https://github.com/EpicGames/UnrealEngine/pull/2313/files
https://github.com/EpicGames/UnrealEngine/pull/2314/files

This is all so I can roll my Cortex/OUYA fork into a UE4 plugin. Developers don’t want to have to build the engine from source. Also as a plugin, it can be activated with the menu toggle.

I found one more issue. If I want to add android:game to the AndroidManifest.xml I need to make sure the APK is being built with API-21 or better build tools. How might I configure UE4 to do that? I’m already specifying a target version of 21. That should be enough.???

I am getting the expected manifest changes. It’s just the packaging tool needs to use the newer API???

[QUOTE=tgraupmann]

That worked for exactly the reason Chris said. It uses the class loader from JNI_OnLoad.

That means I can close the PR that added the JNI_OnLoad callback.
https://github.com/EpicGames/UnrealEngine/pull/2313/files

I still need the input callback to do input remapping. There’s no existing functionality that exposes that.
https://github.com/EpicGames/UnrealEngine/pull/2314/files

Accessing JAR/Java from a UE4 plugin is working like a charm.

You can see I only needed to use FAndroidApplication::FindJavaClass from the UE4 StartupModule to be able to find classes from the JAR/Java. After finding the class I can use JNIEnv normally to find methods, fields, static methods, and invoke per the usual.

You can set the SDK API level to android-21 in Android SDK project settings in the editor. You can set it as high as android-22 if you have it installed, but do not set it to android-23 or android-24 yet; I need to update the APK expansion library code to remove depreciated APIs first.

Ah yes. That worked like a charm. I was looking in the Android project settings, but there’s the Android SDK project settings with NDK API Level which needed to be set to android-21. I did noticed when I saved changes that this setting doesn’t appear to serialize to disk.

And here is where I enabled the android:isGame setting.

That leaves the last PR. I need the Android input callback to do input remapping. I can’t see any existing functionality that exposes that.
https://github.com/EpicGames/UnrealEngine/pull/2314/files

With this input callback is where I pass the input to Java, pass it through a framework, and then return the remapped input back to the UE4 plugin. This allows games to publish in the Cortex store and as the framework adds support for new controllers, the games won’t need to republish to get all the new mappings.

With the PR request I’ve been able to intercept all the controller KeyEvent and MotionEvent input and redirect that to the UE4 plugin.

Turns out I don’t need the input PR. A plugin can reroute the Android input with the following.

First get the extern.

// reassign android input callback

No PR needed!

Would this information work with implementing Facebook or NativeX SDKs? I’m attempting to setup pay per install advertising but I’m having a terrible time at doing so. I’m starting to regret spending time learning the engine because it’s near impossible to profit off any mobile makings.

This information is useful for any Android UE4 plugin.

But what I’m referring to is an SDK, not specifically a plugin. To run pay-per-install ads on Facebook you need to use the Facebook SDK and activate your app when it starts



@Override
public void onCreate() {
    super.onCreate();
    FacebookSdk.sdkInitialize(getApplicationContext());
    AppEventsLogger.activateApp(this);
}


They have a decent looking guide but I’m not sure how to import only the part of the SDK I need, and how to call the java code from UE4. If this thread covers that I can look more thoroughly through it; I’m still learning things here – so I wanted to know if my request is supported with this method before I go about researching it.