Bazel チュートリアル: Android アプリを作成する

問題を報告する ソースを表示

注: Bazel を使用して Android アプリをビルドする場合、既知の制限事項があります。GitHub の team-Android ホットリストにアクセスして、既知の問題の一覧を確認する。Bazel チームとオープンソース ソフトウェア(OSS)コントリビューターは既知の問題に対処するために積極的に取り組んでいますが、Android Studio では Bazel プロジェクトが正式にサポートされないことにご注意ください。

このチュートリアルでは、Bazel を使用してシンプルな Android アプリを作成する方法について説明します。

Bazel は、Android ルールを使用した Android アプリのビルドをサポートしています。

このチュートリアルは、Windows、macOS、Linux ユーザーを対象としており、Bazel または Android アプリの開発の経験は必要ありません。このチュートリアルでは、Android コードを記述する必要はありません。

学習内容

このチュートリアルでは、次の方法を学習します。

  • Bazel と Android Studio をインストールし、サンプル プロジェクトをダウンロードして、環境をセットアップします。
  • アプリのソースコードと、ワークスペース ディレクトリのトップレベルを識別する WORKSPACE ファイルを含む Bazel ワークスペースを設定します。
  • WORKSPACE ファイルを更新し、Android SDK など、必要な外部依存関係への参照を含めます。
  • BUILD ファイルを作成します。
  • Bazel でアプリをビルドする
  • Android Emulator または実機にアプリをデプロイし、実行します。

始める前に

Bazel をインストールする

チュートリアルを開始する前に、次のソフトウェアをインストールします。

  • Bazelインストール手順に沿ってインストールします。
  • Android Studioインストールする手順は次のとおりです。Android Studio をダウンロードする設定ウィザードを実行して SDK をダウンロードし、環境を設定します。
  • (省略可)Gitgit を使用して 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.xmlsrc/main/java/com/example/bazel/AndroidManifest.xml
Android ソースファイル src/main/java/com/example/bazel/MainActivity.javaGreeter.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)

pathapi_levelbuild_tools_version の各属性を指定して、Android SDK の絶対パス、API レベル、使用するビルドツールのバージョンを明示的に指定することもできます。api_levelbuild_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_repositorypath 属性を使用して明示的に指定することもできます。

詳しくは、Bazel で Android ネイティブ開発キットを使用するをご覧ください。

api_level は、SDK と NDK のターゲットとなる Android API のバージョンです。たとえば、Android 6.0 の場合は 23、Android 7.1 の場合は 25 です。明示的に設定しないと、api_level はデフォルトで android_sdk_repositoryandroid_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 App Directory の Java パッケージ階層とは概念が異なりますが、ディレクトリはまったく同じように編成できます。

このチュートリアルのシンプルな Android アプリの場合、src/main/ 内のソースファイルは 1 つの Bazel パッケージで構成されています。複雑なプロジェクトにはネストされたパッケージが多数含まれる場合があります。

android_library ルールを追加

BUILD ファイルには、Bazel の宣言のさまざまなタイプが含まれています。最も重要なタイプはビルドルールです。このルールは、ソースファイルやその他の依存関係から中間または最終的なソフトウェア出力をビルドする方法を Bazel に指示します。Bazel には、android_libraryandroid_binary の 2 つのビルドルールがあり、Android アプリの作成に使用できます。

このチュートリアルでは、まず 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 チュートリアル アプリ」を見つけて起動します。

Bazel チュートリアル アプリ

図 2. Bazel チュートリアル アプリ

おめでとうございます!これで、Bazel でビルドした最初の Android アプリをインストールできました。

mobile-install サブコマンドは、前回のデプロイ以降に変更されたアプリの部分のみをデプロイするために使用できる --incremental フラグもサポートしています。

また、インストール後すぐにアプリを開始するための --start_app フラグもサポートしています。

参考資料

詳しくは、以下のページをご覧ください。

今後ともよろしくお願いいたします。