Java and Kotlin plug-in code can call your C# scripts, for example, to notify Unity of an Android event or to return a result from your plug-in code. There are two ways to do this:
UnitySendMessage.For the equivalent C# to Java and Kotlin implementation, refer to Calling Java and Kotlin plug-in code from C# scripts.
Note: To debug either approach, set AndroidJNIHelper.debug to true to log the JNI activity that Unity performs for each call.
Use UnitySendMessage to send a string from Java or Kotlin plug-in code to a method on a named GameObject. This is a one-way call where the C# method receives the string but doesn’t return a value to the plug-in. Use it for simple notifications.
The plug-in calls UnitySendMessage with three arguments: the name of the target GameObject, the name of the method to call, and the string message.
The following Java example implements UnitySendMessage:
package com.example.androidplugin;
import com.unity3d.player.UnityPlayer;
public class MessageSender {
public static void sendToUnity(String gameObjectName) {
UnityPlayer.UnitySendMessage(gameObjectName, "OnMessageReceived", "Hello from Java");
}
}
The following Kotlin example implements UnitySendMessage:
package com.example.androidplugin
import com.unity3d.player.UnityPlayer
object MessageSender {
@JvmStatic
fun sendToUnity(gameObjectName: String) {
UnityPlayer.UnitySendMessage(gameObjectName, "OnMessageReceived", "Hello from Kotlin")
}
}
In your C# script, add the method that UnitySendMessage calls. Ensure the script is attached to a GameObject whose name matches the first argument.
using UnityEngine;
public class MessageReceiver : MonoBehaviour
{
void Start()
{
gameObject.name = "MessageReceiver";
using var sender = new AndroidJavaClass("com.example.androidplugin.MessageSender");
sender.CallStatic("sendToUnity", gameObject.name);
}
void OnMessageReceived(string message)
{
Debug.Log("Message from plug-in: " + message);
}
}
This example:
UnitySendMessage to send a string back to the OnMessageReceived method on the named GameObject.
Note: In this example, C# calls the plug-in directly to trigger the message, so you can run the example without an Android event. In a real project, the plug-in calls UnitySendMessage in response to an Android event, such as a button tap or a lifecycle callback.
UnitySendMessage has the following limitations:
void MethodName(string message).To send data other than a string, serialize it to a JSON string. For more information, refer to Supported data types for Java/Kotlin and C# code.
Use AndroidJavaProxy to implement a Java or Kotlin interface in C#. When the plug-in calls a method on the interface, Unity runs your C# implementation. Use this approach for typed callbacks, or to pass structured data or return values.
Define an interface in the plug-in and a class that calls it. The following plug-in code calls the interface method to pass a message back to C#.
package com.example.androidplugin;
public class Greeter {
public interface GreetingCallback {
void onGreeting(String message);
}
public void requestGreeting(GreetingCallback callback) {
callback.onGreeting("Hello from Java");
}
}
package com.example.androidplugin
class Greeter {
interface GreetingCallback {
fun onGreeting(message: String)
}
fun requestGreeting(callback: GreetingCallback) {
callback.onGreeting("Hello from Kotlin")
}
}
In your C# script, create a class that derives from AndroidJavaProxy and implements the interface. Pass an instance of this class to the plug-in.
using UnityEngine;
public class GreetingExample : MonoBehaviour
{
class GreetingCallback : AndroidJavaProxy
{
public GreetingCallback() : base("com.example.androidplugin.Greeter$GreetingCallback") { }
void onGreeting(string message)
{
Debug.Log("Greeting from plug-in: " + message);
}
}
void Start()
{
using var greeter = new AndroidJavaObject("com.example.androidplugin.Greeter");
greeter.Call("requestGreeting", new GreetingCallback());
}
}
This example:
GreetingCallback class that derives from AndroidJavaProxy and passes the interface name to the base constructor. Because GreetingCallback is nested in the Greeter class, the name uses the $ separator: com.example.androidplugin.Greeter$GreetingCallback.onGreeting with a signature that matches the interface method. Unity automatically routes calls on the interface to this C# implementation.AndroidJavaObject for the Greeter plug-in class and calls requestGreeting, passing the proxy. The plug-in then calls onGreeting, which runs the C# implementation.Note: In this example, the plug-in calls the interface method on Unity’s main thread. If your plug-in calls the method from a background thread, the C# implementation also runs on the background thread. In this case, use AndroidApplication.InvokeOnUnityMainThread to run any Unity API calls on the main thread.
For more information on writing the plug-in code, refer to Java and Kotlin source plug-ins.