あまり需要がなさそうですが、ゲームとかの場合ですと大量の素材データをアプリ内に封入したりすることがあるじゃないかと思います。そしてそれらの素材を全部 Xcode に登録すると、デバッグ時でも転送するたびにその大量の素材データたちを転送する羽目になって非常に効率悪いです。もちろんオンデマンドリソースを使うのも一つの手ですが、ユーザにいちいち追加ダウンロードさせたくないし、こちらのデバッグも初回がサーバからダウンロードしないといけないとなると非常に不便なので、そこで取ったアプローチはリリースビルドだけリソースファイルをアプリ内に封入して、デバッグビルドはアプリ内に封入せず、iTunes でリソースをアプリの Documents フォルダーに入れる方法です。
というわけで、大まかに分けて 3 ステップです:
- アプリを iTunes で書類転送をできるように設定する
- リソースの取得用のクラスとか作って、Release ビルドと Debug ビルドではそれぞれ違うパスからリソースを取得させる
- リソースを Release ビルドの時だけアプリに封入させる
アプリを iTunes で書類転送をできるように設定する
まあこれは簡単ですね、Target の Info タブ行って Application supports iTunes file sharing
の Key
を追加して、Type
を Boolean
にして Value
を YES
にするだけです。そうするとアプリがデバイスにインストールされていれば、PC に接続して iTunes 開いてアプリのページ行くと街灯アプリの書類のやり取りができるようになります。詳しくはこちらの記事などをご参照すればわかりやすいかと思います。
リソースの取得用のクラスとか作って、Release ビルドと Debug ビルドではそれぞれ違うパスからリソースを取得させる
Xcode は初期状態からデフォルトで Preprocessor Macros に DEBUG=1
を入れてくれるので、Objective-C を使うのでしたら特に問題ないのですが、Swift はマクロではなく Swift Flag を使うので、Target の Build Settings ページに行って、Other Swift Flags という項目を探します(表示されなければ Build Settings の下のメニューバーの左側を Basic から All にすると出るはずです)。それの左に三角のボタンがあるので押すと Debug
と Release
がでてきます。ここで Debug
の方に -D DEBUG
のフラグを追加しておきましょう。そうすると Objective-C の時と同じように Debug と Release をコンパイル時にソースコードを分けることができます。
そしてそのクラスからファイル名と拡張しで実際のリソースの URL を取得するので、DEBUG ならメインバンドル、それ以外なら Documents ディレクトリーという風に URL を返します。Swift ならこんな感じでいいでしょう
func urlForResource(name: String, extension: String) -> URL? {
#if DEBUG
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
let resourceURL = documentDirectory?.appendingPathComponent(name).appendingPathExtension(`extension`)
return resourceURL
#else
let mainBundle = Bundle.main
let resourceURL = mainBundle.url(forResource: name, withExtension: `extension`)
return resourceURL
#endif
}
Objective-C なら多分こんな感じでいけるはずかと思います
- (nullable NSURL*) urlForResourceWithName: (NSString*)name andExtension: (NSString*) extension {
#if defined DEBUG
NSURL *documentDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *resourceURL = [[documentDirectory URLByAppendingPathComponent:name] URLByAppendingPathExtension:extension];
return resourceURL;
#else
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *resourceURL = [mainBundle URLForResource:name withExtension:extension];
return resourceURL;
#endif
}
リソースを Release ビルドの時だけアプリに封入させる
さて一番肝心な部分です。これを実現するためにはまずリソースを Xcode に登録してはいけません(正確には登録しても Target Membership にチェックを入れてはいけません)。でないと問答無用でビルドするたびにリソースを転送します。
しかし Release ビルドには転送して欲しいので、ここで活躍するのがスクリプトです。1. の時とちょっと似てますが、今回は Target の Build Phase の方に行って、その直下のメニューバーの左に +
があるのでそれをクリックします。そしたら色々追加できますがここで New Run Script Phase
を選びます。
選んだらスクリプトが追加されますが、ここで下記のようなスクリプトを追加します
if [ "$CONFIGURATION" != "Debug" ]; then
cp -R ../Data/. ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/
fi
簡単に説明すると、要するに Scheme の Configuration が Debug
じゃなければ(つまり Release 設定であれば)、cp -R ../Data/. ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/
を実行するということです。ここで cp -R
は指定のディレクトリ内のものを構造そのまま別のディレクトリーにコピーするということです。../Data/.
というのはコピー元はプロジェクトフォルダーの一個上の Data
フォルダー内(つまり Data フォルダーと Project フォルダーは同列にある)のすべてのファイルということです。これはみなさんの実際状況に合わせて変えましょう。${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/
というのはコピー先はビルド先のアプリバンドル内ということです。これは多分変更することはないかと思われます。
以上。