JNI Exception using Android Plugin

Hi,

I’m trying to integrate the DeployGate SDK into my unity game for android. Here’s what it says on their website:

If your project has an Application class specified in in your AndroidManifest.xml, open that class and add following line into onCreate() function: DeployGate.install(this);

https://deploygate.com/docs/sdk

So I downloaded the deploygatesdk.jar, copied it to /Assets/Plugins/Android, and used it on startup (C# MonoBehaviour called DeployGate.cs) like this:

	void Start () {

        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");

        AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

        AndroidJavaObject app = activity.Call<AndroidJavaObject>("getApplicationContext");

        AndroidJavaClass dg = new AndroidJavaClass("com.deploygate.sdk.DeployGate");

        dg.CallStatic("install", app);

	}

When I start the game on android, LogCat reports these Errors:

04-14 01:51:14.389: I/Unity(17702): ExecutionEngineException: JNI Exception

04-14 01:51:14.389: I/Unity(17702):   at UnityEngine.AndroidJavaObject._CallStatic (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0 

04-14 01:51:14.389: I/Unity(17702):   at UnityEngine.AndroidJavaObject.CallStatic (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0 

04-14 01:51:14.389: I/Unity(17702):   at DeployGate.Start () [0x00034] in D:\Unity\TestGame\Assets\Scripts\DeployGate.cs:15 

04-14 01:51:14.389: I/Unity(17702):  

04-14 01:51:14.389: I/Unity(17702): (Filename: D Line: 0)

D:\Unity\TestGame\Assets\Scripts\DeployGate.cs:15 is the project path on my windows PC. This is weird. Any idea how to resolve this Exception?

EDIT: I activated debug-checkjni in adb and this exception might be more of a help:

04-14 10:22:25.826: W/System.err(28435): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
04-14 10:22:25.846: W/System.err(28435): 	at android.os.Handler.<init>(Handler.java:197)
04-14 10:22:25.846: W/System.err(28435): 	at android.os.Handler.<init>(Handler.java:111)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.<init>(DeployGate.java:207)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.install(DeployGate.java:467)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.install(DeployGate.java:441)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.install(DeployGate.java:418)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.install(DeployGate.java:369)
04-14 10:22:25.846: W/System.err(28435): 	at com.deploygate.sdk.DeployGate.install(DeployGate.java:349)
04-14 10:22:25.846: W/System.err(28435): 	at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
04-14 10:22:25.846: W/System.err(28435): 	at com.unity3d.player.UnityPlayer.onDrawFrame(Unknown Source)
04-14 10:22:25.846: W/System.err(28435): 	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
04-14 10:22:25.846: W/System.err(28435): 	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)

According to Google it has to run on the uithread to work. Do I have to edit the jar file to achieve that?

1 Answer

1

Ok, I’m gonna solve this myself. Here’s how I did it:

public static class DeployGate {

    private static AndroidJavaClass deployGate = null;

    public static void Install() {
        // Get Android context
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject app = activity.Call<AndroidJavaObject>("getApplicationContext");

        // Install DeployGate, make sure it will not called twice in your app
        deployGate = new AndroidJavaClass("com.deploygate.sdk.DeployGate");

        activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
        {
            deployGate.CallStatic("install", app);
        }));
	}
}

So

            activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
            {
                deployGate.CallStatic("install", app);
            }));

makes the call run on the uithread, additionally, I made everything static since DeployGate should only be installed once and should be persistent through level changes (but that didn’t have anything to do with my errors).
So it’s not a MonoBehaviour anymore, instead I call it like this:

DeployGate.Install();

I hope this’ll help someone who stumbles upon this with the same problem. Here’s the whole class with a few basic methods:

using UnityEngine;
using System.Collections;

public static class DeployGate {

    private static AndroidJavaClass deployGate = null;

    public static void Install() {

        // Get Android context
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject app = activity.Call<AndroidJavaObject>("getApplicationContext");

        // Install DeployGate, make sure it will not called twice in your app
        deployGate = new AndroidJavaClass("com.deploygate.sdk.DeployGate");

        activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
        {
            deployGate.CallStatic("install", app);
        }));
	}

    public static void LogError(string text) {
        deployGate.CallStatic("logError", text);
    }

    public static void LogWarn(string text) {
        deployGate.CallStatic("logWarn", text);
    }

    public static void LogDebug(string text) {
        deployGate.CallStatic("logDebug", text);
    }

    public static void LogInfo(string text) {
        deployGate.CallStatic("logInfo", text);
    }

    public static void LogVerbose(string text) {
        deployGate.CallStatic("logVerbose", text);
    }
}

Source: https://github.com/anchan828/deploygate-with-unity/blob/master/Assets/DeployGate/Plugins/DeployGateSDK.cs

Thanks! You saved my life!!! :D

Why does it have to run in "runOnUiThread" ?

I am not using deployGate rather a custom Android SDK. This worked thanks.

Thanks a lot! :)