Posted at

BazelでiOSアプリをビルドしてみる

More than 3 years have passed since last update.

モバイルDevOps Advent Calendar 11日目の記事です


はじめに

今回はBazelでiOSアプリのビルドを行う方法について、一部実際にBazelのソースコードを読みながら解説します。

基本的に公式のチュートリアルに沿ったBUILDスクリプトを作成しますが、このチュートリアルではiPhoneシミュレータで動作可能なipaファイルが作成されてしまうので、今回ここでは実機で動作可能なAdHoc署名されたipaファイルの作成をしてみます。

具体的には、DeployGateで配信可能なipaファイルの作成を行います。

また、BazelによるiOSアプリのビルドを行うことでのメリットですが、現状はBUILDファイルの作成がなかなか難しいため、会社のアプリなどで実際に運用するなどはコストが高すぎると思います。

ですが、Provisioning Profileを明示的に指定したり、Xcodeに依存しない(当然xcodebuildには依存する)ビルドなどを行えるメリットはあります。(GUIが嫌いな方ならこのメリットでかいのではないでしょうか)

今後のBazelプロジェクトの発展で、BUILDファイルの作成コストが低くなることを祈りましょう。


今回の環境

以下が今回使用したプロジェクトです。

https://github.com/henteko/bazeliOSSample

Xcodeで新規プロジェクトを作成したまんまのプロジェクト構成になっています。

また、Xcodeなどのバージョンは以下の通りです。


Xcode

Version 7.1.1 (7B1005)


Bazel

Build label: 0.1.2

Build target: bazel-out/local_darwin-fastbuild/bin/src/main/java/com/google/devtools/build/lib/bazel-main_deploy.jar
Build time: Fri Dec 4 23:20:19 2015 (1449271219)
Build timestamp: 1449271219
Build timestamp as int: 1449271219


JDK

jdk1.8.0_65.jdk


BUILDファイルを作成しよう

さてここから実際にbazelのBUILDファイルの説明になります。

実際に使用するBUILDファイルの全体は以下の通りです。

objc_library(

name = "BazelSampleClasses",
srcs = [
"bazelSample/AppDelegate.m",
"bazelSample/ViewController.m",
],
hdrs = glob(["bazelSample/*.h"]),
storyboards = ["bazelSample/Base.lproj/LaunchScreen.storyboard", "bazelSample/Base.lproj/Main.storyboard"],
)

objc_binary(
name = "ios-app-binary",
srcs = [
"bazelSample/main.m",
],
deps = [
":BazelSampleClasses",
],
)

ios_application(
name = "ios-app",
binary = ":ios-app-binary",
bundle_id = "com.henteko07.bazelSample",
infoplist = "bazelSample/Info.plist",
provisioning_profile = "bazelSample.mobileprovision",
)

細かく見ていきましょう。


objc_library

objc_library(

name = "BazelSampleClasses",
srcs = [
"bazelSample/AppDelegate.m",
"bazelSample/ViewController.m",
],
hdrs = glob(["bazelSample/*.h"]),
storyboards = ["bazelSample/Base.lproj/LaunchScreen.storyboard", "bazelSample/Base.lproj/Main.storyboard"],
)

ここではObjectice-Cのソースファイルの設定などをしています。

srcsに、各ソースファイルを、hdrsにヘッダーファイル、storyboardsには各ストーリーボードまでのpathを指定します。

また、ストーリーボード使っていないプロジェクトや、xibなどがある場合は、別途xibsという引き数名で指定します。(実際にチュートリアルではxibsを使用してます)


objc_binary

objc_binary(

name = "ios-app-binary",
srcs = [
"bazelSample/main.m",
],
deps = [
":BazelSampleClasses",
],
)

ここではバイナリを指定しています。

実際には、プロジェクト内のmain.mを指定しています。

また、depsには上で作成したobjc_libraryのnameに指定した名前を使います。

これでobjc_binary(:ios-app-binary)が実行されると自動でobjc_library(:BazelSampleClasses)も実行されるようになります。


