Search Unity

How to run a setup method when a package is imported/updated?

Discussion in 'Package Manager' started by caioteixeira5, Apr 5, 2019.

  1. caioteixeira5

    caioteixeira5

    Joined:
    Apr 5, 2019
    Posts:
    3
    Hello :)
    We are trying to run a setup method when a package is imported, we found out that methods with InitializeOnLoadMethod are called when a package is imported for the first time but not when it is updated :/ Just to clarify our use case, we are using a private scoped registry, we want to create/update a custom gradle template on the Assets/Plugins folder every time a package is imported/updated.
    Is there a proper way to call a method when a package is imported and/or updated?
     
  2. manu73

    manu73

    Unity Technologies

    Joined:
    Aug 22, 2014
    Posts:
    68
    Hi @caioteixeira5!

    There are no existing callbacks to know when a package is installed/updated or removed :(

    But you can effectively used a InitializeOnLoadMethod fct to know which packages are installed.
    Btw, this fct will be called at each domain reload (install/update/remove of a package but also entering play-mode)

    Here's a code snippet (works with Unity 2019.1.0b9) you may starts with:

    Code (CSharp):
    1.  
    2. using System.Text;
    3. using System.Threading;
    4. using UnityEngine;
    5. using UnityEditor;
    6. using UnityEditor.PackageManager;
    7.  
    8. public static class InstalledPackages
    9. {
    10.     [InitializeOnLoadMethod]
    11.     private static void InitializeOnLoad()
    12.     {
    13.         var listRequest = Client.List(true);
    14.         while (!listRequest.IsCompleted)
    15.             Thread.Sleep(100);
    16.  
    17.         if (listRequest.Error != null)
    18.         {
    19.             Debug.Log("Error: " + listRequest.Error.message);
    20.             return;
    21.         }
    22.  
    23.         var packages = listRequest.Result;
    24.         var text = new StringBuilder("Packages:\n");
    25.         foreach (var package in packages)
    26.         {
    27.             if (package.source == PackageSource.Registry)
    28.                 text.AppendLine($"{package.name}: {package.version} [{package.resolvedPath}]");
    29.         }
    30.        
    31.         Debug.Log(text.ToString());
    32.     }
    33. }
    34.  
    Regards,

    Manu73
     
    N04H08 likes this.
  3. caioteixeira5

    caioteixeira5

    Joined:
    Apr 5, 2019
    Posts:
    3
    Thank you for the quick answer! :)

    I tested it in both Unity 2018.3 and 2019.1, but it seems to have the same behavior that I had before. This method is not called when a package is updated.
    I actually have a piece of new information, this issue only happens when using a private registry. When I update an official package the method is called.
     
  4. manu73

    manu73

    Unity Technologies

    Joined:
    Aug 22, 2014
    Posts:
    68
    Hi @caioteixeira5!

    Sorry for this inconvenience.

    I locally use Verdaccio and scoped registry in Packman and I was able to update my package published in my local registry.

    The only difference I think, it's that my package contains scripts that I have updated.

    Domain reload (which will call InitializeOnLoadMethod) will only occur if there are changes in scripts.

    Does your package only contains assets (aka non scripts)?
    Also, in Unity General preferences, do you have Auto-Refresh checked?

    Manu73
     
  5. manu73

    manu73

    Unity Technologies

    Joined:
    Aug 22, 2014
    Posts:
    68
    Hi @caioteixeira5!

    I've updated the code snippet to take care of assets only change:

    Code (CSharp):
    1.  
    2. using System.Linq;
    3. using System.Text;
    4. using System.Threading;
    5. using UnityEngine;
    6. using UnityEditor;
    7. using UnityEditor.PackageManager;
    8.  
    9. public class InstalledPackages : AssetPostprocessor
    10. {
    11.     private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    12.     {
    13.         var inPackages = importedAssets.Any(path => path.StartsWith("Packages/")) ||
    14.             deletedAssets.Any(path => path.StartsWith("Packages/")) ||
    15.             movedAssets.Any(path => path.StartsWith("Packages/")) ||
    16.             movedFromAssetPaths.Any(path => path.StartsWith("Packages/"));
    17.  
    18.         if (inPackages)
    19.         {
    20.             InitializeOnLoad();
    21.         }
    22.     }
    23.    
    24.     [InitializeOnLoadMethod]
    25.     private static void InitializeOnLoad()
    26.     {
    27.         var listRequest = Client.List(true);
    28.         while (!listRequest.IsCompleted)
    29.             Thread.Sleep(100);
    30.  
    31.         if (listRequest.Error != null)
    32.         {
    33.             Debug.Log("Error: " + listRequest.Error.message);
    34.             return;
    35.         }
    36.  
    37.         var packages = listRequest.Result;
    38.         var text = new StringBuilder("Packages:\n");
    39.         foreach (var package in packages)
    40.         {
    41.             if (package.source == PackageSource.Registry)
    42.                 text.AppendLine($"{package.name}: {package.version} [{package.resolvedPath}]");
    43.         }
    44.        
    45.         Debug.Log(text.ToString());
    46.     }
    47. }
    You can adapt this code to only look in specific Packages.
     
    GarthSmith likes this.
  6. caioteixeira5

    caioteixeira5

    Joined:
    Apr 5, 2019
    Posts:
    3
    Thank you!
    It is working now :)
    I am also using Verdaccio, my package has both assets and scripts. I am not sure why exactly this was not working, but modifying a hardcoded string on a script was not triggering a recompile for some reason.
     
  7. manu73

    manu73

    Unity Technologies

    Joined:
    Aug 22, 2014
    Posts:
    68
    You're welcome.
     
  8. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
  9. FuriousAvocado

    FuriousAvocado

    Joined:
    Jun 19, 2015
    Posts:
    3
    Hey @QFSW did you make any progress on this topic? I am looking to do the same but if there are compiler errors Unity grinds to a halt, even if there are scripts which can execute.

    Thanks!
     
  10. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,906
    Unfortunately not
     
  11. AdamBebko

    AdamBebko

    Joined:
    Apr 8, 2016
    Posts:
    168
    I would also love functionality like a callback as well when a custom package is installed/updated. Just adding my tiny voice to this thread.

    @manu73 thanks for the code I'll try that out.


    Update: The code doesn't seem to detect custom packages, only unity packages

    Update2: figured it out. Deleting the if check for the package source found all package registries. By the way, the name is the full com.x.package name if you’re checking for a particular package. Thanks for the code!
     
    Last edited: May 22, 2021
  12. flintmech

    flintmech

    Joined:
    Sep 29, 2011
    Posts:
    32
    Is it not possible to use PackageRegistrationEventArgs to detect when a Package is installed/updated/removed? I see this thread started in 2019 - could this API be relatively new? I haven't tried it yet - I'm currently still investigating what I will need to do and found this thread from google.
     
  13. peon_1

    peon_1

    Joined:
    Aug 16, 2014
    Posts:
    5
    @flintmech: PackageRegistryEventArgs is supported since 2020.3 (available since 2020.2). It is used by
    PackageManager.Events.registeredPackages which is supported since 2020.3 (available since 2020.2) and PackageManager.Events.registeringPackages with the same availability, the former (following my own observations, no guarantee) apparently invoked when a package is being installed (i.e. after installation has finished), the latter when uninstalling a package (obviously before uninstalling).

    So yes, it is (relatively) new (at least younger than the thread), but this is the way to go for recent editors.
     
    AdamBebko and TheSleepyKoala like this.
  14. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    613
    Hi, I need a callback for when a Sample is downloaded. Any chance there's an event for that as well? I haven't been able to find it.

    Of course, I could use the InitializeOnLoad trick but that seems hacky.