NuGetForUnityを使うときの注意点メモ

# はじめに

UnityでNugetパッケージを管理するツールとして[NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity)があります。こちらを使ってパッケージ管理する際の注意点をメモしておきます。


# メモ

## どう使うのか

基本、[README](https://github.com/GlitchEnzo/NuGetForUnity)を読みましょう。

## 導入について

導入方法として公式に「OpenUPM」「UPM経由（Git指定）」「unitypackage」の3つが紹介されています。
お好きな方法で導入してください。

* [GitHubの説明ページ](https://github.com/GlitchEnzo/NuGetForUnity?tab=readme-ov-file#how-do-i-install-nugetforunity)



## NuGetForUnityを使っている場合のバージョン管理方法

NuGetForUnityを使っているUnityプロジェクトをGit管理する場合は「`Assets/Packages`」（設定で他のディレクトリをパッケージ保存先にしている場合はそこを）をgitignoreに指定することを推奨します。

直接Nugetパッケージのdllを管理するのではなく、代わりに次の4ファイルをGit管理下にいれて都度restoreするのがよいでしょう。

* `Assets/NuGet.config` 
* `Assets/NuGet.config.meta` 
* `Assets/packages.config` 
* `Assets/packages.config.meta`

（ただ都度Restoreが面倒なら`Assets/Packages`ごとコミットしてもいいとは思います）

## パッケージの復元(Restore)方法

NuGetForUnityを使っているUnityプロジェクトを`git clone`したり`git pull`したときに、`Assets/Packages`の状態が`packages.config`で指定した状態に一致しない場合があります。この場合は復元（Restore）をしましょう。


### UnityEditorが正常に立ち上がり、コンパイルエラーが出ていない場合

UnityEditorが正常に立ち上がり、コンパイルエラーなども出ていない場合はNuGetForUnityのエディタ拡張メニューから復元ができます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47146/52ac8214-61ae-680f-9fa5-c781d5145ee7.png)


### CI時やコンパイルエラーが出てしまう場合

JenkinsなどでBatchModeでUnityを使っている場合はエディタ拡張から復元することができません。

またプロジェクト中で利用しているdllが欠けている場合、コンパイルエラーが出てしまいNuGetForUnityのエディタ拡張メニューが消えてしまいます（これを解消するために復元がしたいのにそれができないという状態になる）

こういった場合のために、コマンドラインから復元ができるCLIツールが用意されています。

#### NuGetForUnity.Cliをグローバルに導入する場合

```sh
# 導入
dotnet tool install --global NuGetForUnity.Cli

# Unityプロジェクトのディレクトリを指定して復元
nugetforunity restore <PROJECT_PATH>
```

#### NuGetForUnity.Cliをローカルに導入する場合

```sh
cd  <PROJECT_PATH>
dotnet new tool-manifest
dotnet tool install NuGetForUnity.Cli
# パス指定を省略するとカレントディレクトリ指定になる
dotnet nugetforunity restore
```


## うまくパッケージが導入できないとき

回避策は2つあります。

1. `targetFramework`を指定する(後述)
2. 該当のdllのみ手動で導入する（NugetパッケージをDLしてzip解凍し、中のdllを手動でプロジェクトに配置する）


## targetFrameworkを指定する


一部のパッケージは`targetFramework`を指定しないと正しく導入できない場合があります。
とくにUnityの場合は`.NET Framework 4.x`と`.NET Standard 2.1`の2つを併合したAPIセットになっているため、これらが混在したNugetパッケージを導入しようとした場合に正しく導入できなかったり、問題を引き起こす場合があります。

こうした事態を回避したい場合は`Assets/packages.config`から`targetFramework`を指定しましょう。


```xml
<?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>
```

```xml
# これ
<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`などを触ろうとするとエラーが出てしまう可能性があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47146/5be3e476-1e96-2c18-3910-97c95d71a118.png)

これは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](https://github.com/GlitchEnzo/NuGetForUnity/releases/tag/v4.1.1)でUnityのAPI Compatibility Levelの設定に依らず`.NET Standard 2.x`側のパッケージが優先されるオプション（デフォルトON）が追加されました。そのためこちらの問題は発生しづらくなりました。