unity-package-management について
unity-package-managementは、Unity Package Managerのパッケージを追加、削除、更新、検索するスキルです。プロジェクトのPipelineパッケージのコマンドを優先し、Editorを使えない場合のヘッドレスC#方式も説明します。
主な機能
- 01UPMパッケージの追加、削除、更新
- 02パッケージ検索とバージョン確認
- 03Pipelineパッケージのコマンドを優先
- 04必要に応じたヘッドレスC#方式
- 05インストール後のパッケージ検証
活用シーン
- 01既存のUnityプロジェクトの依存関係管理
- 02CIでの非対話型パッケージ設定
- 03パッケージIDと利用可能なバージョンの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ unity-technologies/ unity-agent-plugin --skill unity-package-managementインストール後、Claude Code で/unity-package-managementを入力して読み込まれたか確認します。
同梱ファイルreferences/select-packages.md
詳細
Unity パッケージ管理(まず Pipeline コマンドを使用し、C# スクリプトはフォールバックとして使用)
プロジェクトの Pipeline パッケージの package コマンドを unity command で実行して、UPM(Unity Package Manager)パッケージの追加、削除、アップグレード、検索を行います。これらのコマンドに対応できる Editor がない場合に限り、スクリプトから UnityEditor.PackageManager.Client をヘッドレスで操作する方法に切り替えます(フォールバックを参照)。Packages/manifest.json を直接編集しないでください。Package Manager は依存関係と互換性のあるバージョンを正しく解決しますが、手動編集では解決が頻繁に壊れます。
この内容は、Editor のインストール、プロジェクトの作成、ビルド/テストを扱う unity-cli スキルを補完するものです。このスキルでは unity command、unity status、unity pipeline install について説明しています。
まず package コマンドを使用する
Pipeline パッケージは add、remove、list、resolve、search、status の package コマンドグループを登録します。これらを使うには、プロジェクトに com.unity.pipeline が追加された、Editor の起動中のプロジェクトが必要です(unity pipeline install で追加し、次に unity open を実行してから、unity status --until-ready で準備完了を待ちます)。各コマンドのパラメーターは Editor から取得するため、最初に呼び出す前に確認してください。パラメーター名を推測しないでください。
unity status --until-ready --project-path "<project-path>"
unity command package --project-path "<project-path>" # the package commands this Editor has
unity command --query package --format json --project-path "<project-path>" # each command's parameter schema
unity command package search --project-path "<project-path>" # then pass the parameters the schema lists
unity command package add --project-path "<project-path>" # add one or more packages by id
unity command package list --project-path "<project-path>" # confirm what is installed
コマンド名の後に、そのスキーマで定義された名前のパラメーターを渡します(unity command <group> <command> --<parameter> <value>)。スキーマが複数の ID を受け付ける場合は、必要なパッケージをすべて 1 回の package add 呼び出しで追加します。最小バージョンが必要な場合は、スキーマの説明に従ってバージョンを固定してください(@<version> ID 形式は、以下の C# フォールバックで使用します)。package status または package list で確認し、パッケージを削除するには package remove を使用します。ゼロ以外の終了コードは失敗として扱い、メッセージを確認してください。
unity command package がそのようなグループはないと報告した場合、プロジェクトの Pipeline パッケージは古いバージョンです。unity pipeline upgrade を実行するか、以下のフォールバックを使用してください。フォールバックは独自に Editor を起動するため、Editor でプロジェクトを開いている間は実行できません。まずユーザーに保存して閉じてもらってください(フォールバックの最初のルールを参照)。
使用する場面
- 既存または新規作成したプロジェクトで、1 つ以上のパッケージを追加/削除/アップグレードするとき。
- CI でプロジェクトのパッケージを非対話的に設定するとき(Editor が実行されていない場合はフォールバックのスクリプトを使用)。
- パッケージ ID の存在を確認したり、依存する前に利用可能なバージョンを調べたりするとき。
- ゲームで実際に必要なパッケージを選ぶとき。references/select-packages.mdを参照してください。
インストールするパッケージの選択
すべてではなく、プロジェクトで実際に必要なものをインストールしてください。選択したテンプレートにすでに含まれているパッケージを優先してください(URP テンプレートにはレンダーパイプライン、Input System などが含まれています)。ジャンル/見た目/プラットフォーム/収益化とパッケージの対応付け、およびレジストリの検索方法については、references/select-packages.mdを参照してください。インストールする前に、重複を除いたパッケージ ID のリストを作成し、ユーザーに読み上げて確認してください。
フォールバック:問い合わせる Editor がない場合(C# クライアント API)
package add を実行できない場合にのみ、このセクションを使用してください。Editor が開いておらず開くつもりもない場合、プロジェクトに Pipeline パッケージがない場合、またはコマンドグループが存在せずアップグレードも望まない場合が該当します。バッチモードで Editor が実行するスクリプトから Client.AddAndRemove を使ってインストールします。
最初にプロジェクトを閉じる必要があります。 スクリプトは 2 つ目のバッチモード Editor で実行されます。すでにプロジェクトを開いている Editor がロックを保持していると、スクリプトが始まる前にバッチ実行が失敗します。unity editors running --format json は、Pipeline パッケージの有無にかかわらず、開いているすべての Editor を一覧表示します(unity status が一覧表示するのは Pipeline プロジェクトのみなので、そちらの結果が空でもプロジェクトが閉じているとは限りません)。各 data.instances[].projectPath を対象プロジェクトと照合してください。また、<project-path>/Temp/UnityLockfile が存在するか確認し、プロジェクトが Editor で開かれているかユーザーに尋ねてください。Editor でプロジェクトが開かれている場合、または判断できない場合は、作業内容を保存して閉じるようユーザーに依頼し、閉じたという返答を待ってください。バッチ実行がロックによって引き続き失敗する場合は、プロジェクトが開いているものとして扱い、ユーザーに閉じるよう依頼してください。再試行したり、ロックファイルを削除したりしないでください。ユーザーの Editor を自分で閉じたり強制終了したりしてはいけません。未保存のシーンや Play Mode セッションがある可能性があります。ユーザーが Editor を開いたままにしたい場合は、フォールバックを実行しないでください。プロジェクトを閉じるか、Pipeline パッケージをアップグレードする(unity pipeline upgrade を実行してから package add を実行する)までインストールできないことを伝えてください。
-quit の問題 — インストールに unity run を使ってはいけない理由
Client.Add/Client.AddAndRemove は非同期です。後続の EditorApplication.update ティックでのみ完了する Request を返します(UPM の子プロセスは Editor のメインループのポンプを介して結果を返すため、while (!req.IsCompleted) でブロックしてビジーウェイトするとデッドロックします)。-executeMethod の戻り後も、リクエストが完了するまで Editor を起動したままにする必要があります。
インストーラーには unity run を使用できません。デフォルトでは -quit が挿入されるためです(予約済みフラグについては unity-cli スキルを参照してください)。-quit を指定すると、メソッドが戻った時点で Editor が終了し、UPM の解決前に処理が終わります。そのため、パッケージはインストールされず、コールバックも実行されません。
解決策: -quit を付けず、-batchmode を指定して Editor の実行ファイルを直接起動します。Editor は起動したままになり、EditorApplication.update が動き続けてポーリングコールバックが実行されます。完了時にはコールバックが EditorApplication.Exit(code) を呼び出します。これにより Editor が終了し、プロセスの終了コードも設定されます。
インストーラースクリプト
これを Assets/Editor/ProjectBootstrap/PackageInstaller.cs に書き込みます。UnityEditor を使用するため、Editor/ フォルダー内(または Editor 専用アセンブリ内)に置く必要があります。
using System.Linq;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
namespace ProjectBootstrap
{
// Installs (and optionally removes) a fixed set of packages via the PackageManager
// Client API, headless-safe.
public static class PackageInstaller
{
// EDIT this list to match the package selection (see references/select-packages.md).
static readonly string[] PackagesToAdd =
{
"com.unity.inputsystem",
"com.unity.cinemachine",
"com.unity.render-pipelines.universal",
// "[email protected]" // pin a version with @ when a minimum is required
};
// Optionally drop packages in the same resolution pass (e.g. a template default you don't want).
static readonly string[] PackagesToRemove = { };
const double TimeoutSeconds = 600; // UPM resolution + downloads can be slow
static AddAndRemoveRequest _request;
static double _deadline;
// Invoke with: -executeMethod ProjectBootstrap.PackageInstaller.Install (NO -quit)
public static void Install()
{
if (PackagesToAdd.Length == 0 && PackagesToRemove.Length == 0)
{
Debug.Log("[PackageInstaller] Nothing to do.");
EditorApplication.Exit(0);
return;
}
Debug.Log($"[PackageInstaller] Adding: {string.Join(", ", PackagesToAdd)}");
_request = Client.AddAndRemove(packagesToAdd: PackagesToAdd, packagesToRemove: PackagesToRemove);
_deadline = EditorApplication.timeSinceStartup + TimeoutSeconds;
EditorApplication.update += Poll;
}
static void Poll()
{
if (_request == null) return;
if (!_request.IsCompleted)
{
if (EditorApplication.timeSinceStartup > _deadline)
{
EditorApplication.update -= Poll;
Debug.LogError("[PackageInstaller] Timed out waiting for UPM.");
EditorApplication.Exit(2);
}
return;
}
EditorApplication.update -= Poll;
if (_request.Status == StatusCode.Success)
{
var names = _request.Result.Select(p => $"{p.name}@{p.version}");
Debug.Log($"[PackageInstaller] Resolved: {string.Join(", ", names)}");
EditorApplication.Exit(0);
}
else
{
Debug.LogError($"[PackageInstaller] Failed: {_request.Error?.message}");
EditorApplication.Exit(1);
}
}
}
}
AddAndRemove はセット全体を 1 回の UPM 解決処理でインストールします。パッケージごとに Client.Add を実行するより速く、エラーも少なくなります。
1 つのスクリプトで追加/削除/アップグレードする場合:
- 追加:ID を
PackagesToAddに記載します。 - 削除:ID を
PackagesToRemoveに記載します。 - アップグレード/バージョン固定:
@<version>を付けて ID を追加します(例:[email protected])。バージョンを指定しない場合、解決時に互換性のある最新リリースが選択されます。
パッケージの検出/検証
追加前に ID の存在を確認したり、バージョンを一覧表示したりするには、レジストリを検索します。Editor 内の Client.SearchAll()/Client.Search("<id>") 呼び出しも非同期のため、インストーラーと同じポーリングと Exit のパターン、および同じヘッドレス実行を使用します。Assets/Editor/ProjectBootstrap/PackageSearch.cs を作成します。
using System.Linq;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
namespace ProjectBootstrap
{
public static class PackageSearch
{
const double TimeoutSeconds = 120;
static SearchRequest _request;
static double _deadline;
// Invoke with: -executeMethod ProjectBootstrap.PackageSearch.SearchAll (NO -quit)
public static void SearchAll()
{
_request = Client.SearchAll(); // or Client.Search("com.unity.cinemachine")
_deadline = EditorApplication.timeSinceStartup + TimeoutSeconds;
EditorApplication.update += Poll;
}
static void Poll()
{
if (_request == null) return;
if (!_request.IsCompleted)
{
if (EditorApplication.timeSinceStartup > _deadline)
{
EditorApplication.update -= Poll;
Debug.LogError("[PackageSearch] Timed out.");
EditorApplication.Exit(2);
}
return;
}
EditorApplication.update -= Poll;
if (_request.Status == StatusCode.Success)
{
foreach (var p in _request.Result.OrderBy(p => p.name))
Debug.Log($"[PackageSearch] {p.name}@{p.versions.latestCompatible} {p.displayName}");
Debug.Log($"[PackageSearch] {_request.Result.Length} packages found.");
EditorApplication.Exit(0);
}
else
{
Debug.LogError($"[PackageSearch] Failed: {_request.Error?.message}");
EditorApplication.Exit(1);
}
}
}
}
_request.Result は PackageInfo[] で、各エントリには name、displayName、description、versions(.latest、.latestCompatible、.all)が含まれます。Editor を使わずにターミナルだけで確認する場合(自由入力検索ではなく、既知の ID が対象)は、レジストリに直接問い合わせてください。references/select-packages.md を参照してください。
ヘッドレスで実行する(-quit を使わずに Editor を直接呼び出す)
バージョンから Editor のバイナリを特定し、バッチモードで実行します。プロジェクトを開いている Editor がない場合にのみ実行してください(フォールバックの最初のルールを参照)。スクリプトが EditorApplication.Exit で終了するため、-quit は渡さないでください。
VERSION="<version>" # e.g. 6000.0.47f1 (or an installed version)
PROJECT="<project-path>"
METHOD="ProjectBootstrap.PackageInstaller.Install" # or ...PackageSearch.SearchAll
# Install directory of that editor (Hub layout), via the unity CLI
ED=$(unity editors path "$VERSION" --format json | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['path'])")
# Resolve the executable per-OS (handles both "dir containing Unity.app" and the ".app" itself)
case "$(uname)" in
Darwin) if [ -d "$ED/Unity.app" ]; then UNITY_BIN="$ED/Unity.app/Contents/MacOS/Unity";
elif [[ "$ED" == *.app ]]; then UNITY_BIN="$ED/Contents/MacOS/Unity";
else UNITY_BIN="$ED/Unity"; fi ;;
Linux) UNITY_BIN="$ED/Editor/Unity" ;;
*) UNITY_BIN="$ED/Editor/Unity.exe" ;; # Windows (Git Bash / MSYS); use Editor\Unity.exe in PowerShell
esac
"$UNITY_BIN" -batchmode -projectPath "$PROJECT" -executeMethod "$METHOD" -logFile -
echo "Exit code: $?" # 0 = success, 1 = UPM error, 2 = timeout
-logFile - を指定すると、Editor のログ([PackageInstaller]/[PackageSearch] の行を含む)が標準出力にストリーミングされるため、解決の進行状況を監視したり、UPM のエラーを確認したりできます。お使いのビルドで unity editors path の出力形式が異なる場合は、代わりに unity editors --installed --format json からディレクトリを取得してください。
確認
# Every requested id should appear as a dependency
cat "<project-path>/Packages/manifest.json"
実行が 0 で終了したこと、およびリスト内の各パッケージが manifest.json に存在することを確認します。パッケージの解決に失敗した場合は、_request.Error.message にログが記録されるため、その内容を読み、ID/バージョンがレジストリと一致しているか確認してください。Editor 自身のログ([PackageInstaller] の行を含む)は、上記の -logFile - でストリーミングした標準出力にあります。unity logs ではなく、そちらを確認してください(unity logs に表示されるのは CLI 自身のログであり、Editor のログではありません)。
ヘッドレスでインポートして保存する(.meta ファイルを生成する)
スクリプトまたはツールで新しい .cs/アセットファイルを書き込んだ後、Unity はそれらをインポートして、各アセットに必要な .meta ファイルを生成する必要があります。また、すべての .cs/アセットは対応する .meta と一緒にコミットする必要があります。プロジェクトを一度開くだけでも(unity open "<project-path>")、インポートと生成が行われます。この処理をヘッドレスで行う必要がある場合(スクリプトまたは CI 内)は、この方法を使ってください。
パッケージインストーラーと異なり、これは同期処理です。戻る前に完了するため、unity run 経由で安全に実行できます(挿入される -quit は問題ありません。このメソッドも正常な終了コードのために EditorApplication.Exit を呼び出します)。次のファイルを書き込みます。
Assets/Editor/ProjectBootstrap/ProjectSaver.cs:
using UnityEditor;
using UnityEngine;
namespace ProjectBootstrap
{
public static class ProjectSaver
{
// Invoke with: -executeMethod ProjectBootstrap.ProjectSaver.SaveAll
public static void SaveAll()
{
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
AssetDatabase.SaveAssets();
Debug.Log("[ProjectSaver] Assets imported and saved.");
EditorApplication.Exit(0);
}
}
}
unity run "<project-path>" --editor-version <version> \
-- -executeMethod ProjectBootstrap.ProjectSaver.SaveAll
メモ
- これらの Editor スクリプトは、ブートストラップを簡便にするためのものです。
Assets/Editor/ProjectBootstrap/に残しておいても(呼び出さない限り何もしません)、セットアップ後に削除しても構いません。判断はお任せします。ユーザーにその旨を伝えてください。 - すべてのスクリプトは
UnityEditorを使用するためEditor/以下に配置されています。ビルドに含まれることはありません。 - マネタイズ/バックエンドのパッケージ(
com.unity.purchasing、com.unity.services.levelplay、UGS パッケージ)も同じ仕組みでインストールしますが、実際の統合には専用のスキルを使ってください:implement-in-app-purchases、levelplay-unity-integration、build-live-game。