BazelCon 2022 findet vom 16. bis 17. November in New York und online statt.
Jetzt anmelden

Installation von Mobile Mobile

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Schnelle iterative Entwicklung für Android

Auf dieser Seite wird beschrieben, wie bazel mobile-install die iterative Entwicklung für Android erheblich beschleunigt. Darin werden die Vorteile dieses Ansatzes im Vergleich zu den Herausforderungen der herkömmlichen App-Installationsmethode beschrieben.

Fazit

So installieren Sie kleine Änderungen an einer Android-App sehr schnell:

  1. Suchen Sie die android_binary-Regel der App, die Sie installieren möchten.
  2. Deaktivieren Sie Proguard, indem Sie das Attribut proguard_specs entfernen.
  3. Legen Sie das multidex-Attribut auf „native“ fest.
  4. Legen Sie das dex_shards-Attribut auf „10“ fest.
  5. Verbinden Sie Ihr Gerät mit ART (nicht Dalvik) über USB und aktivieren Sie USB-Debugging darüber.
  6. Führen Sie bazel mobile-install :your_target aus. Das Starten von Apps ist etwas langsamer als gewöhnlich.
  7. Bearbeiten Sie den Code oder die Android-Ressourcen.
  8. Führen Sie bazel mobile-install --incremental :your_target aus.
  9. haben Sie viel Zeit.

Mögliche Befehlszeilenoptionen für Istio, die hilfreich sein können:

  • --adb gibt für ermitteln, welches ADB-Binärprogramm verwendet werden soll
  • Mit --adb_arg können der Befehlszeile von adb zusätzliche Argumente hinzugefügt werden. Du kannst z. B. auswählen, auf welchem Gerät du die App installieren möchtest, wenn mehrere Geräte mit deiner Workstation verbunden sind: bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app startet die App automatisch

Sehen Sie sich im Zweifelsfall das Beispiel an oder wenden Sie sich an uns.

Einführung

Eines der wichtigsten Attribute einer Toolchain für Entwickler ist die Geschwindigkeit: Es gibt einen großen Unterschied zwischen dem Ändern des Codes und dem Aufrufen innerhalb einer Sekunde. Außerdem müssen Sie Minuten, manchmal Stunden, bevor Sie Feedback darüber erhalten, ob Ihre Änderungen Ihren Erwartungen entsprechen, erfüllen.

Die herkömmliche Android-Toolkit zum Erstellen einer APK-Datei umfasst leider viele monolithische, sequenzielle Schritte. Alle diese Schritte müssen beim Erstellen einer Android-App erledigt werden.

bazel mobile-install beschleunigt die iterative Entwicklung von Android durch eine Kombination von Änderungsschnitten, Fragmentierung von Arbeitsdaten und cleverer Bearbeitung von Android-Intern, ohne dabei den Code deiner App zu ändern.

Probleme bei der Installation von traditionellen Apps

Beim Erstellen einer Android-App gibt es einige Punkte, darunter:

  • Dexing Standardmäßig wird &dt

  • Daten werden auf das Gerät hochgeladen. ADB verwendet nicht die volle Bandbreite einer USB 2.0-Verbindung. Größere Anwendungen können jedoch sehr lange dauern. Die gesamte Anwendung wird hochgeladen, selbst wenn sich nur kleine Teile geändert haben, z. B. eine Ressource oder eine einzelne Methode. Dies kann ein großer Engpass sein.

  • Kompilierung des nativen Codes. Android L hat ART eingeführt, eine neue Android-Laufzeit, die Apps vorab kompiliert, anstatt sie in Echtzeit zusammenzustellen. Das führt zu einer deutlich schnelleren Installation von Apps. Das ist ein guter Kompromiss für Nutzer, da sie eine App in der Regel einmal installieren und häufig verwenden. Allerdings wird die Entwicklung dann langsamer, wenn eine App mehrmals installiert und jede Version nur sehr selten ausgeführt wird.

Der Ansatz von bazel mobile-install

