bazel モバイル インストール

問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Android 向けの迅速なイテレーション開発

このページでは、bazel mobile-install で反復型開発がどのように行われるかについて説明します。 大幅に向上させることができます従来のデータウェアハウスとの違いについて 課題に対処できます。

概要

Android アプリの小さな変更を非常にすばやくインストールする手順は次のとおりです。

  1. インストールするアプリの android_binary ルールを見つけます。
  2. proguard_specs 属性を削除して、ProGuard を無効にします。
  3. multidex 属性を native に設定します。
  4. dex_shards 属性を 10 に設定します。
  5. (Dalvik ではなく)ART を実行するデバイスを USB 経由で接続し、USB を有効にします 表示されます。
  6. bazel mobile-install :your_target を実行します。アプリの起動に少し時間がかかる 通常より遅いです。
  7. コードまたは Android リソースを編集します。
  8. bazel mobile-install --incremental :your_target を実行します。
  9. 待ち時間が短くなるのを楽しみましょう。

役立つ可能性のある Bazel のコマンドライン オプションは次のとおりです。

  • --adb は、どの adb バイナリを使用するかを Bazel に指示します
  • --adb_arg を使用すると、adb のコマンドラインに引数を追加できます。 インストールするデバイスを選択できるので便利です。 ワークステーションに複数のデバイスを接続している場合は、次のようにします。 bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app が自動的にアプリを起動します

疑わしい場合は、 またはお問い合わせください。

はじめに

開発者のツールチェーンの最も重要な属性の一つは速度です。 コードを変更することとそれを実際に実行することと フィードバックを受け取るまでに数分から数時間かかる 期待どおりの結果が得られるかどうかを 確認します

残念ながら、.apk をビルドするための従来の Android ツールチェーンでは、 モノリシックなシーケンシャルなステップが多数あります Android アプリを作成します。Google では、5 分待ってからシングル ラインの接続を Google マップのような大規模なプロジェクトでは珍しくありませんでした。

bazel mobile-install により、Android の反復型開発が大幅に高速化されます。 変更のプルーニング、作業のシャーディング、巧妙な操作を組み合わせて、 Android の内部。アプリのコードを変更する必要はありません。

従来のアプリのインストールに関する問題

Android アプリのビルドには、次のような問題があります。

  • dex 変換。デフォルトでは「dx」ビルドで 1 回だけ呼び出されるため、 以前のビルドの処理を再利用する方法を知っておくこと。すべてのメソッドに対して再度 dex 変換を行います。 ただし、メソッドは 1 つのみ変更されています。

  • デバイスにデータをアップロードしています。adb は USB 2.0 の帯域幅をすべて使用しません。 アップロードに時間がかかります。アプリ全体が 小さな部分のみが変更された場合でも、たとえば、リソースや 単一のメソッドであるため、これが大きなボトルネックになる可能性があります。

  • ネイティブ コードのコンパイル。Android L では、新しい Android ランタイムである ART が導入されました。 これは、アプリをジャストインタイムでコンパイルするのではなく、事前にコンパイルします。 Dalvik。これにより、インストールには時間がかかりますが、アプリの速度が大幅に向上します あります。ユーザーはアプリをインストールすることが多いため、これは良いトレードオフになります。 何度でも再利用できますが、開発に時間がかかり、 インストールされ、各バージョンの実行回数は多くても数回程度です。

bazel mobile-install のアプローチ

bazel mobile-install により、次の改善が行われます。

  • シャーディングされた dex 変換。アプリの Java コードをビルドした後、Bazel でクラスをシャーディング ファイルをほぼ同じサイズに分割し、実行時に個別に dx を呼び出します。 できます。前回のビルド以降に変更されていないシャードで、dx が呼び出されない。

  • 増分ファイル転送。Android リソース、.dex ファイル、ネイティブ ライブラリはメインの .apk から削除され、別の インストールする必要があります。これにより、コードや Android の アプリ全体を再インストールする必要はありません。したがって、次のようになります。 転送にかかる時間は短くなり、アップロード済みの .dex ファイルだけが デバイス上で再コンパイルされます。

  • .apk の外部からアプリの一部を読み込む。小さなスタブ アプリケーションは、 Android リソース、Java コード、ネイティブ コードを読み込む .apk に挿入する デバイス上のモバイル インストール ディレクトリからダウンロードし、コントロールを 使用します。ごくまれなケースを除き、すべてアプリに対して透過的である 以下で説明します。

シャーディングされた dex 変換

シャーディングされた dex 変換は比較的簡単です。.jar ファイルがビルドされると、 ツール ほぼ同じサイズの個別の .jar ファイルにシャーディングしてから、 前回のビルド以降に変更されたオブジェクトに対する dx。このロジックは、 dex 変換するシャードが Android に固有のものではなく、 Bazel の一般的な変更プルーニング アルゴリズム。

