Unity is a great game engine to develop mobile games. It brings a lot of functionality with easy to use tools. But as you go deeper in creating Android games with Unity there comes a time when you have to extend Unity by your own Android Java plugins.
Unity's documentation is decent enough to get started. Sometimes in your Java code You need to call a Unity method. Unity has a way to do it through UnitySendMessage which is available when you extend UnityPlayerActivity (Or UnityPlayerNativeActivity). But I didn't want to extend UnityPlayerActivity, instead I wanted to write plugins for different jobs and make them useful in other projects too. I wanted to have several plugins for different jobs and seperated from each other so extending UnityPlayerActivity was not a good choice.
By the way, you may have 3rd-party plugins that already extend UnityPlayerActivity. In this article you will learn how to do it in this way (not extending UnityPlayerActivity)
NOTE: I suppose you know already how to create a Java plugin for unity. If you don't please see Unity's Documentation.
Unity Part
In Unity you have to prepare a GameObject with a name. In this article I use the default GameObject that you have when you create a new scene in Unity, Main Camera. Rename "Main Camera" to "MainCamera" (We will use this name in Java to call a Unity Method in the future).
Then write a script that contains a public method which receives a string as input and returns nothing (void) This is the method that's going to be called. Its name is also important because it is also used in Java code. maybe some method like this:
public void OnJavaCall(string message)
{
Debug.Log(message);
}
I kept it as simple as possible, the method just logs the message. Attach the script that you just wrote to the MainCamera.
The Java Part
In your Java code you can now call the method (OnJavaCall in this example). You have to write out code similar to what's shown below:
public static void CallUnityFunc(Activity activity)
{
Log.i(Tag, "Calling unity function");
try
{
Field UnityPlayer = activity.getClass().getDeclaredField("mUnityPlayer");
UnityPlayer.setAccessible(true);
Method method = UnityPlayer.getType().getDeclaredMethod("UnitySendMessage", String.class,String.class,String.class);
method.setAccessible(true);
method.invoke(activity, "MainCamera","OnJavaCall","Hello Unity , From Java");
}
catch(Exception e)
{
Log.e(Tag,e.getClass().toString()+" "+ e.getMessage());
}
}
I wrote a static method that takes an Activity as input. We will pass the Unity player to this Method in the future. In the method declaration as you can see I use reflection to call the UnitySendMessage. UnitySendMessage takes three parameters : The GameObject's name (MainCamera in this example), Method's name (OnJavaCall here), and the message that is going to be sent as an arguement to our method (OnJavaCall).
To test it now you have to compile your plugin (which is an Android library project) to generate a .jar file. After that you know of course you have to copy the .jar file to your Unity project.
Back to Unity
Then in Unity, call that static method (CallUnityFunc here) we wrote in Java to see how it works. for example:
AndroidJavaClass classPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = classPlayer.GetStatic("currentActivity");
AndroidJavaClass PluginClass = new AndroidJavaClass("com.helper.bazaarpayment.PluginClass");
// put your own package and class name accordingly to your Java plugin
//so let's call it
PluginClass.CallStatic("CallUnityFunc",activity);
Note that this code will not work until you actually run it on an Android device. It's good to check for runtime platform through Application.platform. Note that when you make this call to Java, The MainCamera (containing the script that has OnJavaCall) that we created must be present, otherwise there won't be any GameObject with name MainCamera that has a OnJavaCall method.
You may want to use GameObject.DontDestroyOnLoad to ensure you have MainCamera in all places. Compile and run to see how it works. You can use the adb interface located at platform-tools folder in your Android sdk folder. With command: adb logcat -s Unity you can see Unity logs.
With this approach you don't have to extend UnityPlayerActivity. You can have self-contained plugins for distinct tasks. You can also leave 3rd-party plugins that extend UnityPlayerActivity to work untouched.
What is this useful for ?
The functionality of sending a message is already there (you're just calling it using reflection).
Also, how is it useful is you are hard-coding it to only call a single Unity object?