はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】Unity Package Manager(UPM)が認識する自作Packageを作成し、git経由でインストールできるまで整える

はじめに

今回は自作パッケージを作成しPackageManagerAdd package from git URLからインストールできるようにする手法について紹介したいと思います。

実際にインストールしている様子

カスタムパッケージの作成

Package Managerに認識してもらうためには以下の2つをする必要があります。

  • package.json作成
  • asmdef作成

厳密にはpacakge.jsonを作成するだけでもPackageManagerに認識されるのですが、asmdefを配置しないとスクリプトが認識されません。

ファイル・フォルダを生成する

まずはPackagesフォルダに以下のファイルを生成します。(厳密には埋め込みパッケージ以外にも相対パスや絶対パスを用いたローカルパッケージを利用した方法もあります。詳細は公式ドキュメントパッケージソースの箇所をみてください)

Unity公式ではカスタムパッケージに推奨するパッケージレイアウトを以下のようにされています。

<root>
  ├── package.json
  ├── README.md
  ├── CHANGELOG.md
  ├── LICENSE.md
  ├── Third Party Notices.md
  ├── Editor
  │   ├── [company-name].[package-name].Editor.asmdef
  │   └── EditorExample.cs
  ├── Runtime
  │   ├── [company-name].[package-name].asmdef
  │   └── RuntimeExample.cs
  ├── Tests
  │   ├── Editor
  │   │   ├── [company-name].[package-name].Editor.Tests.asmdef
  │   │   └── EditorExampleTest.cs
  │   └── Runtime
  │        ├── [company-name].[package-name].Tests.asmdef
  │        └── RuntimeExampleTest.cs
  ├── Samples~
  │        ├── SampleFolder1
  │        ├── SampleFolder2
  │        └── ...
  └── Documentation~
       └── [package-name].md

パッケージレイアウト - Unity マニュアル

分かりやすくするために今回は必要最低限にして以下の構成でいきます。(一応RuntimeEditorPlatformsが一般的に異なるので、必要最低限ですが両方用意します。Testsはまあなくても良いかなと)

<root>
  ├── package.json
  ├── Editor
  │   ├── [company-name].[package-name].Editor.asmdef
  │   └── EditorExample.cs
  └── Runtime
      ├── [company-name].[package-name].asmdef
      └── RuntimeExample.cs
// サンプル
// 以下のファイル群をPackagesフォルダ以下に生成する
com.hanachiru.samplepackage
  ├── package.json
  ├── Editor
  │   ├── Hanachiru.SamplePackage.Editor.asmdef
  └── Runtime
      └── Hanachiru.SamplePackage.asmdef
ファイル構成

.metaはUnityが自動で生成してくれるので、まずはpackagesフォルダの下に上記のファイル群を生成してあげてください。

中身を記述する

上記のようにファイルを生成したら、中身を書いていきます。

package.json

package.jsonはパッケージの情報を書き込むjsonファイルです。

Unity uses a package manifest file (package.json) to manage information about a specific version of a specific package. The package manifest is always at the root of the package and contains crucial information about the package, such as its registered name and version number. It also defines useful information to communicate to the user, such as a user-friendly name that appears in the UI, a brief description of the package, and the earliest version of Unity the package is compatible with.

// DeepL翻訳
Unityはパッケージマニフェストファイル(package.json)を使用して、特定のパッケージの特定のバージョンに関する情報を管理します。パッケージマニフェストは常にパッケージのルートにあり、登録名やバージョン番号など、パッケージに関する重要な情報が含まれています。また、UI に表示されるユーザーフレンドリーな名前、パッケージの簡単な説明、パッケージが互換性のある Unity の最も古いバージョンなど、ユーザーに伝えるための有用な情報も定義します。

パッケージマニフェスト - Unity マニュアル

package.jsonnameversionのプロパティが必須です。

プロパティ JSON 型 説明
name 文字列 正式に登録されたパッケージ名です。ユニークな識別子である必要があり、Package Managerに表示される名前ではありません
version 文字列 パッケージのバージョン番号。例. 3.2.1

