Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


Calling C# code from Java and Kotlin plug-in code

Call C# script code from your Java and Kotlin plug-in code.
Read time 4 minutesLast updated 9 days ago

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:
  • Send a message to a GameObject with
    UnitySendMessage
    .
  • Call a C# method through a callback interface with AndroidJavaProxy.
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.

Send a message to a GameObject

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.androidpluginimport com.unity3d.player.UnityPlayerobject 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:
  1. Sets the GameObject's name to match the target name the plug-in sends.
  2. Calls the plug-in, which uses
    UnitySendMessage
    to send a string back to the
    OnMessageReceived
    method on the named GameObject.
  3. Logs the message that the plug-in sends.
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:
  • You can only call C# methods with the signature
    void MethodName(string message)
    .
  • Calls are asynchronous and have a delay of one frame.
  • Multiple GameObjects with the same name can cause conflicts.
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.

Call a C# method through a callback interface

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#.

Java plug-in code

package com.example.androidplugin;public class Greeter { public interface GreetingCallback { void onGreeting(String message); } public void requestGreeting(GreetingCallback callback) { callback.onGreeting("Hello from Java"); }}
### Kotlin plug-in code
package com.example.androidpluginclass 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:
  1. Creates a C#
    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
    .
  2. Implements
    onGreeting
    with a signature that matches the interface method. Unity automatically routes calls on the interface to this C# implementation.
  3. Creates an
    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.

Additional resources