Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is advised for Unity package using Nuget dependencies? #669

Open
camille-avatarmedical opened this issue Sep 25, 2024 · 7 comments
Open

Comments

@camille-avatarmedical
Copy link

Hi,

In my company we use NugetForUnity which works great for Unity projects. We also try to split our code into reusable parts for which we use Unity packages. I wonder what the current way to create a Unity package that use a NuGet dependency seamlessly?

If that not possible do you have any experience to share to deal with this situation?

@igor84
Copy link
Collaborator

igor84 commented Sep 26, 2024

I don't know of any way. In my company we also split our reusable code but into nuget packages so we are using NugetForUnity both for our internal and external packages and have no problem expressing dependencies between them.

That said maybe you can write Editor class in your Unity package that is InitializeOnLoad and that writes your nuget dependencies into packages.config file if they are not already there and then call AssetDatabase.Refresh to trigger the nuget restore process.

@camille-avatarmedical
Copy link
Author

Thanks for the very interesting feedback @igor84. Would you mind sharing details about how you split your code into nuget packages? Notably:

  • How do you manage Unity's dependencies for a Nuget package? For example, let's say you want to make some utilities around a Unity package (UI Toolkit for example). How you would do it?
  • I guess the nuget packages you create should be code only? Do you have tried and succeeded to embed Unity resources (textures, prefab, etc...) into your packages?

@igor84
Copy link
Collaborator

igor84 commented Sep 26, 2024

  • We only had a couple of nuget packages that work around some unity packages and we just installed those Unity packages manually. We would just document in package Readme that some Unity package needs to be installed.
  • We did make one nuget package with code and assets but we are not happy with it because it is 500MB while all other packages are less than 1MB. Also whenever you make any small code change a new version of the package with all the same assets needs to be uploaded on our nuget repository and all those versions quickly filled up our hard drive on repository machine. So my advice would be to at least separate code and assets in separate packages and make sure to only build new version of nuget with assets when you really need it an not whenever someone commits some change.

@marked-one
Copy link

When I stumbled upon this problem, my initial guess was exactly what @igor84 proposes in his first comment. But the code in the package itself can't execute in case of errors. And this is exactly the case when no dependencies are present. It is possible to put code under Version Defines for your own packages, but they can only be added for Unity Editor, Unity modules and UPM packages. So this doesn't cover the case with NuGet packages, or Asset Store assets. Probably a DLL in a package can execute in case of compilation errors, but I didn't go that far.

My second idea was to put a file, e.g. a json, with a list of dependencies in the package. And then implement a tool that parses this file and installs the required dependencies. What I didn't like about this approach is that I first install a package and then I need to resolve dependencies via manually pressing e.g. "Resolve" button. I didn't find a way to automate this, as there's no callback after a package is installed. And when installed package has errors no assembly reload happens either. Plus, I didn't test whether such a tool will work when installed after the package that fails to compile, though I remember I had some similar issues in the past.

My solution was to fully manage dependencies outside of packages. I created an "installer tool", essentially a Scriptable Object with 3 lists (NuGet & UPM packages, and Asset Store assets) and an Install button. Internally there's a bit more complex code than just a Scriptable Object, but this is how "user interface" looks like. It is then possible to create multiple Scriptable Object assets containing different sets of packages and use them as installers. So here I don't deal with the dependencies after I install packages, I instead install the package with all the dependencies. The only drawback I found is that these assets should be shared somehow. In my case I simply put them in the same package with my "installer tool" as I am the only user of it so far.

And yes, in my case I first install NuGet packages, then UPM packages, then Asset Store assets, as dependencies usually go the other way round.

@marked-one
Copy link

Just in case, I put my tool on GitHub: https://github.com/marked-one/UnityBulkPackageInstaller

@sindrijo
Copy link

My second idea was to put a file, e.g. a json, with a list of dependencies in the package. And then implement a tool that parses this file and installs the required dependencies. What I didn't like about this approach is that I first install a package and then I need to resolve dependencies via manually pressing e.g. "Resolve" button. I didn't find a way to automate this, as there's no callback after a package is installed. And when installed package has errors no assembly reload happens either. Plus, I didn't test whether such a tool will work when installed after the package that fails to compile, though I remember I had some similar issues in the past.
And yes, in my case I first install NuGet packages, then UPM packages, then Asset Store assets, as dependencies usually go the other way round.

Did you try using PackageManager.UI.IPackageManagerExtension?

It has the following members:

  • OnPackageAddedOrUpdated | Called by the Package Manager UI when a package is added or updated.
  • OnPackageRemoved | Called by the Package Manager UI when a package is removed.
  • OnPackageSelectionChange | Called by the Package Manager UI when the package selection changed.

You would probably need to have this plugin already installed, as I'm not sure how reliable those callbacks are if the plugin lives in the package being installed itself.

@marked-one
Copy link

@sindrijo yep, I considered this API.

But it has a serious limitation: it is tied to the Package Manager UI.

This means, it only solves the problem for when you install packages manually.

But whenever a package is installed from code via Client API or via manually changing manifest.json, these callbacks won't trigger unless Package Manager window is open and active.

So, not a universal solution. Though maybe it could be enough to solve the OPs problem.

And yes, your guess is right, the OnPackageAddedOrUpdated callback runs before domain reload, so it can't be triggered when the code is in the installed package itself, as it is not yet compiled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants