🐷

【Unity】Macアプリを、公証済みpkg(インストーラー)で配布する

2023/04/25に公開

恋愛メタバースMemoriaを運営するFlamers CTOの設楽(だーら)です。今回は、Mac向けのアプリを、Appleからの公証を受けた状態かつインストーラー形式で配布する方法についてまとめます。
既存の記事を参考に進めれば可能な部分は多いですが、当記事に補足としてまとめている部分も案外重要かなと思いまとめました。

前置き

今回やりたいこと

  • Unity製のMac向けアプリケーションをユーザーに配布する
  • ユーザーが簡単に起動できるように、Appleからの公証を受けた状態で配布する(公証がない場合、特別な手段が必要。詳細は別の記事に記述)
    • 公証を得ない場合、「インターネットからダウンロードしたアプリを開くためには、ターミナルを起動する必要がある」などの問題があります。
  • zip形式でアプリを生で配布するのではなく、pkgの形でインストーラーとして配布したい。
    • すると、アップデートなども容易になる。

      完成形のイメージ

前提

  • Apple Developer Programに通過していることが条件となります。申請については、スクラップになりますがこちらの記事にまとめています。
    • 年間1万数千円の料金がかかります。
    • Appleとの電話などが必要ですが、思ったよりも取得は簡単でした。
  • 作業はMacBookで行います。ただし、Unityでの作業はWindowsPCでできます(自分はそうしました)

参考リンク

全体像

  • 証明書を要求するための準備
  • Apple Developerにて、Certificateの作成
  • Apple Developerにて、Identifierの登録
  • Apple Developerにて、Deviceの登録(これが本当に必要かは未検証です。検証した方いたら教えてほしいです)
  • (いつでもいいが)UnityでMac用にビルド
  • Xcodeでentitlementsファイルの作成
  • コマンドラインで署名、パッケージ化、提出

詳細

証明書を要求するための準備と、Apple DeveloperでのCertificateの作成

補足1. 取るべきCertificate

  • Developer ID InstallerとDeveloper ID Applicationの2種類を取得する。
  • appをpackageのインストーラー形式で配布するとき、.appはapplicationの方で署名し、.pkgはinstallerの方で署名する。

補足2. Profile Typeについて

  • 画像の用に、G2 Sub-CAとPrevious Sub-CAを選択可能。G2の方が新しいようなのでそちらを選ぶ。
  • 一つのCertificate Signing Request(CSR) fileでは、一つだけのG2発行の証明書を取得できる。そのため、参考に貼ったリンク通り、2つのCSRファイルを作成しておく必要がある
  • 同じCSRファイルで、G2発行の別のCertificateを取得しようとすると以下のようなエラーがでる

補足3. 中間証明書について

  • 以下の画像の用に、赤文字で「証明書は信頼されていません」と出ることがある。
  • これは、中間証明書が無いことが原因。こちらの記事に従って、証明書の発行局の、対応する中間証明書をダウンロードし、ダブルクリックして登録しておく必要がある。
  • Developer ID - G2発行のものは以下の画像の中間証明書をダウンロード

Apple Developerにて、Identifierの登録

  • AppIDを作成する。
  • ここで登録しているBundle IDで、おそらくアプリの同一判定を行っている。Unityのビルドとも関係あり。基本はUnityで作成される、com.xxxxxx.yyyyyyの形式と合わせれば良さそう。
  • Capabilitiesは特に指定しなかったがいけた。

Apple Developerにて、Deviceの登録

  • Device ID(UUID)の調査方法はこちら
  • Device Nameは適当につければよき(おそらくダッシュボードでの識別用)

UnityでMac用にビルド

  • Project Settings > Player > Other Settings > Mac App Store Optionsの設定を変更する
  • Bundle Identifierは、Overrideせずにそのまま入力されているものでよさそう。これが先程Apple Developerで作成したBundle IDと同じになるようにする。
  • Buildは、アプリのバージョンを管理している。Project自体のversionではなく、こちらのBuildの数値によってアップデートを判断している模様。補足で詳細にかく。
  • Categoryは、こちらのドキュメントに一覧がある
  • App Storeには配布しないので、Mac App Store Validationにチェックを入れない

補足1. Buildについて

  • アプリのバージョンを管理している数値。
  • .pkgに含まれる.appの、Buildの数値によって、以下のように上書きが走ったり走らなかったりする
  • すでにMac上にあるapplicationのBuildの数値を現行Build、新しくインストールする.pkgに含まれる.appのBuildの数値を新Buildとしたときの、インストールの結果はこちら
