※これ書いたの2年位まえなので情報メガッサ古いので注意してくださいね★
Unityのビルドが面倒くさい……
会社でスマホ向けのゲームをUnityで作っているのですが、Unityのビルドって面倒くさいですよね!
- コードをチェックアウトしてくる
- Unityを起動する
- Android向けにビルドする
- iOS向けにビルドする
- 実機で遊びたい会社の人(エライ人含む)の端末にせっせとインストールする
こんなことやってると一日仕事です! 僕の一日は adb install をひたすら打ち続けるだけで浪費されてしまいます。
しかも会社にはいろんな人がいます。
- 企画の人 / 営業の人 / マネージャー つまりUnity使わない人
- Windowsで開発してるけど、使ってるスマホはiPhoneの人
- 外部の協力会社の人(テスターさんとか)
こんないろんな人達のためにひたすらインストールし続けるとか非生産的すぎます( ゚皿゚)キーッ!!
そこでJenkinsさんの出番です
CI (Continuous Integration)とか継続的インテグレーションが随分と浸透してきました。簡単に言うとプログラムを自動で、継続的に、ビルドしてくれる仕組みとでも思ってください。
CIサーバとしてよく利用されるのがJenkinsさんです。Jenkinsさんは継続的インテグレーションの手助けをしてくれるプログラムです。
JenkinsさんにUnityプロジェクトのビルドのやり方を登録してあげれば、あら簡単、リンクをポチるだけで自動でビルドをしてくれるじゃないですか!
Jenkinsさんでスマホ向けにビルドをする方法は【研究課題レポート抜粋】Jenkins+Unityで構築するスマフォアプリビルドサーバー を参考にして構築しました。アメーバさんありがとう!
ちょっと改良
でも、このとおりだと、ちょっといろいろ、面倒なので若干の改良を加えました。
ビルド対象のシーンを自動で
先ほどのブログでは、ビルド対象のシーンを配列に登録して管理しています。
private static string[] scene = {"Assets/_Scenes/PiggCube.unity"};
この方法ですと、シーンが増えるたびに配列にシーンを追加しなおさないと行けないのですごく手間です。
ですので、BuildSettingsのScenes in Buildに入っているシーンを取得して、配列にして返す関数を用意しました。
private static string[] GetScenes() {
ArrayList levels = new ArrayList();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
if (scene.enabled) {
levels.Add(scene.path);
}
}
return (string[]) levels.ToArray(typeof(string));
}
これを使えばシーンを追加しても、ビルドスクリプト自体に手を入れなくてよくなります。
Jenkinsが実行するシェルスクリプトにエラー処理を追加
上のスクリプトですと、Unityからプロジェクトを吐き出すところでしかエラーハンドリングがされていません(exit codeも必ず1が返却される……)。
ですので、エラーハンドリングを追加しました。xcodeでappファイルを作るところと、ipaファイルに変換する部分です。
#----------------------------------------------------------------------
# コマンドラインでのipaと.dSYMファイルの作成
#----------------------------------------------------------------------
#------- xcodeプロジェクトをビルドして .appと.dSYMを生成する -------#
BUILD_OPT_MAKE_DSYM="GCC_GENERATE_DEBUGGING_SYMBOLS=YES DEBUG_INFORMATION_FORMAT=dwarf-with-dsym DEPLOYMENT_POSTPROCESSING=YES STRIP_INSTALLED_PRODUCT=YES SEPARATE_STRIP=YES COPY_PHASE_STRIP=NO"
xcodebuild -project "${XCODE_PROJECT_CONFIG_PATH}" -configuration "${CONFIGURATION}" CODE_SIGN_IDENTITY="${IDENTITY}" $BUILD_OPT_MAKE_DSYM
# xcodeプロジェクトのビルドに失敗した場合
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
cat "can not build app file"
exit $EXIT_CODE
fi
#------- .appからipa作成 -------#
/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${TARGET_APP_PATH}" -o "${IPA_FILE_PATH}"
# ipaへの変換に失敗した場合
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
cat "can not build ipa file"
exit $EXIT_CODE
fi
これをやらないと何が困るかというと、例えばiPhone Developerの証明書の有効期限が切れた時。
こういう場合は xcodeでのビルドでコケるのですが、エラーハンドリングしていないとJenkinsさんは正常終了したと勘違いして処理を終わらせてしまします。エラーでコケてるのに……。
証明書は忘れた頃に突然有効期限が切れるので、注意が必要です。
ビルドは楽になったがががが
さてさて、これでビルドは楽になった!
Jenkinsさんでリンクをワンクリックするだけでipaファイルとapkファイルが出来上がる! ひゃっほー!
……と思ったのですが、これではまだまだインストール地獄から解放はされていません。
apkやipaファイルをJenkinsさんからダウンロードして、みんなそれぞれのマシンで自分のスマホにいれればいいじゃない! と思うのですが、営業さんや企画さんやエライ人には敷居が高すぎて無理です!
iOS向けはしかたがない……iPhone構成ユーティリティとかxcodeのオーガナイザーから泣く泣くインストールしましょう。。。
でもandroidは……。apkファイルさえダウンロードできれば簡単にスマホにインストールできるじゃないか!
企業特有の事情
Jenkinsさんが、手持ちのスマホからアクセスできる場所に設置されていれば問題ありません。
Jenkinsさんにandroid端末からアクセスして、目的のapkファイルをダウンロードすればあっという間にインストール完了です。
でも、多くの企業では社外からアクセスできない社内ネットワーク上にJenkinsさんが置かれているのではないでしょうか?
さらに、スマホの社内ネットワーク接続が禁止されてるとかとかとか。
つまり、インターネットからJenkinsさんにアクセスできない! というシチュエーションが多いとおもいます。
あー、これは詰んだか。インストール祭りか。楽はできないのかーー。
……諦めたらそこでゲームは終了です。
androidはGoogle アカウントと紐付いています。
そ、そうだ! Google様を使おう!
Jenkinsでビルドした成果物をGoogle Driveにアップロードする。
Google Drive(旧名:Google Docs)ですが、ここ、わりかしなんでもアップロードできちゃいます。
Jenkinsさんが作った成果物をここにあげちゃえばいいんだ!
でもどうやって?
ここは徹底的に手抜きしましょう。
Google DriveにはMac用のクライアントアプリがあります。
これをインストールすると、ローカルGoogle Drive用のディレクトリをリモートのGoogle Driveと同期してくれます
そうです、Jenkinsさんの成果物をこのGoogle Drive用のディレクトリにおいてあげればいいだけです。
前述の、ビルド用のシェルスクリプトに一行
cp ${コピー元APKファイル} ${Google Drive用ディレクトリ}
を追加すればOKです。
あとはandroid端末から、Google Driveにアクセスして、apkファイルをダウンロードすればOK
営業さんや企画やさんやエライ人には「ここからダウンロードしてください」とGoogle DriveのURLを送り付ければあとはみんなが勝手にインストールしてくれるという寸法です!
注意点としては、Google Driveでの共有範囲の設定をきちんとやること。
これ、間違えると開発中のアプリが誰からでもアクセスできるなんていう恐ろしいことになるから注意が必要ですよ……。
やった! これでインストール地獄からも解放される!
おめでとう! ありがとう!
で、iPhoneむけはどうすれば簡単になるの?
( ゚д゚)ハッ!
……だれか簡単になる方法があればご教授ください。