パッケージマニフェスト - Unity マニュアル

またdescriptiondisplayNameunityは任意ですが記述することが推奨されています。

プロパティ JSON 型 説明
description 文字列 パッケージの説明
displayName 文字列 ユーザーに分かりやすい名前
unity 文字列 互換性のあるUnityの最低バージョン。省略された場合は全てのUnityと互換性があるとみなします。例. 2018.3

それ以外は任意ですが、使うのはdependencieslicensekeywordscategoryあたりでしょうか。(UniTaskだとこれくらいだった)

その他プロパティ・詳細は以下の公式ドキュメントを参照してください。
docs.unity3d.com

↓サンプル(package.json)

{
    "name": "com.hanachiru.samplepackage",
    "displayName": "Sample Package",
    "version": "1.0.0",
    "unity": "2018.4",
    "description": "Sample Package.",
    "keywords": [],
    "license": "MIT",
    "category": "",
    "dependencies": {}
}
[company-name].[package-name].asmdef

asmdefについては以下の公式ドキュメントを参照してください。

フォルダー内のスクリプトに基づいて独自のマネージアセンブリを定義するには、アセンブリ定義ファイルを使用します。これを行うには、適切に定義された依存関係を持つ複数のアセンブリにプロジェクトのスクリプトを分けます。こうすると、スクリプトで変更を加えたときに必要なアセンブリのみが再構築され、コンパイル時間が削減されます。Unity プロジェクト内では、各マネージアセンブリを単一のライブラリと考えることができます。

スクリプトのコンパイルとアセンブリ定義ファイル - Unity マニュアル

[company-name].[package-name].asmdef

↓サンプル(Hanachiru.SamplePackage.asmdef)

{
    "name": "Hanachiru.SamplePackage",
    "rootNamespace": "",
    "references": [],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}
[company-name].[package-name].Editor.asmdef

必要なこととしてincludePlatformsEditorのみにする必要があります。

[company-name].[package-name].Editor.asmdef

↓サンプル(EditorToys.Screenshot.Editor.asmdef

{
    "name": "Hanachiru.SamplePackage.Editor",
    "rootNamespace": "",
    "references": [],
    "includePlatforms": [
        "Editor"
    ],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}

Package Managerから確認する

上記の操作が正しくできていれば、PackageManagerから認識されているはずです。

PackageManagerでの表示

Add package from git URLからインストールできるようにする

せっかくなのでGitにあげて、PackageManagerAdd package from git URLからインストールできるようにしましょう。

Publicなリポジトリにファイルをアップロードします。このとき対象パッケージ(package.json)がここになければならないという制約はないので、好きなファイル構成でアップロードしてもらって構いません。

アップロードした様子

例えばSmartAddresserだとUnityプロジェクトをそのままあげていますね。確かにUnityでもそのまま開けますし、悪くない気もします。

GitHub - CyberAgentGameEntertainment/SmartAddresser: Automate Addressing, Labeling, and Version Control for Unity's Addressable Asset System.

これでやるべきことは完了です。

実際にインストールしてみる

package.jsonはどこに配置してもいいと言いましたが、ルートにない場合は?path=/subfolderのようにパスを指定してあげる必要があります。
Git の依存関係 - Unity マニュアル

// ルートにある場合
https://github.com/hanachiru/UnitySamplePackage.git
// ルートにない場合
https://github.com/hanachiru/UnitySamplePackage.git?path=/Packages/com.hanachiru.samplepackage
Add package from git URL

manifest.jsonの場合は以下を追加します。

"com.hanachiru.samplepackage": "https://github.com/hanachiru/UnitySamplePackage.git?path=/Packages/com.hanachiru.samplepackage",

↓実際の例

{
  "dependencies": {
    "com.hanachiru.samplepackage": "https://github.com/hanachiru/UnitySamplePackage.git?path=/Packages/com.hanachiru.samplepackage",
    // ...

さいごに

package.jsonになんのプロパティを書くかだったり、Gitのファイル構成をどうするかあたりは柔軟性があるので、OSSを参考にすると良いと思います。