bazel mobile-installnimmt folgende Verbesserungen vor:

  • Shards dexing Nachdem der Java-Code der Anwendung erstellt wurde, teilt Yahoo die Kursdateien in ungefähr gleich große Teile auf und ruft dx separat auf ihnen auf. dx wird nicht für Shards aufgerufen, die sich seit dem letzten Build nicht geändert haben.

  • Inkrementelle Dateiübertragung. Android-Ressourcen, DEX-Dateien und native Bibliotheken werden aus der Haupt-APK entfernt und in einem separaten Verzeichnis für die mobile Installation gespeichert. So können Sie Code und Android-Ressourcen unabhängig aktualisieren, ohne die gesamte App neu installieren zu müssen. Die Übertragung der Dateien dauert dadurch weniger Zeit und die DEX-Dateien werden nur auf dem Gerät neu kompiliert.

  • Teile der App werden außerhalb der APK-Datei geladen. Dafür wird eine kleine Stub-Anwendung in die APK-Datei eingefügt, die Android-Ressourcen, Java-Code und nativen Code aus dem auf dem Gerät installierten Installationsverzeichnis für Mobilgeräte lädt und die Kontrolle an die eigentliche App überträgt. Lediglich einige wenige E-Mail-Fälle sind unten beschrieben.

Fragmentiertes Dexing

Shard-Dexing ist relativ einfach: Sobald die JAR-Dateien erstellt wurden, werden sie von einem Tool in separate JAR-Dateien von ungefähr gleicher Größe fragmentiert. Dann wird dx für die Dateien aufgerufen, die seit dem vorherigen Build geändert wurden. Die Logik, die bestimmt, welche Shards spezifisch sind, ist nicht spezifisch für Android: Sie verwendet lediglich den allgemeinen Pruning-Algorithmus für die Änderung von Änderungen.

In der ersten Version des Fragmentierungsalgorithmus wurden die KLASS-Dateien einfach alphabetisch sortiert und dann in mehrere Teile unterteilt, die sich jedoch als unoptimal erweisen: Wenn eine Klasse hinzugefügt oder entfernt wurde (auch eine verschachtelte oder anonyme), würde es dazu führen, dass alle Klassen alphabetisch um eine nach dem anderen verschoben werden, sodass diese Shards noch einmal entschlüsselt werden. Daher wurde beschlossen, Java-Pakete statt einzelne Klassen zu fragmentieren. Dies führt natürlich immer noch dazu, dass viele Shards entfernt werden, wenn ein neues Paket hinzugefügt oder entfernt wird. Dies ist jedoch weniger häufig als das Hinzufügen oder Entfernen einer einzelnen Klasse.

Die Anzahl der Shards wird durch die BUILD-Datei (mit dem Attribut android_binary.dex_shards) gesteuert. In einer Idealwelt würde Istio automatisch bestimmen, wie viele Shards am besten sind. Jedoch muss {5/} derzeit die Reihe von Aktionen (z. B. Befehle, die während des Builds ausgeführt werden) vor der Ausführung einer der Shards kennen, daher kann sie nicht die optimale Anzahl von Shards ermitteln, da sie nicht weiß, wie viele Java-Klassen irgendwann in der App vorhanden sein werden. Je größer es ist, desto dynamischer wird er. Der Süße liegt in der Regel zwischen 10 und 50 Shards.

Inkrementelle Dateiübertragung

Nach dem Erstellen der App müssen Sie sie im nächsten Schritt installieren, am besten mit dem niedrigsten Aufwand. Die Installation besteht aus den folgenden Schritten:

  1. Installation der APK-Datei (normalerweise mit adb install)
  2. Hochladen von DEX-Dateien, Android-Ressourcen und nativen Bibliotheken in das Verzeichnis für die mobile Installation

Im ersten Schritt gibt es nur wenige inkrementelle Schritte: Die Anwendung ist entweder installiert oder nicht. Bei {5/} ist der Nutzer derzeit darauf angewiesen, ob dieser Schritt über die Befehlszeilenoption --incremental ausgeführt werden soll, da dies nicht in allen Fällen festgestellt werden kann.

Im zweiten Schritt werden die App-Dateien aus dem Build mit einer Manifestdatei auf dem Gerät verglichen. Dort sind die App-Dateien und ihre Prüfsummen aufgeführt. Alle neuen Dateien werden auf das Gerät hochgeladen, alle geänderten Dateien und alle entfernten Dateien werden vom Gerät gelöscht. Wenn das Manifest nicht vorhanden ist, wird angenommen, dass jede Datei hochgeladen werden muss.

