Notifications
Article
Cross-Platform Native (Unmanaged) Plugins
Published 6 days ago
7
0
Making non-cross platform code a cross-platform reality
Often when using Unity, you'll receive third party drivers/plugins/libraries from 3rd party vendors. These are often wrapped as blackbox files and you're only given the APIs for them. Fear not! They can be used in Unity with some workarounds by implementing Native (Unmanaged) Plugins.
As a side note, Unity also supports Managed Plugins written in C#. The benefit with Managed Plugins, is that they're generally capable of cross-platform usage by writing the code once in C#. We will not cover how to do this in this tutorial, but there are tutorials can be found on Google. If I have time at a later date, I can write another tutorial for the steps to deal with that (which is going to be much simpler than what will be covered in this tutorial).

Scenario

You have some drivers from a third party hardware provider. Let's say that this hardware is a steering wheel, and the hardware provider has provided a .dll file for you compiled in C/C++ for Windows that you would like to bring into Unity so that you can integrate the steering wheel with your application.
Alternatively, you could have your own scripts and libraries written in your own native languages and you wish to bring those into Unity.

Solution

We will cover the use case of a very basic random number generator written in native code that will run through 5 major platform scenarios: Windows, OSX, Linux, Android, iOS.
IMPORTANT NOTE: If you're compiling a library for a specific OS, you need to build it using that specific OS. For example, if you're making a Linux library, you need to compile it using a Linux machine.
1) Windows
Open Visual Studio and create a new Win32 Console Application project named RandomNumberDLL. Create a new C++ file called RandomNumber.cpp and fill it with the following contents:
#include <iostream> extern "C" int GetRandom() { return rand(); }
Build the file out to a dll RandomNumberDLL.dll and copy it into your Unity Project into either of the following paths: Plugins/, Plugins/x86, Plugins/x86_64, Plugins/Win/, Plugins/Win/x86, Plugins/Win/x86_64 depending on how you want to sort your folders.
In your Project window, select your newly imported file, and make sure you have assigned the appropriate target platform(s).
To use the newly created C/C++ function in Unity, create a new MonoBehaviour and paste this into the body of the new script:
#if UNITY_EDITOR_WINDOWS || UNITY_STANDALONE_WINDOWS private const string LIBRARY_NAME = "RandomNumberDLL"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
You can now get access to the C/C++ function in your C# MonoBehaviour under Windows by calling GetRandom().
IMPORTANT NOTE: The ".dll" file extension is not required for the DllImport syntax.
2) OSX
Open Xcode and create a new project. Under Framework & Library, choose Bundle and name the project RandomNumberPlugin. After the project has been created, add the framework to the project:
/Applications/Unity/Unity.app/Contents/PlaybackEngines/macstandalonesupport/Variations/universal_development_mono/UnityPlayer.app/Contents/Frameworks/MonoEmbedRuntime/osx
When you're done, create a C++ file and paste the follow code above in and build:
#include <iostream> extern "C" int GetRandom() { return rand(); }
Find the path of RandomNumberPlugin.bundle by right clicking it in the left panel and selecting show in finder.
Copy the file into your Unity Project into either of the following paths: Plugins/, Plugins/x86, Plugins/x86_64, Plugins/MacOS/, Plugins/MacOS/x86, Plugins/MacOS/x86_64 depending on how you want to sort your folders.
In your Project window, select your newly imported file, and make sure you have assigned the appropriate target platform(s).
To use the newly created C/C++ function in Unity, create a new MonoBehaviour and paste this into the body of the new script:
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX private const string LIBRARY_NAME = "RandomNumberPlugin"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
You can now get access to the C/C++ function in your C# MonoBehaviour under OSX by calling GetRandom().
IMPORTANT NOTE: The ".bundle" file extension is not required for the DllImport syntax.
3) Linux
Using vim, nano, sublime or your favorite text editor, create a new file called Plugin.cpp. Paste the following contents into the file:
#include <iostream> extern "C" int GetRandom() { return rand(); }
Save the file and inside bash run the following:
g++ *.cpp -O3 -fPIC -shared -o libRandomNumberSO.so
Note this following compiles all .cpp files in your current directory. You can choose to compile a specific .cpp file if needed.
SUPER IMPORTANT: Linux libraries need to start with the lib* prefix or it will not work in Unity.
Copy the file into your Unity Project into either of the following paths: Plugins/, Plugins/x86, Plugins/x86_64, Plugins/Linux/, Plugins/Linux/x86, Plugins/Linux/x86_64 depending on how you want to sort your folders.
In your Project window, select your newly imported file, and make sure you have assigned the appropriate target platform(s).
To use the newly created C/C++ function in Unity, create a new MonoBehaviour and paste this into the body of the new script:
#if UNITY_STANDALONE_LINUX private const string LIBRARY_NAME = "RandomNumberSO"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
You can now get access to the C/C++ function in your C# MonoBehaviour under Linux by calling GetRandom().
IMPORTANT NOTE: The ".so" file extension and the "lib" prefix is not required for the DllImport syntax.
4) iOS
Using your favorite text editor, create a file called Plugin.cpp and paste in the following contents:
#include <iostream> extern "C" int GetRandom() { return rand(); }
For iOS it works a bit differently. Instead of compiling the file, we can just directly copy and put it into the Unity project's plugin folder: Plugins/, Plugins/iOS depending on how you want to sort your folders.
In your Project window, select your newly imported file, and make sure you have assigned the appropriate target platform(s).
To use the newly created C/C++ function in Unity, create a new MonoBehaviour and paste this into the body of the new script:
#if UNITY_IOS private const string LIBRARY_NAME = "__Internal"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
When building out your Xcode project for iOS, it will automatically copy those over into the project where they can be directly used.
You can now get access to the C/C++ function in your C# MonoBehaviour under iOS by calling GetRandom().
5) Android
This is the most complicated of them all so bear with me... There are two ways to import native code for Android: .jar and .so. Since we are using C/C++, we will skip the .jar method (since it bundles .class files) and opt for the .so version.
IMPORTANT NOTE: There is a bug with Android SDK version for using "rand()", looking around StackOverflow, people are saying that you need to target SDK v19/v21 in order for it to work. I didn't get it to work but other C code still works. For this example we will just be returning -1.
Create a new file called RandomNumberAndroid.cpp and paste in the following code:
#include <jni.h> #include <iostream> extern "C" int GetRandom() { return -1; }
Begin by downloading Android Studio and follow the instructions here: https://developer.android.com/ndk/guides/index.html to setup your system for NDK
After you've installed LLDB, CMake and NDK, create a new project and include C++ libraries and press next until you are finished. You will then be presented with a boilerplate project that has a cpp folder with a pre-populated native-lib.cpp.
You can write your native code here or create your own cpp by right clicking the folder and choosing C/C++ Source File. We will create a new file called RandomNumberAndroid.cpp. Please note that the newly created cpp will not show up in your project by default (even though the file is created in the cpp folder). You must import it via a few lines in gradle and CMakeLists.txt.
Open Up CMakeLists.txt, and you will see the boilerplate file and notable the following lines:
add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). # Associated headers in the same location as their source # file are automatically included. src/main/cpp/native-lib.cpp )
Copy and paste that line while renaming the native-lib to the name of your newly created cpp (without the file extension) RandomNumberAndroid and update the path in the last line to src/main/cpp/RandomNumberAndroid.cpp. Rebuild/sync gradle and it should show up now in your cpp folder on the left.
There is one more thing to add before it will actually export the .so files.
Open up MainActivity.java and you will see a line that looks like this:
System.loadLibrary("native-lib");
Replace it with:
System.loadLibrary("RandomNumberAndroid");
You can press Play to make sure it compiles and everything loads fine.
From here, we must export the project as an .apk file to get access to the compiled libraries. So press Build > Build APK and locate the path where the file has been built to. Rename the .apk to .zip and decompress the package. You will see a lib folder with your .so files compiled for all the compatible architectures.
Copy these files into your Unity Project into either of the following paths: Plugins/, Plugins/Android depending on how you want to sort your folders.
Keep in mind that the file format for the .so file will be libRandomNumberAndroid.so.
In your Project window, select your newly imported file, and make sure you have assigned the appropriate target platform(s).
To use the newly created C/C++ function in Unity, create a new MonoBehaviour and paste this into the body of the new script:
#if UNITY_ANDROID private const string LIBRARY_NAME = "RandomNumberAndroid"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
IMPORTANT NOTE: The ".so" file extension and the "lib" prefix is not required for the DllImport syntax.
You can now get access to the C/C++ function in your C# MonoBehaviour under Android by calling GetRandom().
---

Bringing it all together

#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX private const string LIBRARY_NAME = "RandomNumberBundle"; #elif UNITY_EDITOR_WINDOWS || UNITY_STANDALONE_WINDOWS private const string LIBRARY_NAME = "RandomNumberDLL"; #elif UNITY_STANDALONE_LINUX private const string LIBRARY_NAME = "RandomNumberSO"; #eli UNITY_IOS private const string LIBRARY_NAME = "__Internal"; #eli UNITY_ANDROID private const string LIBRARY_NAME = "RandomNumberAndroid"; #elif UNITY_EDITOR //private const string LIBRARY_NAME = "RandomNumber"; #endif [DllImport(LIBRARY_NAME)] private static extern int GetRandom ();
Then inside your MonoBehaviour scripts, just call:
GetRandom()
Depending on your target platform, it will choose the appropriate plugin and everything should work just fine.
---
Credits: https://www.youtube.com/watch?v=DfRYLwG1Bug

Warren Wang
CEO - Programmer
11
Comments