現行Build 新Build 結果 補足
1.5.2 1.5.3 置き換わる Finder内のアプリケーションの更新時刻が最新になる。再生した実際のゲームの中身も更新される(★1)
1.5.3 1.5.2 置き換わらない 上の逆で、Finder内のアプリケーションの更新時刻は1.5.3を入れたときのまま。再生した実際のゲームの中身も更新されない(★2)
1.5.3 1.5.3 置き換わる Finder内のアプリケーションの更新時刻が最新になる。再生した実際のゲームの中身も更新される
  • なお、上の表の★1の前後でプロジェクト自体のversionは上げていない(現行Buildも新Buildも両方1.5.2)。しかし、プロジェクトは更新される。故に、プロジェクト自体のversionはアップデートには関係なさそう(まあちょっと検証不十分ではあるが雰囲気そう)。
  • ★2のときも、インストーラーが走ったような挙動にはなる。だが少しだけ書き込み時間が短かかった感覚。
  • プロジェクト自体のversionの数値と、Buildのversionの数値を同じにすれば良さそう?

補足2. アプリ名について

  • .pkgでインストールされると、通常であればアプリケーション(/Applications)の下にアプリが作成される。よって、Macのアプリ一覧に表示される
  • このときの名前は、一番最初にインストールするときの、.appの名前になる模様。
  • xxyy.appであれば、xxyyというアプリができる。
  • なお、一度作成されたアプリ名は、その後インストーラー経由でアプリをアップデートしてもそのまま引き継がれる模様。なので、アプリ名にはバージョンなどは含めないほうがよい。
  • .pkgの名前は関係ない。ゆえに、xxyy_ver1.5.2.pkgという名前でもOK!

Xcodeでentitlementsの作成

  • entitlementsファイルを生成するために、Xcodeで空のアプリを作る。Xcodeで作成する必要はないかもしれないが、安心感あるのでこの方法で作成した。
  • macOS向けのAppを選択。
  • ProfuctNameなどを入れる。
  • Xcodeのプロジェクトが立ち上がる。
  • ✔みたいなファイルが.entitlementsファイル。GUIで編集できる。
  • .entitlementsファイルは、Unityのプロジェクト内に持ってくる必要はない。後ほどターミナルで打つコマンドの際に利用される。ファイルのパスだけ把握しておけばOK。

補足1. .entitlementsの記述内容

  • 他の方も書いているが、com.apple.security.cs.allow-unsigned-executable-memoryを、ValueをYESとして追記しないと動かなかった。
  • その他、必要そうな画像のような値を追加した。

補足2. Codeで.entitlementsを見る

  • 僕のローカル環境のディレクトリが見えて恐縮ですが、以下の場所に.entitlementsファイルがあります。
% ls -a ~/Projects/XcodeProjects/MemoriaVR/MemoriaVR
.			..			Assets.xcassets		ContentView.swift	MemoriaVR.entitlements	MemoriaVRApp.swift	Preview Content
  • テキストエディターで見ると以下のようなxmlファイルとなっている。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.device.audio-input</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-only</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
	<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
	<true/>
</dict>
</plist>

コマンドラインでの作業

  • まず、.appでの全てのコンテンツの読み込み制限を修正する
chmod -R a+xr mygame.appのパス
  • 次に、.entitlementsで.appに署名をする。この際に、Developer ID Applicationの方を使う。
codesign -o runtime -f --deep -s 'Developer ID Application: チーム名 (チームID)' --entitlements mygame.entitlementsのパス mygame.appのパス
  • 以下コマンドで署名の確認ができる
codesign -dvv mygame.appのパス
  • 次に、.pkgを作成する。この際に、Developer ID Installerの方を使う。
productbuild --component mygame.appのパス /Applications --sign "Developer ID Installer: チーム名 (チームID)" mygame.pkgのアウトプット先のパス
  • 以下コマンドでパッケージ化の確認ができる。
pkgutil --check-signature mygame.pkgのパス
  • 提出のコマンドを打つ前に、以下の手順に従って、そのApp用のパスワードを作成しておく必要がある。
  • 最後に、提出する。なお、チームIDは下の画像の、赤い縁の中の数値。5分くらい待てば結果がでる。
Xcrun notarytool submit mygame.pkgのパス --apple-id "自分のApple ID" --password "先程作ったアプリパスワード。形式はwwww-xxxx-yyyy-zzzz" --team-id "チーム ID" --wait


チームIDは赤縁

完成!

  • 最後のXcronコマンドでstatus: Acceptedとなれば完了!
  • mygame.pkgを配布することで、インストーラーとして機能する。

補足. すでにその人のMacに同一のアプリケーションがある場合

  • 通常は、/Applicationsの下にアプリが入る。
  • しかし、その人のMacにもともと同じアプリ(Bundle IDが同じアプリ)がある場合、そのもともとのディレクトリの位置で上書きがされる模様。
  • インストーラーでのアプリ配布前から渡していた人へは、アプリ一覧に表示されない可能性があることを注意喚起する必要がある。
Flamers Tech Blog

Discussion