iOSプロジェクトのステージ、高清細テクスチャ、オフラインモデルなどをOn-Demand Resourcesへ移行すると、通常はアプリのインストールサイズを大幅に削減できます。ただし、ビルドが成功しても、リソースが実際に利用できるとは限りません。よくある問題はコンパイルエラーではなく、タグの設定漏れ、テスト用ビルドへの全リソースの意図しない埋め込み、またはリリース成果物のリソースパックとコードからのリクエストの不一致です。クラウドMacでは、こうした確認を独立したジョブとして定型化できます。毎回クリーンなワークスペースからアーカイブし、マニフェストとチェックサムを保存したうえで、実際のリソースリクエストまで実行します。
検収可能な範囲を先に定義する
ODRの検収では、少なくともプロジェクト設定、書き出し成果物、実行時リクエストの3層を確認する必要があります。いずれか1層だけでは死角が残ります。
プロジェクト層では、TargetでOn-Demand Resourcesが有効になっていること、リソースカタログ内の各タグに明確な用途があることを確認します。成果物層では、.assetpack、マニフェストファイル、ファイルハッシュを検査します。実行時層では、初回リクエスト、リソースの解放、再リクエストを検証します。
「アプリが起動する」だけでは、ODRの検収基準として不十分です。一度もアクセスされないステージリソースが完全に欠落していても、ホーム画面の起動は妨げられません。
各タグについて、担当者、トリガーとなる画面、想定するリソースの種類、初回インストールに必須かどうか、という4項目を記録しておくことを推奨します。これらはXcodeの画面内だけに残すのではなく、通常のテキストマニフェストとしてリポジトリに保存します。
安定したタグでパック分割の粒度を制御する
タグをフォルダ数と1対1で対応させないでください。粒度が細かすぎると小さなパックと頻繁なリクエストが大量に発生し、粗すぎると1つの画面を開くためだけに無関係なリソース一式をダウンロードすることになります。より安定した方法は、level-01、tutorial-audio、model-basicのようにユーザーの操作フロー単位で分割し、コード内のリクエスト名とリソースカタログのタグを完全に一致させることです。
タグマニフェストをゲートにする
使用を許可するタグをリポジトリに保存できます。
level-01
level-02
tutorial-audio
model-basic
ビルドスクリプトでプロジェクトファイルまたは生成後のリソース情報からタグを抽出し、ソートしてからこのマニフェストと比較します。タグを追加する場合は、必ずマニフェストも変更します。タグを削除する場合は、コード内のNSBundleResourceRequest呼び出しも併せて確認します。これにより、スペルミスを実行時ではなくマージ時に検出できます。
タグ名には安定したASCII文字だけを使用し、スペース、大文字と小文字の混在、一時的なバージョン番号は避けます。リソースの更新はコンテンツバージョンまたはチェックサムで表現し、level-final-v2-newのような保守不能な名前を増やし続けないでください。
アーカイブと書き出しの条件を固定する
同じコミットには、固定したworkspace、scheme、Release構成、書き出しオプションを使用します。VMArmノード上のジョブでは、今回の出力ディレクトリを最初に空にして構いませんが、グローバルキャッシュを一律に削除しないでください。変更の原因がリソースなのか環境なのかを判断しにくくなります。
set -euo pipefail
: "${WORKSPACE:?WORKSPACE is required}"
: "${SCHEME:?SCHEME is required}"
ROOT="$PWD"
ARCHIVE_PATH="$ROOT/out/Game.xcarchive"
EXPORT_DIR="$ROOT/out/export"
rm -rf "$ARCHIVE_PATH" "$EXPORT_DIR"
mkdir -p "$EXPORT_DIR"
xcodebuild \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$ARCHIVE_PATH" \
clean archive
xcodebuild \
-exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportPath "$EXPORT_DIR" \
-exportOptionsPlist "$ROOT/ci/ExportOptions.plist"
ローカル検収用の経路では、embedOnDemandResourcesAssetPacksInBundleをtrueに設定し、まずパックの内容とリクエスト処理が正しいことを確認できます。本番経路では、実際の配布方式に対応する書き出し設定を使用し、ローカル用の埋め込み設定を流用してはいけません。2つの経路の成果物は別々のディレクトリに保存し、テスト用ビルドがリリース予定のビルドを上書きしないようにします。
成果物を3層で検査する
第1層ではファイルの存在を確認します。第2層ではplistを解析できることを確認します。第3層ではすべてのリソースファイルについて安定したチェックサムを生成し、同じコミットから作成した2回のビルドを比較できるようにします。
set -euo pipefail
ARCHIVE_PATH="$PWD/out/Game.xcarchive"
EXPORT_DIR="$PWD/out/export"
REPORT_DIR="$PWD/out/report"
mkdir -p "$REPORT_DIR"
find "$ARCHIVE_PATH" "$EXPORT_DIR" \
-name '*.assetpack' \
-print | LC_ALL=C sort > "$REPORT_DIR/assetpacks.txt"
find "$ARCHIVE_PATH" "$EXPORT_DIR" \
-name 'AssetPackManifest.plist' \
-exec plutil -lint {} \; > "$REPORT_DIR/plist-lint.txt"
find "$ARCHIVE_PATH" "$EXPORT_DIR" \
-type f \
\( -name '*.car' -o -name '*.plist' -o -name '*.assetpack' \) \
-exec shasum -a 256 {} \; |
LC_ALL=C sort > "$REPORT_DIR/checksums.txt"
test -s "$REPORT_DIR/assetpacks.txt"
.assetpackが実際にはディレクトリである場合、最後のハッシュコマンドではその内容を直接計算できません。そのため、ディレクトリ配下の通常ファイルも検査対象に含める必要があります。レポートにはコミット番号、Xcodeのバージョン、scheme、書き出し設定ファイルのハッシュを記録しますが、署名用秘密鍵、トークン、認証情報への完全なパスは記録しないでください。
2つのレポートを比較するときは、まず「ファイル順の変化」と「内容の変化」を区別します。ソート方法を統一すれば、前者は除外できます。同じコミットでもハッシュが変わり続ける場合は、生成スクリプトがタイムスタンプ、ワークスペースの絶対パス、ランダムな識別子を書き込んでいないか確認します。
実行時の検証とトラブルシューティング
実行時テストはクリーンな状態から開始します。検収用ビルドをインストールした後、初回インストール対象ではないタグを1つリクエストし、リクエスト開始、アクセス可能になった時点、リソース解放の3つのイベントを記録します。その後アプリを終了してテスト環境をクリーンアップし、もう一度実行します。成功が古いキャッシュによるものではないことを確認してください。
よくある症状の確認順序
リクエストが即座に失敗する場合は、まずコード内のタグとリソースカタログのタグを照合します。リクエストが長時間待機する場合は、リソースパックが正しく書き出されているか、テストネットワークに問題がないかを確認します。ローカル埋め込みでは成功する一方で本番経路では失敗する場合は、2つのExportOptionsとリソースホスティング設定を重点的に比較します。一部のリソースだけが欠落する場合は、同名ファイルが複数のタグに割り当てられていないか、またはそのリソースが依然としてメインバンドルに含まれていないかを確認します。
無限リトライでエラーを覆い隠してはいけません。リクエストには明確なタイムアウトを設定し、失敗ログにはタグ、エラードメイン、エラーコード、処理段階だけを記録します。アクセストークンや機密性の高いパスは出力しないでください。検収完了後は、レポート、書き出し設定のハッシュ、失敗ログを保存し、一時パッケージとテストキャッシュを削除します。これにより、次回のODR変更で差異が生じたとき、Xcodeの挙動を推測し直すのではなく、成果物を直接比較できます。
よくある質問
開発用ビルドにはODRリソースパックを埋め込むべきですか?
最初のローカル検証では有効です。embedOnDemandResourcesAssetPacksInBundleをtrueにしてパッケージングを先に確認し、その後に実際の配信設定を使った別の書き出しを検証します。
IPAの容量だけでODRの正しさを判断できますか?
できません。assetpackの数、タグ対応、AssetPackManifest.plist、ファイルハッシュを確認し、キャッシュ削除後にも再取得して、残存データによる見かけ上の成功を除外します。
次回のXcodeビルドに、365日稼働のクラウドMacを選択
チップ、メモリ、ストレージ、請求期間、ノードのリージョンを確認して、設定に進みます。実際の利用可能状況はコンソールのリアルタイム表示をご確認ください。