Introduction to native plug-ins in Unity
Read time 4 minutesLast updated 12 days ago
A provides a C interface that you can access from managed (C#) scripts.
native plug-in
?
Unity native plug-in support uses the standard .NET Platform invoke feature. This feature lets C# code call unmanaged functions exported by native code libraries. It uses a process called marshalling to transfer data between managed and unmanaged code.
For an example of a native plug-in, check out the Simplest Plug-in example on Github.
Import native plug-ins
You can import native plug-ins into a Unity project in two basic forms:
- Binary files precompiled for specific platforms and CPU architectures.
- Source code files, which are compiled as part of your Unity project build process. (To use source code files as a native plug-in, your project must use the IL2CPP scripting backend.)
To work in Unity, a native plug-in must export its external functions using C linkage. This type of linkage avoids C++ name mangling and other Application Binary Interface (ABI) issues.
To access an unmanaged function from managed C# code, you declare a C# function with the same name and compatible return and parameter types, then call it like any other method. Refer to Call functions for the full declaration rules and examples.
static externUnity supports precompiled static libraries on Apple mobile platforms (iOS, tvOS and visionOS) and on Android. Plug-ins that you import into your Unity project as source code files are also statically linked. Unity supports source code plug-ins in projects that use the IL2CPP scripting backend. Source code plug-ins aren't supported for Editor scripts or when code runs in Play mode.
After you import plug-in files into your Unity project, you must set properties that determine when the library should be loaded. To do this, select the imported files in the Unity Project panel and set the relevant properties in the Inspector. Refer to Change plug-in settings for more information.
Interoperate with a native plug-in
The C# code that you write in Unity is managed by the scripting runtime. The scripting runtime manages where data is stored in memory and routinely moves data around to avoid memory fragmentation. Unmanaged code in a native plug-in, on the other hand, handles its own memory directly and can use pointers to address specific memory locations. When you write managed code that interoperates with unmanaged code, you have to be careful about where the data is stored, when the data is accessed, and which side is responsible for freeing memory that's no longer needed.
Some data types can be represented in different ways in managed code as compared to native code. .NET provides an interop marshaller that provides a default representation and conversion for most types. For situations where the default behavior is incorrect or suboptimal, the .NET Interop Services API provides the following attributes that you can use to explicitly define the desired representation and conversion for specific data types:
Refer to Pass data between managed and unmanaged code for more information.
Basic plug-in example
A simple, C-language native library with a single function might have code that looks like this:
float ExamplePluginFunction (){ return 5.0F;}
If you compiled this code separately and imported the compiled library into your Unity project, you could use the following C# script to call the :
ExamplePluginFunction()using UnityEngine;using System.Runtime.InteropServices;class ExampleScript : MonoBehaviour{ // Use the library file name for dynamically linked libraries. [DllImport ("PluginName")] private static extern float ExamplePluginFunction (); void Awake () { // Calls the ExamplePluginFunction inside the plugin // And prints 5 to the console Debug.Log (ExamplePluginFunction ()); }}
If you import the native code as source code, then you must use in the DllImport attribute rather than the library name:
__Internalusing UnityEngine;using System.Runtime.InteropServices;class ExampleScript : MonoBehaviour{ // Use __Internal instead of the library name for source-code plug-ins. [DllImport ("__Internal")] private static extern float ExamplePluginFunction (); void Awake () { // Calls the ExamplePluginFunction inside the plugin // And prints 5 to the console Debug.Log (ExamplePluginFunction ()); }}
Refer to DllImport attribute for more information on how to identify the native plug-in library to load.
Additional resources
Interoperation between managed and unmanaged code is a complex topic. This documentation is only intended to provide a brief orientation to the subject. Refer to the following .NET documentation to gain a more thorough understanding: