[iOS] gulp の watch 機能を使って R.swift の生成処理を自動化する
R.swift をもっと簡単にする
先日、弊社の iOS エンジニアの田中が iOS アプリのリソースアクセスを簡単にするライブラリ「R.swift」を紹介いたしました。
ここでも改めて触れますが、R.swift では以下のようなことができます。
- コード補完でリソースファイルにアクセスすることができる
- リソースファイル取得時に型も補完してくれる
- 文字列指定による動的な指定をしなくてよいので静的に解析することができる(コンパイル時にエラーを出してくれる)
大変便利なライブラリですが、注意点としてこのライブラリが生成する R.generated.swift
を都度生成する必要があります。Run Script に R.swift のコマンドを記述することで生成されますが、リソースファイルを編集したら一度ビルドを実行しなければ R.generated.swift
に反映されませんので、ちょっと面倒です。
そこで、直感的に思い浮かんだのが JavaScript 製タスクランナー「gulp」の watch 機能です。こちらを使って、リソースファイルを監視し、変更があったら R.generated.swift
を生成するようにしてみました。
今回作成したものは GitHub で公開しております。必要に応じてご参照ください。
gulp のインストール
はじめに gulp をインストールします。gulp は Node.js 実行環境が必要となります。Node.js がインストールされていない場合は次のブログを参考にインストールしておきましょう。現在では v4.4.7
が LTS の最新バージョンです。
まず gulp コマンドが叩けるよう gulp-cli
をグローバルにインストールします。
$ npm install --global gulp-cli
次にプロジェクトのルートディレクトリに、package.json
を作成します。npm init
から行っても結構です。
{ "name": "xcode-watcher", "version": "1.0.0", "description": "", "main": "gulpfile.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "suwa.yuki", "license": "ISC", "devDependencies": { "gulp": "^3.9.1" } }
npm install
を実行します。devDependencies
に gulp
を指定しているので npm install
を実行するだけで Gulp がインストールされます。
$ npm install
これで gulp が使えるようになりました。
$ gulp -v [11:58:23] CLI version 1.2.2 [11:58:23] Local version 3.9.1
R.swift のコマンドをコマンドラインから実行する
次に、Run Script に書いていた R.swift の生成コマンドを、コマンドラインで叩けるようにします。Xcode のビルド時に実行される Run Script は、Xcode が設定する環境変数が使えるようになっており、R.swift はこの一部の情報を使ってコマンドを実行します。そのため、コマンドラインから叩くには Xcode が設定する環境変数を取得する必要があります。そのようなシェルスクリプトを作りました。次のシェルスクリプトファイルを gen.sh
という名前で作成してください。
#!/bin/sh TARGET_NAME=$1 XCODE_SETTINGS="${TARGET_NAME}.settings" xcodebuild -showBuildSettings -target $TARGET_NAME > ${XCODE_SETTINGS} xcode_setting() { echo $(cat ${XCODE_SETTINGS} | awk "\$1 == \"${1}\" { print \$3 }") } export PODS_ROOT=$(xcode_setting "PODS_ROOT") export PROJECT_FILE_PATH=$(xcode_setting "PROJECT_FILE_PATH") export TARGET_NAME=$(xcode_setting "TARGET_NAME") export PRODUCT_BUNDLE_IDENTIFIER=$(xcode_setting "PRODUCT_BUNDLE_IDENTIFIER") export PRODUCT_MODULE_NAME=$(xcode_setting "PRODUCT_MODULE_NAME") export BUILT_PRODUCTS_DIR=$(xcode_setting "BUILT_PRODUCTS_DIR") export DEVELOPER_DIR=$(xcode_setting "DEVELOPER_DIR") export SOURCE_ROOT=$(xcode_setting "SOURCE_ROOT") export SRCROOT=$(xcode_setting "SRCROOT") export SDKROOT=$(xcode_setting "SDKROOT") ${PODS_ROOT}/R.swift/rswift ${TARGET_NAME}
シェルスクリプトファイルを作成したら、実行権限を与えつつ実行してみましょう。R.generated.swift
ファイルが生成されるはずです。
$ chmod 755 ./gen.sh $ gen.sh <ターゲット名>
リソースファイルを監視する
最後に、gulp の watch 機能と R.swift の生成処理を組み合わせます。gulpfile.js
を新たに作成します。次のようにします。
var gulp = require('gulp'), exec = require('child_process').exec; var target = '<ターゲット名>'; gulp.task('gen', function(cb) { exec(`./gen.sh ${target}`, function (err, stdout, stderr) { cb(err); }); }); gulp.task("watch", function() { var targets = [ './**/*.storyboard', './**/*.xib', './**/*.json', './**/*.png' ]; gulp.watch(targets, ['gen']); });
watch
タスクの中で定義している targets
の配列に、監視対象のファイルを指定します。ここでは私がよく使う拡張子だけ明記しています。また target
は Xcode プロジェクトのターゲット名を入れてください。
実行してみる
それでは実行してみます。まずはコマンドラインにて gulp watch
を実行します。
$ gulp watch [12:15:38] Using gulpfile ~/Desktop/ResourceSample/gulpfile.js [12:15:38] Starting 'watch'... [12:15:38] Finished 'watch' after 147 ms
プロセスが開始し、監視されている状態になりました。この状態で Storyboard ファイルなどを編集したり、画像を追加したりすると R.swift の生成処理が自動で走ります。
まとめ
これで、ようやく Android 感が出てきましたね!(爆)
Xcode プロジェクトの環境変数を引っ張ってくる部分は R.swift に限らず色々な場面で有用だと思うので、ぜひ参考にしてください。