ios_application

ios_application(

name = "ios-app",
binary = ":ios-app-binary",
bundle_id = "com.henteko07.bazelSample",
infoplist = "bazelSample/Info.plist",
provisioning_profile = "bazelSample.mobileprovision",
)

最後にアプリケーションの設定です。

ここでは、binaryに上で作成したobjc_binary(:ios-app-binary)を指定します。

また、bundle_idにはアプリのbundle identifierを指定します。

ちなみに、ここでbundle_idを指定しないと、アプリ内のInfo.plistのCFBundleIdentifierがデフォルトで使われるようです。

なので、現状のXcodeで作られる新規プロジェクトではInfo.plistの中のCFBundleIdentifierが$(PRODUCT_BUNDLE_IDENTIFIER)と指定されているので、これがそのまま使われてしまうみたいです。(要検証)

provisioning_profileには使用したいProvisioning Profileをpathで指定します。

また、この値は実機で動作可能なipaファイル(build時のオプションによって変更可能)を作る時に使用されるようです。


実際にビルドを走らせてみる

さて、実際にビルドをしてみましょう。

ここではBUILDファイルの説明のみしましたが、当然BazelにはWORKSPACEファイルも必要です。

が、今回のプロジェクトではWORKSPACEファイルが空でいいので、touchなどで作成しておきましょう。


ビルドの実行

以下のコマンドで、実際に実機で動作可能なipaファイルのビルドが可能です。

$ bazel build //:ios-app --ios_sdk_version=9.1 --ios_cpu="arm64" --default_ios_provisiong_profile=":bazelSample.mobileprovision"

//:ios-appでBUILDで作成したios_application(:ios-app)を指定しています。

また、以下のオプションを使用しています。


ios_sdk_version

これでiOSのSDK Versionを指定します。

現状のBazel(0.1.2)ではデフォルトでDEFAULT_IOS_SDK_VERSION="8.4"が指定されています。

ソースコードを参照

iOS SDKの8.4がインストールされている環境では問題ないのですが、筆者の環境だと9.1しかインストールされていなかったので、9.1を指定するようにしています。

もちろん、8.4のダウンロードをXcodeで行えば、そのままでも動作可能です。


ios_cpu

これでビルド対象のCPUアーキテクチャを指定します。

現状のBazel(0.1.2)ではデフォルトでDEFAULT_IOS_CPU="x86_64"が指定されています。

ソースコードを参照

これをそのまま使うと、シミュレータ用のipaファイルが出力されることになってしまうので、今回はarm64を指定しました。

もちろん、その他のCPUアーキテクチャを指定することも可能です。

実機のiPhoneで使用されているCPUアーキテクチャは他の方の記事を参照してください。

また、実際にどうやってこのCPUアーキテクチャからipaの種類を変更しているかについては、ソースコードに書いてあるので参照してください。

ソースコードを参照


default_ios_provisiong_profile

ここではios_applicationで指定したものと同じProvisioning Profileを指定します。

また、ここでの指定方法はLabelを使っているらしく、実際にBUILDファイル内に指定したprovisioning_profileを参照するらしく、BUILDファイル内にprovisioning_profileの指定が無いとエラーになります。


ipaファイル

ビルドを実行すると、以下のpathにipaファイルが作成されます。

./bazel-bin/ios-app.ipa

これをDeployGateにアップロードすれば、実機で動作が確認できると思います。

また、ipaファイルのアップロードにはdgコマンドを使用すると簡単にアップロードができるので、オススメです。

$ dg deploy ./bazel-bin/ios-app.ipa

このdgコマンドについては、他の方が書いてくれた記事があるので、ご参照ください。


おわりに

今回はiOSアプリのビルドにBazelを使用して、実際に実機で動作可能なipaファイルの作成を紹介しました。

冒頭でも述べた通り、まだBazelでのiOSビルドのメリットはあまりないと思いますが、今後のBazelプロジェクトに期待しましょう!!!!