I’ve googled this, and there’s a couple of hits related to using the PackageManager API to do this. However, when I use that, it shows info about the package regardless of whether it’s currently installed or not, and there doesn’t seem to be a property on the PackageInfo class to tell me whether it’s installed or not. Am I missing something here, or is this really not possible using the API?
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEditor.PackageManager;
public class Test : MonoBehaviour
{
private IEnumerator Start()
{
var pack = Client.List();
while (!pack.IsCompleted) yield return null;
var haveProgrids = pack.Result.FirstOrDefault(q => q.name == "com.unity.progrids");
Debug.Log(haveProgrids);
}
}
haveProgids is null if you don’t have the ProGrids package installed, PackageInfo if you have. You get the idea.
If you check for the package specifically, you’ll miss if the project has the github version of the package instead of the original package. I don’t know if that is important for the OP’s use case, but sometimes people have the source for a package in the Assets folder, and the actual package not installed, because the project requires a slight modification to the package.
Like I said, I tried that but the list is filled with packages that I don’t have installed, and there doesn’t seem to be a property in PackageInfo to say whether it’s installed, so that list result isn’t useful.
My solution was to read the Packages/manifest.json file and check if the “dependencies” dictionary has a key that matches the package ID I’m checking for. It’s fool-proof. I wish the PackageManager library had something built-in though.
I wouldn’t share the example if it weren’t working for me, so something is wrong with your editor or I don’t know. My example is working in 2020.3.5f1 properly.
That’s good to know that it’s working for you. If you don’t mind verifying something for me, it would help me feel better about it too… Install the FBX Exporter package, run your checker to verify it’s in the list. Then uninstall it and see if it’s still in the list. That’s the specific package I needed to know was not installed. I’m wondering if installing it makes it get stuck in the list even after removal.
using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEditor.PackageManager;
public class Test : MonoBehaviour
{
private IEnumerator Start()
{
var pckName = "com.unity.formats.fbx";
var pack = Client.List();
while (!pack.IsCompleted) yield return null;
var haveProgrids = pack.Result.FirstOrDefault(q => q.name == pckName);
Debug.Log(haveProgrids == null ? $"I DO NOT have '{pckName}'" : $"I DO have '{pckName}'");
}
}
I ran the ‘do not have’ case both before the first install of the package and after uninstall it and both times it indicated the ‘do not have’ status, so it seems working properly.
Great, maybe I’ll try again for a sanity check. Although, I have to admit that I like my technique of reading the manifest file because it doesn’t require asynchronous code.
By the way, for reference, here’s the function I created, which resides in my “CommonEditor.cs” file, which contains several re-usable functions for editor scripts. The JSON class is my own wrapper for JSON parsing, which provides a lot of flexible functionality, but any suitable JSON parser would work.
public static bool isPackageInstalled(string packageId)
{
// Since the PackageManager API doesn't seem to have a way to detect if a package is installed,
// we just check the manifest manually. It's JSON format, so it's easy to read.
string jsonText = File.ReadAllText("Packages/manifest.json");
JSON json = new JSON(jsonText);
// Since the package names are dictionary keys and have periods in them,
// we can't reference them using the JSON class's getValue().
// So, we need to get the raw Dictionary to look at.
var dependencies = json.getStringStringDict("dependencies");
return dependencies.ContainsKey(packageId);
}
I liked Gillissie’s approach, and simplified it further – just search the contents of manifest.json for a specific substring, no JSON parsing needed. I guess there might be edge cases where the manifest.json format might change, or if certain packages have weird names, but I think it’s safe for 99.9% of cases.
Sorry for bumping this but I think I can clear up the confusion.
I was trying to find out if shadergraph (“com.unity.shadergraph”) was installed and it too was not listed in the results. However, each package in the results has a “dependecies” property and therein I found the missing packages.
Maybe it’s related to them being listed in the manifest as “depth:1” instead of 0 (not sure.)
This is achievable using version defines in an assembly definition.
Step 1 (If you don’t already have an assembly definition):
In the project explorer, right click in the project folder that you want to make an assembly out of. In the context menu, select Create > Assembly Definition.
Step 2:
Select the Assembly Definition file and in the inspector add the package in question to the list of Assembly Definition references. Here’s an example for both TextMeshPro and InputSystem:
Step 3:
Still in the inspector, add the version define. Define property can be whatever you want. Expression should be the minimum version number of the package you are targeting. Example:
Now, in your code you can do this:
INPUTSYSTEM_1_3 will only be defined if the user has the input system package installed (version 1.3.0 and above).
This method seems to only work for unity packages. It would be nice if Unity would let you input a string or something for referencing a custom resource instead of the dropdown which only seems to include unity packages.
I used this method to obtain all the current unity packages installed in my project. After that just use, for example, a “for” or “foreach” to compare each package name id with the desired one (as in the examples above).
AG_Xene’s solution is good but will only work in editor as it’s from the UnityEditor namespace. If you want build logic to change based on whether or not a package is installed then you need the package code to define a compiler define so that the compiler can change your code at compile time.