'How to make a Unity plugin support old versions of Unity?

I'm developing a plugin for Unity. Say, on my machine I have the most recent version of Unity installed (right now it's 2019.1.8). However, I also want the plugin to support older versions of Unity, preferably even very old versions (like 4.x or 5.x). How should this be achieved?

I'd imagine that I would need to have separate versions of Unity installed on my machine. E.g. with Unity Hub or by manually re-naming the installation folders of Unity each time I want to keep a version before installing a new one (like it's described here: https://support.unity3d.com/hc/en-us/articles/210001066-Can-I-activate-more-than-one-version-of-Unity-on-the-same-machine-).

When releasing the plugin on Unity Asset Store, I'd also have to upload multiple *.unitypackage files, and Unity Asset Store will deliver the proper file to each buyer, depending on the version of the installed Unity Editor on the buyer's machine.

Since Unity versions may have significant differences, I'd essentially have to develop several projects in parallel. And (especially later in development) a single change in code would have to be manually copied into all other versions of the project. That makes sense because in some cases it won't be simply copy-and-paste but instead adjusting the code to work around stuff that didn't exit in older versions, was renamed, became deprecated etc.

This looks like incredible overhead to me. Do developers of Unity plugin actually do all this or is there some easier way? If I simply build with the latest version of Unity and upload only one *.unitypackage file, then only some of the most recent versions of Unity (usually about 1 year old at the maximum) would be able to properly import and use it, right?



Solution 1:[1]

In general in your code you can use c# pre-processors in order to make code compile or commented out conditionally on some global defines.

Unity offers Version and Platform specific pre-processors

From Unity 2.6.0 onwards, you can compile code selectively. The options available depend on the version of the Editor that you are working on. Given a version number X.Y.Z (for example, 2.6.0), Unity exposes three global #define directives in the following formats: UNITY_X, UNITY_X_Y and UNITY_X_Y_Z.

and

Starting from Unity 5.3.4, you can compile code selectively based on the earliest version of Unity required to compile or execute a given portion of code. Given the same version format as above (X.Y.Z), Unity exposes one global #define in the format UNITY_X_Y_OR_NEWER, that can be used for this purpose.

So you can exactly control which code version shall be used for which specific target platform, Unity version, .Net version etc


You can wrap your code e.g. in

#if UNITY_2017_1_OR_NEWER
    /* Code that only compiles under newer version */
#elif UNITY_5
    /* Code that compiles for Unity 5.x.y */
#elif UNITY_4
    /* Code that compiles for Unity 4.x.y */
#else
    /* apparently some older stuff */
#endif

Then you can pack it all in one single *.unitypackage and the user won't even notice. Since commented out stuff is stripped of in a built application it doesn't increase the build size.

The structure for development, however, is another question. I think in order to be sure that the support works you won't come arround having one project for each Unity version and copy paste the code for older versions into the pre-processor wrapped sections of the newest one.

In order to keep it as simple for me as possible I would probably use a folder structure like

YourPlugIn
|-- General
|-- Unity4
|-- Unity5
|-- Unity2017

and use the partial keyword in order to implement complete behaviours instead enabling and disabling single code blocks e.g.

General/MyBehaviour.cs

public partial class MyBehaviour : MonoBehaviour
{
    // this is the script users should be dragging onto objects
}

Unity4/MyBehaviour_4.cs

#if UNITY_4
// Extends the general MyBehaviour for Unity 4.x.y
public partial class MyBehaviour
{
    public string InitialValue;

    private void Start()
    {
        Debug.Log(InitialValue);
    }
}
#endif

Unity5/MyBehaviour_5.cs

#if UNITY_5
// Extends the general MyBehaviour for Unity 5.x.y
public partial class MyBehaviour
{
    public int InitialValue;

    private void Start()
    {
        Debug.Log(InitialValue.ToString());
    }
}
#endif

Unity2017/MyBehaviour_2017.cs

#if UNITY_2017
// Extends the general MyBehaviour for Unity 2017.x.y
public partial class MyBehaviour
{
    public Vector3 InitialValue;

    private void Start()
    {
        Debug.Log(InitialValue.ToString());
    }
}
#endif

But then you can not use any of the e.g. UNITY_X_Y_OR_NEWER defines because you would get duplicates ;)

Ofcourse there is a lot of more issue zones like e.g. renaming your classes afterwards or in newer version wrapping them in interfaces etc .. but I hope I made my idea clear.


I would also take the risk to claim that it should be enough to only support the "latest" versions of Unity and not make a Plug-In backwards compatiable down to Unity 2.6 ... who will still use that old stuff anyway?

Currently in the HUB the latest release that is offered for installation is 2017.1.5f1 so I'ld claim it is enough to have backwards support until that one and not any further.


To the question about version control: Github offers a pretty complete .gitignore for Unity. There you can see that there is a lot more than the Temp folder you should ignore .. especially the Library.

In this post I also descriped a fast and secure way to remove all the generated files with one single git command. Personally I like to exclude all Library/*.asset files from the ignoring (so they are version controlled) as here some things like e.g. custom Layouts, the current build target etc are stored.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 bobbyg603