Sometimes we write code that’s meant to be run outside of the Unity engine. This could be anything from unit tests being run in MonoDevelop or Visual Studio to shared code that’s used on a multiplayer server. Regardless, the Unity engine isn’t available for use unless you’re running in the editor or a deployed build. This means you’ll have problems whenever you access the Unity engine via Debug.Log, GameObject, or MonoBehaviour. Today’s article shares some quick tips that enable you to tweak your code so that you can detect whether the Unity engine is available for use. Read on to learn how!

Unity has a nice page documenting various preprocessor symbols that they’ve defined in various situations. For example, you might write some code like this:

class InputHandler
{
	void Update()
	{
		#if UNITY_IOS || UNITY_ANDROID
			// ... do touchscreen handling
		#else
			// ... do keyboard and mouse handling
		#endif
	}
}

These are really handy symbols as they allow us to detect what code should be compiled at compile time. There’s zero runtime overhead to #if since the compiler evaluates it and strips out the irrelevant code. So when you compile the above script on iOS or Android it only compiles this:

class InputHandler
{
	void Update()
	{
		// ... do touchscreen handling
	}
}

The other code is simply removed, so it doesn’t add anything to your app size and doesn’t cost any runtime performance.

Ideally, we’d have something similar to detect if the Unity engine is available at all. For example, say we want to use Unity’s built-in JSON serializer JsonUtility. Since it relies on the Unity engine, we can’t use it when we’re running code from outside the Unity editor or deployed builds. That means we’ll get errors like these:

System.MissingMethodException : Attempted to access a missing method
 
System.Security.SecurityException was unhandled
  Message=ECall methods must be packaged into a system module.

There are plenty of other JSON libraries available that we can fall back to in these circumstances. So we naturally want to write some code like this:

public static class JsonLibrary
{
	public static string ToJson(object obj)
	{
		#if UNITY_ENGINE_AVAILABLE
			return UnityEngine.JsonUtility.ToJson(obj);
		#else
			return LitJson.JsonMapper.ToJson(obj);
		#endif
	}
 
	public static T FromJson<T>(string json)
	{
		#if UNITY_ENGINE_AVAILABLE
			return UnityEngine.JsonUtility.FromJson<T>(json);
		#else
			return LitJson.JsonMapper.FromJson<T>(json);
		#endif
	}
}

This JsonLibrary class simply abstracts JsonUtility when the Unity engine is available and LitJSON’s JsonMapper when the Unity engine isn’t available.

Unfortunately, UNITY_ENGINE_AVAILABLE isn’t defined by Unity. When you open the C# solution in an IDE like MonoDevelop or Visual Studio, Unity defines all of the symbols such as UNITY_EDITOR and UNITY_ANDROID in the compiler settings for the solution. So you can’t simply use UNITY_EDITOR or any other such symbol as a proxy for the Unity engine being available since it’s always there.

One alternative would be to modify the C# solution that Unity creates for us. We could define a UNITY_ENGINE_NOT_AVAILABLE symbol and reverse our #if code, but we’d have to re-define the symbol every time Unity overwrote the solution. It’s an annoying manual step and we can do better.

We could also define the symbol in the “Scripting Define Symbols” section of “Player Settings”. This also isn’t quite what we want because all symbols defined here are added to the generated C# solution. We still wouldn’t have a way to know whether the Unity engine is available for use.

This leads to the real trick of today’s article. There are two files you can add to your Unity project’s Assets directory: smcs.rsp and gmcs.rsp. These are text files where you can define extra parameters to pass to the C# compiler. That happens every time Unity compiles your project. Crucially, these parameters are not added to the C# solution that Unity generates.

So we now have two kinds of compilation. The first is Unity’s automatic compilation that uses smcs.rsp and gmcs.rsp. This is where the Unity engine is available. The second type of compilation is from an IDE that’s building the C# solution that Unity generates. This is where the Unity engine isn’t available.

The only step left is to define the UNITY_ENGINE_AVAILABLE symbol in smcs.rsp and gmcs.rsp. Again, they’re just text files so create or modify them to include this one line:

-define:UNITY_ENGINE_AVAILABLE

With that in place the above code would work just fine. We’d have a JsonLibrary that uses the Unity engine when available and falls back to alternatives when it’s not. You can use the same for logging since the Debug class won’t work outside of Unity and many other types of code. Hopefully you’ll find this useful in your projects!