注: Android アプリのビルドに Bazel を使用する場合、既知の制限事項があります。既知の問題の一覧については、GitHub の team-Android ホットリストをご覧ください。Bazel チームとオープンソース ソフトウェア(OSS)のコントリビューターは既知の問題の解決に積極的に取り組んでいますが、Android Studio は Bazel プロジェクトを公式にはサポートしていません。
このチュートリアルでは、Bazel を使用してシンプルな Android アプリを作成する方法について説明します。
Bazel は、Android ルールを使用した Android アプリのビルドをサポートしています。
このチュートリアルは、Windows、macOS、Linux のユーザーを対象としており、Bazel または Android アプリ開発の経験は必要ありません。このチュートリアルでは、Android コードを記述する必要はありません。
学習内容
このチュートリアルでは、次の方法について学びます。
- Bazel と Android Studio をインストールし、サンプル プロジェクトをダウンロードして、環境をセットアップします。
- アプリのソースコードと、ワークスペース ディレクトリの最上位を識別する
WORKSPACE
ファイルを含む Bazel ワークスペースを設定します。 - 必要な外部依存関係(Android SDK など)への参照を含むように
WORKSPACE
ファイルを更新します。 BUILD
ファイルを作成します。- Bazel を使用してアプリをビルドします。
- Android エミュレータまたは実機にアプリをデプロイして実行します。
始める前に
Bazel をインストールする
チュートリアルを開始する前に、次のソフトウェアをインストールします。
- Bazel。インストールするには、インストール手順に沿って操作してください。
- Android Studioインストールするには、Android Studio をダウンロードする手順に沿って操作します。設定ウィザードを実行して SDK をダウンロードし、環境を構成します。
- (省略可)Git。
git
を使用して Android アプリ プロジェクトをダウンロードします。
サンプル プロジェクトを取得する
サンプル プロジェクトには、Bazel のサンプル リポジトリにある基本的な Android アプリ プロジェクトを使用します。
このアプリには、クリックすると挨拶を表示するボタンが 1 つあります。
図 1. Android アプリボタンの挨拶。
git
を使用してリポジトリのクローンを作成します(または、ZIP ファイルを直接ダウンロードします)。
git clone https://github.com/bazelbuild/examples
このチュートリアルのサンプル プロジェクトは examples/android/tutorial
にあります。チュートリアルの残りの部分では、このディレクトリでコマンドを実行します。
ソースファイルを確認する
アプリのソースファイルを確認します。
.
├── README.md
└── src
└── main
├── AndroidManifest.xml
└── java
└── com
└── example
└── bazel
├── AndroidManifest.xml
├── Greeter.java
├── MainActivity.java
└── res
├── layout
│ └── activity_main.xml
└── values
├── colors.xml
└── strings.xml
主なファイルとディレクトリは次のとおりです。
名前 | 場所 |
---|---|
Android マニフェスト ファイル | src/main/AndroidManifest.xml 、src/main/java/com/example/bazel/AndroidManifest.xml |
Android ソースファイル | src/main/java/com/example/bazel/MainActivity.java 、Greeter.java |
リソース ファイル ディレクトリ | src/main/java/com/example/bazel/res/ |
Bazel を使用したビルド
ワークスペースを設定する
ワークスペースは、1 つ以上のソフトウェア プロジェクトのソースファイルを含むディレクトリで、ルートに WORKSPACE
ファイルがあります。
WORKSPACE
ファイルは空のか、プロジェクトのビルドに必要な外部依存関係への参照を含んでいる可能性があります。
まず、次のコマンドを実行して空の WORKSPACE
ファイルを作成します。
OS | コマンド |
---|---|
Linux、macOS | touch WORKSPACE |
Windows(コマンド プロンプト) | type nul > WORKSPACE |
Windows(PowerShell) | New-Item WORKSPACE -ItemType file |
Bazel の実行
次のコマンドを使用して、Bazel が正しく実行されているかどうかを確認できます。
bazel info workspace
Bazel が現在のディレクトリのパスを表示したら、準備完了です。WORKSPACE
ファイルが存在しない場合、次のようなエラー メッセージが表示されることがあります。
ERROR: The 'info' command is only supported from within a workspace.
Android SDK と統合する
Bazel は、Android SDK のビルドツールを実行してアプリをビルドする必要があります。つまり、Bazel がビルドツールを見つけられるように、WORKSPACE
ファイルに情報を追加する必要があります。
WORKSPACE
ファイルに次の行を追加します。
android_sdk_repository(name = "androidsdk")
これにより、ANDROID_HOME
環境変数で参照されるパスで Android SDK が使用され、最も高い API レベルとその場所にインストールされているビルドツールの最新バージョンが自動的に検出されます。
ANDROID_HOME
変数に Android SDK の場所を設定できます。Android Studio の SDK Manager を使用して、インストールされている SDK のパスを探します。SDK がデフォルトのロケーションにインストールされていると仮定すると、次のコマンドを使用して ANDROID_HOME
変数を設定できます。
OS | コマンド |
---|---|
Linux | export ANDROID_HOME=$HOME/Android/Sdk/ |
macOS | export ANDROID_HOME=$HOME/Library/Android/sdk |
Windows(コマンド プロンプト) | set ANDROID_HOME=%LOCALAPPDATA%\Android\Sdk |
Windows(PowerShell) | $env:ANDROID_HOME="$env:LOCALAPPDATA\Android\Sdk" |
上記のコマンドは、現在のシェル セッションにのみ変数を設定します。永続的にするには、次のコマンドを実行します。
OS | コマンド |
---|---|
Linux | echo "export ANDROID_HOME=$HOME/Android/Sdk/" >> ~/.bashrc |
macOS | echo "export ANDROID_HOME=$HOME/Library/Android/Sdk/" >> ~/.bashrc |
Windows(コマンド プロンプト) | setx ANDROID_HOME "%LOCALAPPDATA%\Android\Sdk" |
Windows(PowerShell) | [System.Environment]::SetEnvironmentVariable('ANDROID_HOME', "$env:LOCALAPPDATA\Android\Sdk", [System.EnvironmentVariableTarget]::User) |
path
、api_level
、build_tools_version
属性を含めることで、Android SDK の絶対パス、API レベル、使用するビルドツールのバージョンを明示的に指定することもできます。api_level
と build_tools_version
が指定されていない場合、android_sdk_repository
ルールは SDK で利用可能な最新バージョンを使用します。これらの属性は、SDK に存在する限り、任意の組み合わせで指定できます。次に例を示します。
android_sdk_repository(
name = "androidsdk",
path = "/path/to/Android/sdk",
api_level = 25,
build_tools_version = "30.0.3"
)
Windows では、path
属性に混合スタイルのパス(スラッシュを含む Windows パス)を使用する必要があります。
android_sdk_repository(
name = "androidsdk",
path = "c:/path/to/Android/sdk",
)
省略可: ネイティブ コードを Android アプリにコンパイルする場合は、Android NDK をダウンロードし、WORKSPACE
ファイルに次の行を追加して、その場所を Bazel に指定する必要があります。
android_ndk_repository(name = "androidndk")
android_sdk_repository
と同様に、Android NDK へのパスはデフォルトで ANDROID_NDK_HOME
環境変数から推測されます。パスは、android_ndk_repository
の path
属性で明示的に指定することもできます。
詳細については、Bazel を使用した Android Native Development Kit の使用をご覧ください。
api_level
は、SDK と NDK がターゲットとする Android API のバージョンです(Android 6.0 の場合は 23、Android 7.1 の場合は 25 など)。明示的に設定されていない場合、api_level
はデフォルトで android_sdk_repository
と android_ndk_repository
で使用可能な最高の API レベルになります。
SDK と NDK で API レベルを同じ値に設定する必要はありません。このページには、Android リリースから NDK 対応 API レベルへのマップが掲載されています。
BUILD ファイルを作成する
BUILD
ファイルは、一連のビルド出力(aapt
のコンパイル済み Android リソースや javac
のクラスファイルなど)とその依存関係の関係を記述します。これらの依存関係は、ワークスペース内のソースファイル(Java、C++)やその他のビルド出力です。BUILD
ファイルは Starlark という言語で記述されています。
BUILD
ファイルは、Bazel のパッケージ階層というコンセプトの一部です。パッケージ階層は、ワークスペースのディレクトリ構造をオーバーレイする論理構造です。各パッケージは、関連するソースファイルのセトと BUILD
ファイルを含むディレクトリ(およびそのサブディレクトリ)です。パッケージには、独自の BUILD
ファイルを含むサブディレクトリを除く、すべてのサブディレクトリも含まれます。パッケージ名は、WORKSPACE
を基準とした BUILD
ファイルのパスです。
Bazel のパッケージ階層は、BUILD
ファイルが配置されている Android アプリ ディレクトリの Java パッケージ階層と概念的に異なりますが、ディレクトリは同じ構造になっている場合があります。
このチュートリアルのシンプルな Android アプリの場合、src/main/
のソースファイルは単一の Bazel パッケージで構成されます。より複雑なプロジェクトには、ネストされたパッケージが多数存在する場合があります。
android_library ルールを追加する
BUILD
ファイルには、Bazel のさまざまなタイプの宣言が含まれています。最も重要なタイプはビルドルールで、ソースファイルのセットやその他の依存関係から中間または最終的なソフトウェア出力をビルドする方法を Bazel に指示します。Bazel には、Android アプリのビルドに使用できる 2 つのビルドルール(android_library
と android_binary
)が用意されています。
このチュートリアルでは、まず android_library
ルールを使用して、アプリのソースコードとリソース ファイルから Android ライブラリ モジュールをビルドするよう Bazel に指示します。次に、android_binary
ルールを使用して、Android アプリ パッケージのビルド方法を Bazel に指示します。
src/main/java/com/example/bazel
ディレクトリに新しい BUILD
ファイルを作成し、新しい android_library
ターゲットを宣言します。
src/main/java/com/example/bazel/BUILD
:
package(
default_visibility = ["//src:__subpackages__"],
)
android_library(
name = "greeter_activity",
srcs = [
"Greeter.java",
"MainActivity.java",
],
manifest = "AndroidManifest.xml",
resource_files = glob(["res/**"]),
)
android_library
ビルドルールには、Bazel がソースファイルからライブラリ モジュールをビルドするために必要な情報を指定する一連の属性が含まれています。また、ルールの名前は greeter_activity
です。この名前は、android_binary
ルールの依存関係としてルールを参照するために使用します。
android_binary ルールを追加する
android_binary
ルールは、アプリの Android アプリ パッケージ(.apk
ファイル)をビルドします。
src/main/
ディレクトリに新しい BUILD
ファイルを作成し、新しい android_binary
ターゲットを宣言します。
src/main/BUILD
:
android_binary(
name = "app",
manifest = "AndroidManifest.xml",
deps = ["//src/main/java/com/example/bazel:greeter_activity"],
)
ここで、deps
属性は、上記の BUILD
ファイルに追加した greeter_activity
ルールの出力を参照します。つまり、Bazel がこのルールの出力をビルドするときに、まず greeter_activity
ライブラリ ルールの出力がビルドされ、最新の状態であるかどうかを確認します。存在しない場合は、Bazel がビルドし、その出力を使用してアプリケーション パッケージ ファイルをビルドします。
ファイルを保存して閉じます。
アプリをビルドする
アプリをビルドしてみてください。次のコマンドを実行して、android_binary
ターゲットをビルドします。
bazel build //src/main:app
build
サブコマンドは、続くターゲットをビルドするように Bazel に指示します。ターゲットは、BUILD
ファイル内のビルドルールの名前として、ワークスペース ディレクトリに対するパッケージパスとともに指定します。この例では、ターゲットは app
、パッケージパスは //src/main/
です。
コマンドラインでの現在の作業ディレクトリとターゲットの名前によっては、パッケージパスまたはターゲット名を省略できる場合があります。ターゲット ラベルとパスの詳細については、ラベルをご覧ください。
Bazel がサンプルアプリのビルドを開始します。ビルドプロセス中、出力は次のようになります。
INFO: Analysed target //src/main:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src/main:app up-to-date:
bazel-bin/src/main/app_deploy.jar
bazel-bin/src/main/app_unsigned.apk
bazel-bin/src/main/app.apk
ビルド出力を見つける
Bazel は、中間ビルド オペレーションと最終ビルド オペレーションの両方の結果を、ユーザーごと、ワークスペースごとの出力ディレクトリのセットに格納します。これらのディレクトリは、プロジェクト ディレクトリの最上位にある次の場所からシンボリック リンクされています。ここで、WORKSPACE
は次のとおりです。
bazel-bin
: バイナリ実行可能ファイルとその他の実行可能なビルド出力を保存します。bazel-genfiles
には、Bazel ルールによって生成された中間ソースファイルが保存されます。bazel-out
は、他のタイプのビルド出力を格納します。
Bazel は、android_binary
ルールを使用して生成された Android .apk
ファイルを bazel-bin/src/main
ディレクトリに保存します。サブディレクトリ名 src/main
は Bazel パッケージの名前から派生しています。
コマンド プロンプトで、このディレクトリの内容を一覧表示して、app.apk
ファイルを探します。
OS | コマンド |
---|---|
Linux、macOS | ls bazel-bin/src/main |
Windows(コマンド プロンプト) | dir bazel-bin\src\main |
Windows(PowerShell) | ls bazel-bin\src\main |
アプリを実行する
これで、bazel
mobile-install
コマンドを使用して、コマンドラインから接続された Android デバイスまたはエミュレータにアプリをデプロイできるようになりました。このコマンドは、Android Debug Bridge(adb
)を使用してデバイスと通信します。デプロイ前に、Android Debug Bridge の手順に沿って、adb
を使用するようにデバイスをセットアップする必要があります。Android Studio に組み込まれている Android Emulator にアプリをインストールすることもできます。次のコマンドを実行する前に、エミュレータが実行されていることを確認します。
次の情報を入力します。
bazel mobile-install //src/main:app
次に、「Bazel チュートリアル アプリ」を探して起動します。
図 2. Bazel チュートリアル アプリ。
これで、これで、Bazel でビルドされた最初の Android アプリをインストールしました。
mobile-install
サブコマンドは --incremental
フラグもサポートしています。このフラグを使用すると、前回デプロイしてから変更されたアプリの部分のみをデプロイできます。
また、インストール時にアプリをすぐに起動するための --start_app
フラグもサポートしています。
関連情報
詳しくは、次のページをご覧ください。
- GitHub で問題を報告する
- mobile-install の詳細
- rules_jvm_external を使用して、Maven リポジトリから AppCompat、Guava、JUnit などの外部依存関係を統合する
- robolectric-bazel 統合を使用して Robolectric テストを実行します。
- Android インストルメンテーション テストでアプリをテストする
- NDK を使用して C コードと C++ コードを Android アプリに統合する
- 次の Bazel サンプル プロジェクトをご覧ください。
ぜひ活用してみてください。