シャーディング アルゴリズムの最初のバージョンでは、単純に .class ファイルを単純に リストを同じサイズに分割しましたが、 次善の策: クラスが追加または削除された場合(ネストされた、 すべてのクラスがアルファベット順で 1 つずつ移動し、 その結果、シャードに再度 dex 変換が行われます。そのため、Java をシャーディングすることにしました。 パッケージ化されています。もちろんこの方法でも 新しいパッケージが追加または削除されたときに多くのシャードに dex 変換を行う 頻繁な操作を避けることができます。

シャードの数は BUILD ファイル( android_binary.dex_shards 属性など)。Bazel は、理想的な環境であれば、 最適なシャードの数を自動的に決定しますが、Bazel は現在、 たとえば、ビルド中に実行するコマンドなど)を、 実行されないため、最適なシャード数を決定できません。 最終的に検索される Java クラスが 。一般的に、シャードの数が多いほどビルドが速くなり、 インストールには影響がありますが、動的パラメータによって、アプリの起動が遅くなります。 リンカーの作業量が増えますスイート スポットは通常 10 ~ 50 のシャードです。

増分ファイル転送

アプリをビルドしたら、次のステップとして、できれば 必要最小限の労力で済みますインストールは以下の手順で構成されます。

  1. .apk のインストール(通常は adb install を使用)
  2. .dex ファイル、Android リソース、ネイティブ ライブラリを モバイル インストール ディレクトリ

最初のステップでは、インクリメンタリティはあまりありません。つまり、 判断できます現在、Bazel は、このステップを行う必要があるかどうかの判断をユーザーに依存しています --incremental コマンドライン オプションを使用する。これは、 すべてのケースに対応します

第 2 ステップでは、ビルドに含まれるアプリのファイルがデバイス上のファイルと比較されます。 デバイス上にあるアプリファイルとそのファイルをリストしたマニフェスト ファイル チェックサムがあります新しいファイル、変更されたファイルはすべてデバイスにアップロードされます ファイルは更新され、削除されたファイルは ダウンロードしますマニフェストが存在しない場合、すべてのファイルに 指定できます。

増分インストールのアルゴリズムは、 マニフェストではチェックサムではなく、デバイス上のファイルを変更できます。この場合、 コンピュータ上のファイルのチェックサムを計算して、 しかし、これはインストール時間の増加に見合わないと判断されました。

Stub アプリケーション

スタブ アプリケーションでは、dex、ネイティブ コード、 デバイス上の mobile-install ディレクトリにある Android リソースが発生する。

実際の読み込みは、BaseDexClassLoader をサブクラス化することで実装されます。 手法を使用します。この処理は、アプリケーションの クラスが読み込まれて、APK 内にあるすべてのアプリ クラスが 更新できるように、デバイス上の mobile-install ディレクトリに配置する (adb install なし)。

この処理は アプリケーションのクラスが読み込まれるので、アプリケーション クラスを .apk があります。この場合、これらのクラスに変更を加えるには、 再インストールします。

これは、環境変数で指定された Application クラスを AndroidManifest.xml を、 スタブ アプリケーション。この アプリが起動されるタイミングを制御し、クラスローダーと リソース マネージャー(コンストラクタ)に、 Android フレームワーク内部の Java リフレクション。

スタブアプリケーションは、ネイティブ ライブラリのコピーを 別の場所にモバイル インストールすることによってインストールできます。この操作が必要なのは、 ダイナミック リンカーはファイルに対して X ビットを設定する必要がありますが、 root 以外の adb がアクセスできるすべてのロケーションに対して実行します。

これらすべての処理が完了すると、スタブ アプリケーションは 実際のApplicationクラスを指定し、それ自体へのすべての参照を実際の 実装する必要があります。

結果

パフォーマンス

一般に、bazel mobile-install を使用すると、ビルドが 4 ~ 10 倍高速化されます。 小さな変更の後に大きなアプリをインストールします

以下の数値は、いくつかの Google サービスで計算されています。

もちろん、これは変更の性質によって異なります。つまり、構成後の再コンパイルは ベース ライブラリの変更には時間がかかります。

制限事項

スタブ アプリケーションの手法は、すべてのケースで機能するとは限りません。 次のようなケースでは、想定どおりに機能しない場合があります。

  • ContextApplication クラスにキャストされると、 ContentProvider#onCreate()。このメソッドは、アプリケーション Application のインスタンスを置き換える前に起動を行います。 そのため、ContentProvider は引き続きスタブアプリを参照します。 表示されます。おそらく、これはバグではありません。 このような Context をダウンキャストすることになっていますが、これはごくわずかな時間で起こるようです 紹介しています

  • bazel mobile-install がインストールしたリソースは、次の内部からのみ使用できます クリックします。リソースに他のアプリが PackageManager#getApplicationResources() の場合、これらのリソースは 最後の非増分インストールです

  • ART が実行されていないデバイス。スタブ アプリケーションは Froyo 以降の Dalvik には、 特定の環境において、そのコードが複数の .dex ファイルに分散されている場合、正しくない たとえば、Java アノテーションが API で使用されている場合、 特定 できます。アプリはこれらのバグをくっつけない限り、Dalvik、 (ただし、古い Android バージョンのサポートは、Google の フォーカス)