Beachten Sie, dass Sie den Algorithmus für die inkrementelle Installation irreführend machen können, indem Sie eine Datei auf dem Gerät ändern, aber nicht deren Prüfsumme im Manifest. Dies kann durch die Berechnung der Prüfsumme der Dateien auf dem Gerät abgefangen werden. Aber es wurde nicht angenommen, dass sich die Installationsdauer lohnen würde.

Stub-Anwendung

In der Stub-Anwendung werden die Dexes, der native Code und die Android-Ressourcen aus dem Verzeichnis mobile-install auf dem Gerät geladen.

Der tatsächliche Ladevorgang wird durch das Erstellen von Unterklassen von BaseDexClassLoader implementiert und ist ein relativ gut dokumentiertes Verfahren. Das geschieht, bevor alle Klassen der Anwendung geladen werden, sodass alle in der APK-Datei enthaltenen Anwendungsklassen in dem Verzeichnis mobile-install auf dem Gerät abgelegt werden können, sodass sie ohne adb install aktualisiert werden können.

Dies muss geschehen, bevor alle Klassen der Anwendung geladen werden. Es muss also keine Anwendungsklasse in der APK-Datei vorhanden sein. Änderungen an diesen Klassen müssen daher vollständig neu installiert werden.

Dazu wird die in AndroidManifest.xml angegebene Klasse Application durch die Stub-Anwendung ersetzt. Dies übernimmt die Kontrolle, wenn die App gestartet wird, und passt den Classloader und den Ressourcenmanager so früh wie möglich (seinen Konstruktor) entsprechend an. Dazu wird Java in den Innenräumen des Android-Frameworks verwendet.

Eine andere Sache bei der Stub-Anwendung besteht darin, die durch die mobile Installation installierten nativen Bibliotheken an einen anderen Speicherort zu kopieren. Das ist erforderlich, weil für die dynamische Verknüpfung das Element X für die Dateien festgelegt werden muss. Dies ist nicht an einem Standort möglich, der nicht über eine Stamm-adb zugänglich ist.

Sobald alle diese Schritte abgeschlossen sind, instanziiert die Stub-Anwendung anschließend die tatsächliche Application-Klasse und ändert dabei alle Verweise auf sich selbst im Android-Framework.

Ergebnisse

Leistung

Im Allgemeinen führt bazel mobile-install zu einer 4- bis 10-fachen Geschwindigkeit beim Erstellen und Installieren großer Anwendungen nach einer kleinen Änderung.

Für einige Google-Produkte wurden die folgenden Werte berechnet:

Dies hängt natürlich von der Art der Änderung ab: Die Kompilierung, nachdem die Basisbibliothek geändert wurde, dauert länger.

Beschränkungen

Die Tricks, die die Stub-Anwendung spielt, funktionieren nicht in jedem Fall. In den folgenden Fällen ist die erwartungsgemäße Funktion hervorgehoben:

  • Wenn Context in die Klasse Application umgewandelt wird, in ContentProvider#onCreate(). Diese Methode wird beim Starten der Anwendung aufgerufen, bevor wir die Instanz der Klasse Application ersetzen können. Daher verweist ContentProvider weiterhin auf die Stub-Anwendung und nicht auf die echte Anwendung. Dies ist natürlich kein Programmfehler, da Sie Context nicht wie gewünscht ausgliedern sollten, was aber in einigen Apps von Google vorkommt.

  • Von bazel mobile-install installierte Ressourcen sind nur in der Anwendung verfügbar. Wenn Ressourcen von PackageManager#getApplicationResources() über andere Apps auf Ressourcen zugreifen, stammen diese aus der letzten nicht inkrementellen Installation.

  • Geräte, auf denen ART nicht ausgeführt wird Die Stub-Anwendung funktioniert zwar gut an Froyo und später, aber es gibt einen Fehler, der den Eindruck vermittelt, dass die Anwendung in bestimmten Fällen falsch ist, wenn der Code auf mehrere DEX-Dateien verteilt wird, z. B. wenn Java-Annotationen speziell verwendet werden. Solange Ihre App diese Fehler kitzelt, sollte sie auch mit Dalvik funktionieren. Beachte aber, dass alte Android-Versionen nicht von uns unterstützt werden.