Guide to Using DLLs in Unity
Today’s article guides you through the necessary steps to create, use, and debug a .NET DLL in Unity. These can help you modularize your code into libraries that can be imported as a single file by the users of your library. They’re especially useful when utilizing the “pure code” approach to code design as you can easily break up a Unity app’s monolithic structure into reusable components. So read on to learn how to use DLLs in Unity!
First of all, let’s talk about what a .NET DLL is. Simply put, it’s a file that contains one or more compiled .NET scripts. These are usually C#, but could be any other .NET language such as F# or IronPython. In fact, when you just add scripts directly to your Unity project, they are automatically compiled into a DLL stored in MyProject/Library/ScriptAssemblies/Assembly-CSharp.dll.
So how can you make a DLL of your own? The Unity editor doesn’t provide any way to build them, so you’ll need to make use of external tools like MonoDevelop, Xamarin Studio, or Microsoft Visual Studio. We’ll talk about each of them since they’re all common in Unity development.
MonoDevelop (version included with Unity 5.0.2f1)
- File > New > Solution
- C# > Library
- Choose a project name and directory > OK
- Project > ProjectName Options
- Build > General > Target framework > Mono / .NET 2.0
- Project > Edit References > .NET Assembly
- Navigate to /Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll
- OK
- Add your code to the project
- Build > Build All
- The DLL is placed in ProjectDirectory/bin/Debug/ProjectName.dll
Xamarin Studio (as of 5.9.1 build 3)
- File > New > Solution
- Other > .NET > Library > Next
- Choose a project name and directory > Create
- Project > ProjectName Options
- Build > General > Target framework > Mono / .NET 2.0
- Project > Edit References > .NET Assembly > Browse…
- Navigate to /Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll
- Open > OK
- Add your code to the project
- Build > Build All
- The DLLÂ is placed in ProjectDirectory/bin/Debug/ProjectName.dll
Microsoft Visual Studio (as of 2013, version 12.0.31101.00 Update 4)
- File > New > Project
- Top drop-down list > .NET Framework 2.0
- Templates > Visual C# > Class Library
- Choose a project name and directory > OK
- Project > Add Reference > Browse > Browse Button
- Navigate to C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll
- Add > OK
- Add your code to the project
- Build > Build Solution
You now have a DLL placed in ProjectDirectory/bin/Debug/ProjectName.dll. Copy this file to your Unity project’s Assets directory or any folder in it and it will be usable by the rest of your project’s scripts.
One issue that will crop up at this point is that if any code in your DLL ever crashes, your stack trace won’t contain as much information as it would had you put the scripts directly into your Unity project. Specifically, file names and line numbers will be omitted making debugging much harder.
Luckily, there is a solution to this issue. If you build with MonoDevelop or Xamarin Studio, there will be a ProjectName.dll.mdb file in the same directory that the DLL gets placed in. Copy this file to your Unity project’s Assets directory along with the DLL and Unity will now have debugging information about your DLL’s contents, including file names and line numbers.
If you’re building your DLLs with Microsoft Visual Studio, there’s one extra step. Visual Studio builds a PDB file instead of an MDB and Unity doesn’t know how to use it directly. Instead, Unity provides a command-line utility to convert PDB files into MDB files. Run it like this:
c:\Program Files\Unity\Data\MonoBleedingEdge\lib\mono\4.5\pdb2mdb.exe MyLib.dll
Lastly, there are a couple of downsides to using DLLs in Unity. The first is that there is an issue that crops up when dispatching an event from code in a DLL. This is easily overcome, as I’ve described in this article.
The other issue is that when code in a DLL crashes, you can’t simply double-click on the crash in the Unity editor’s Console pane and jump straight to the line for a quick fix. Instead, you need to note the line that crashed, open the IDE you’re building the DLL in, find the line, fix the crash, rebuild the DLL, and re-import the DLL into Unity. This can be a tedious process, but you can partially automate it in each IDE via post-build steps.
Now you know how to create, use, and debug a .NET DLL in Unity. If you decide to use them, you’ll have a powerful tool to modularize your app into reusable libraries. If you’ve already adopted this strategy and are using DLLs in your app, let me know how it’s gone for you in the comments. Do you have any particular strategies that make using DLLs easier or more powerful?
#1 by Benjamin Guihaire on May 25th, 2015 ·
Other downsides
-For some reasons, the size of the executable generated by Unity when you have Dlls in your project is bigger than when the same code is directly as .cs code in Unity, no matter what “stripping” option is selected in the project settings of Unity.
-you might want to generate 2 dlls (debug and release).. which makes things more cumbersome to manage in your Unity project (you debug DLL version might have extra code such as ASSERT which you don’t want in your final production code).
-Make sure to not package the MDB files in your iOS production ipa.
– when converting your app to work in 64bits (il2cpp), if one of the DLL use some code that is not supported in 64bits, its then hard to find where the problem comes from (ex: which dlls use that MethodBase.GetCurrentMethod() ?)
Little upsides :
Unity use an old Mono compiler (2.8 ? ), if you compile a dll with a newer mono, you can get a more optimized generated IL code in your DLL than what you would get when compiling from Unity.
You can use for example [MethodImpl(MethodImplOptions.AggressiveInlining)] which I don’t think even exist with the old Mono. And if you use Visual studio compiler, you will usually get better generated IL code (I noticed it with C# unsafe code), and visual studio does a better job to collapse and use less temporary variables in your functions (Spend a time to look at the generated IL code, this is pretty fascinating !)
#2 by jackson on May 25th, 2015 ·
These are some excellent points! None of them seem especially set in stone though, so they may change as new versions of Unity are released. Which version or versions did you observe these issues in?
#3 by Benjamin Guihaire on May 27th, 2015 ·
4.6.5p1
#4 by Mars on May 25th, 2015 ·
we can use all in unity c# codes directly.
#5 by izyl on January 9th, 2017 ·
Hello, i am trying to ship the NatUpnp lib from .net com libraries.
I add the reference to the project.
i build and i get a InterOp.NatUpnpLib.dll
i add this dll in my asset folder.
At this stage it compiles in both editors : visual studio and unity
If i launch the game from the unity editor it works fine i can add a redirection on my internet box.
But when i build the game as soon as i try to discover my router the application crashes in kernel.dll
I am so new at c# i don’t even know what to do.
I Tried to catch all exceptions but the code doesnt even go in the catch
What can i do please ?
#6 by jackson on January 9th, 2017 ·
I’m not familiar with that library, but it may have some OS dependency in it that won’t work outside of the editor or Windows. This guide is just for C# code that would otherwise work if you directly put it into the Assets directory, not arbitrary DLLs since those can have all kinds of unsupported dependencies.
#7 by Lena on July 12th, 2017 ·
Hi Jackson,
I don’t understand when this is happening:
“If you’re building your DLLs with Microsoft Visual Studio, there’s one extra step. Visual Studio builds a PDB file instead of an MDB and Unity doesn’t know how to use it directly. Instead, Unity provides a command-line utility to convert PDB files into MDB files. Run it like this:
c:\Program Files\Unity\Data\MonoBleedingEdge\lib\mono\4.5\pdb2mdb.exe MyLib.dll”
How do I know if my file is a PDB or a MDB?
Can it be changed after the .dll is built?
I’ve received a ready file an need to integrate it in the project, should I sent it back to the editor…?
#8 by jackson on July 12th, 2017 ·
If you have a PDB file, it will have the
.pdb
extension. Similarly, an MDB file with have the.mdb
extension. Neither is required, but they help with debugging.#9 by George on October 7th, 2017 ·
Hello Jackson. I’m very interested in the integration of DLLs in Unity (or rather in general ).
I’ve tried using a dll for Npgsql, the library to handle PostgreSQL command texts via script. The commands coming from the DLL work perfectly fine in the Standalone Build, but they don’t work in editor. One throws a MissingMethodException, the other crashes the Editor completely. Do you have any idea why that is happening? It’s getting quite annoying to debug via build only.
Sidenote: The DLL came with an asset I downloaded. I simply put it into the Plugins folder and chosen all platforms for its import settings. I’m also using a Npgsql xml for the intellisense, although the error is obviously not there.
#10 by jackson on October 7th, 2017 ·
Hey George, remember that DLLs are really just a code organization tool. If you get a
MissingMethodException
from a.cs
file in yourAssets
directory then you’ll still get aMissingMethodException
if you move that code into a DLL. Putting the code in the DLL doesn’t unlock any new features.In this case it seems that your DLL is using some functionality that isn’t available in the Unity editor but is available in a standalone build. So you’ll need to find a way to avoid using that “missing method” while in the editor. Options include using an alternative method by rewriting the DLL or finding another DLL, wrapping calls to the DLL in a
#if !UNITY_EDITOR
block, and upgrading the “Scripting Runtime Version” or “Api Compatibility Level” in Player Settings.#11 by George on October 12th, 2017 ·
Hello again Jackson, sorry for the late reply!
Thanks a lot! Upgrading the Scripting Runtime Version to the experimental 4.6 did the trick! It seems though that now it doesn’t work on the build. This is quite interesting! Why would this happen? I’m guessing I can fix it somehow with the use of those
#if
ifs?The DLL information though says that the assembly targets .NET 3.5. Does that mean anything? Sorry for bothering you with these questions, I’m quite new to the whole Dynamic-link library thing.
#12 by jackson on October 12th, 2017 ·
Different environments (editor, macOS standalone, Windows standalone, iOS, Android, etc.) all have slightly different behavior. There’s a lot that will work in one environment but not another. It’s likely that the DLL is using some function that doesn’t exist in the environment you built for. One way to track it down is to look at the stack trace for the
MissingMethodException
. Sometimes that’ll give you a clue about which method is missing. If not, you can use the call stack to look into the source code for the DLL and figure out the problem from there. If you don’t have the source code, you can decompile the DLL with a program like ILSpy or dotPeek.In the end you need to figure out what the problem function is and not call it in the environments where it doesn’t work. Using
#if PROBLEM_ENVIRONMENT
is one way of changing the behavior of the code for specific environments. Just keep in mind that#if
is evaluated at compile time, not run time. So you’ll need to build the code twice. Since the code in question is in a DLL, you’ll need to build at least two versions of it and include the appropriate one for each environment. Here’s basically what your code will look like if you use#if
:Alternatively, you can attempt to find a way to never call the problem function in any environment. This has the advantage of not needing to make multiple builds of the DLL. The downside is that you have to find a one-size-fits-all solution that works on all platforms.
Best of luck!