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:
    40
    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
     
  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:
    40
    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:
    40
    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:
    40
    You're welcome.