はじめに
UnityでNugetパッケージを管理するツールとしてNuGetForUnityがあります。こちらを使ってパッケージ管理する際の注意点をメモしておきます。
メモ
どう使うのか
基本、READMEを読みましょう。
導入について
導入方法として公式に「OpenUPM」「UPM経由(Git指定)」「unitypackage」の3つが紹介されています。
お好きな方法で導入してください。
NuGetForUnityを使っている場合のバージョン管理方法
NuGetForUnityを使っているUnityプロジェクトをGit管理する場合は「Assets/Packages」(設定で他のディレクトリをパッケージ保存先にしている場合はそこを)をgitignoreに指定することを推奨します。
直接Nugetパッケージのdllを管理するのではなく、代わりに次の4ファイルをGit管理下にいれて都度restoreするのがよいでしょう。
Assets/NuGet.configAssets/NuGet.config.metaAssets/packages.configAssets/packages.config.meta
(ただ都度Restoreが面倒ならAssets/Packagesごとコミットしてもいいとは思います)
パッケージの復元(Restore)方法
NuGetForUnityを使っているUnityプロジェクトをgit cloneしたりgit pullしたときに、Assets/Packagesの状態がpackages.configで指定した状態に一致しない場合があります。この場合は復元(Restore)をしましょう。
UnityEditorが正常に立ち上がり、コンパイルエラーが出ていない場合
UnityEditorが正常に立ち上がり、コンパイルエラーなども出ていない場合はNuGetForUnityのエディタ拡張メニューから復元ができます。
CI時やコンパイルエラーが出てしまう場合
JenkinsなどでBatchModeでUnityを使っている場合はエディタ拡張から復元することができません。
またプロジェクト中で利用しているdllが欠けている場合、コンパイルエラーが出てしまいNuGetForUnityのエディタ拡張メニューが消えてしまいます(これを解消するために復元がしたいのにそれができないという状態になる)
こういった場合のために、コマンドラインから復元ができるCLIツールが用意されています。
NuGetForUnity.Cliをグローバルに導入する場合
# 導入
dotnet tool install --global NuGetForUnity.Cli
# Unityプロジェクトのディレクトリを指定して復元
nugetforunity restore <PROJECT_PATH>
NuGetForUnity.Cliをローカルに導入する場合
cd <PROJECT_PATH>
dotnet new tool-manifest
dotnet tool install NuGetForUnity.Cli
# パス指定を省略するとカレントディレクトリ指定になる
dotnet nugetforunity restore
うまくパッケージが導入できないとき
回避策は2つあります。
-
targetFrameworkを指定する(後述) - 該当のdllのみ手動で導入する(NugetパッケージをDLしてzip解凍し、中のdllを手動でプロジェクトに配置する)
targetFrameworkを指定する
一部のパッケージはtargetFrameworkを指定しないと正しく導入できない場合があります。
とくにUnityの場合は.NET Framework 4.xと.NET Standard 2.1の2つを併合したAPIセットになっているため、これらが混在したNugetパッケージを導入しようとした場合に正しく導入できなかったり、問題を引き起こす場合があります。
こうした事態を回避したい場合はAssets/packages.configからtargetFrameworkを指定しましょう。
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework=".netstandard2.1"/>
<package id="Microsoft.Bcl.TimeProvider" version="8.0.0" targetFramework=".netstandard2.0"/>
<package id="R3" version="1.1.11" manuallyInstalled="true" />
<package id="System.ComponentModel.Annotations" version="5.0.0" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" />
<package id="System.Threading.Channels" version="8.0.0" />
</packages>
# これ
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework=".netstandard2.1"/>
<package id="Microsoft.Bcl.TimeProvider" version="8.0.0" targetFramework=".netstandard2.0"/>
※ただしこの方法で導入できたからといって、Unity上で正しく動作する保障はありません。場合によっては他のパッケージと干渉してしまう可能性もあります。
mscorlibとの干渉を避ける
Microsoft.Bcl.AsyncInterfacesを導入した状態でIAsyncDisposableなどを触ろうとするとエラーが出てしまう可能性があります。
これはUnity側が提供するランタイム側にIAsyncDisposableが既に定義されてしまっているためです。その状況でMicrosoft.Bcl.AsyncInterfacesを導入したため発生します。
回避策としては「Microsoft.Bcl.AsyncInterfacesを導入する場合は.NET Standard 2.1向けのdllを使う」です。.NET Standard 2.1向けdllはこのあたりの干渉がしないように調整されています。
特にUnityのAPI Compatibility Levelが「.NET Framework」を指定している場合はこの問題を踏む可能性があります。API Compatibility Levelが「.NET Framework」設定の場合、NuGetForUnityはnet462版のdllを優先して解決しようとします。そのため干渉する.NET Framework 4.6.2版のMicrosoft.Bcl.AsyncInterfacesを引っ張ってきてしまい、干渉を引き起こします。なのでNuGetForUnityを使う場合はAPI Compatibility Levelは「.NET Standard」にしておいたほうがよいかもしれないです。
2024/6/13 追記
NuGetForUnity v4.1.1でUnityのAPI Compatibility Levelの設定に依らず.NET Standard 2.x側のパッケージが優先されるオプション(デフォルトON)が追加されました。そのためこちらの問題は発生しづらくなりました。

