Bau eines Android-Projekts in einem Docker-Container

Bei der Entwicklung eines Projekts für die Android-Plattform, selbst wenn es nur klein ist, muss man früher oder später mit der Entwicklungsumgebung konfrontiert werden. Neben dem Android SDK ist es notwendig, die neueste Version von Kotlin, Gradle, platform-tools und build-tools zu haben. Während auf dem System des Entwicklers all diese Abhängigkeiten größtenteils mit Hilfe der Android Studio IDE gelöst werden, kann jedes Update auf dem CI/CD-Server Kopfschmerzen bereiten. Wenn in der Webentwicklung Docker zum Standardwerkzeug für das Umgebungsproblem geworden ist, warum also nicht versuchen, ein ähnliches Problem auch in der Android-Entwicklung damit zu lösen...

Für alle, die nicht wissen, was Docker ist – einfach ausgedrückt, es ist ein Tool zur Erstellung sogenannter „Container“, die einen minimalen Kern des Betriebssystems und eine notwendige Softwareauswahl enthalten, die wir überall bereitstellen können, während wir die Umgebung beibehalten. Was genau in unserem Container enthalten sein wird, wird im Dockerfile festgelegt, das dann in ein Image gebaut wird, das überall ausgeführt werden kann und Eigenschaften der Idempotenz besitzt.

Der Installationsprozess und die Grundlagen von Docker sind hervorragend auf seiner der offiziellen Websitedokumentiert. Daher, um etwas vorzugreifen, hier ist das Dockerfile, das wir erstellt haben

# Т.к. основным инструментом для сборки Android-проектов является Gradle, 
# и по счастливому стечению обстоятельств есть официальный Docker-образ 
# мы решили за основу взять именно его с нужной нам версией Gradle
FROM gradle:5.4.1-jdk8

# Задаем переменные с локальной папкой для Android SDK и 
# версиями платформы и инструментария
ENV SDK_URL="https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip" 
    ANDROID_HOME="/usr/local/android-sdk" 
    ANDROID_VERSION=28 
    ANDROID_BUILD_TOOLS_VERSION=28.0.3

# Создаем папку, скачиваем туда SDK и распаковываем архив,
# который после сборки удаляем
RUN mkdir "$ANDROID_HOME" .android 
    && cd "$ANDROID_HOME" 
    && curl -o sdk.zip $SDK_URL 
    && unzip sdk.zip 
    && rm sdk.zip 
# В следующих строчках мы создаем папку и текстовые файлы 
# с лицензиями. На оф. сайте Android написано что мы 
# можем копировать эти файлы с машин где вручную эти 
# лицензии подтвердили и что автоматически 
# их сгенерировать нельзя
    && mkdir "$ANDROID_HOME/licenses" || true 
    && echo "24333f8a63b6825ea9c5514f83c2829b004d1" > "$ANDROID_HOME/licenses/android-sdk-license" 
    && echo "84831b9409646a918e30573bab4c9c91346d8" > "$ANDROID_HOME/licenses/android-sdk-preview-license"    

# Запускаем обновление SDK и установку build-tools, platform-tools
RUN $ANDROID_HOME/tools/bin/sdkmanager --update
RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" 
    "platforms;android-${ANDROID_VERSION}" 
    "platform-tools"

Wir speichern es im Ordner unseres Android-Projekts und starten den Container-Bau mit dem Befehl

docker build -t android-build:5.4-28-27 .

Parameter -t legt das Tag oder den Namen unseres Containers fest, der normalerweise aus seinem Namen und seiner Version besteht. In unserem Fall haben wir ihn android-build genannt und in der Version eine Kombination aus den Versionen von Gradle, Android-SDK und platform-tools angegeben. In Zukunft wird es einfacher sein, das benötigte Image nach Namen zu suchen, indem wir eine solche „Version“ verwenden.

Nachdem der Build abgeschlossen ist, können wir unser Image lokal verwenden; wir können es mit dem Befehl docker push in ein öffentliches oder privates Repository für Images hochladen, um es auf andere Maschinen herunterzuladen.

Als Beispiel bauen wir das Projekt lokal. Dazu führen wir im Ordner des Projekts den Befehl aus

docker run --rm -v "$PWD":/home/gradle/ -w /home/gradle android-build:5.4.1-28-27 gradle assembleDebug

Lass uns auseinandernehmen, was er bedeutet:

docker run — der Befehl zum Starten des Images selbst
-rm — bedeutet, dass nach dem Stoppen des Containers alles, was während seiner Lebensdauer erstellt wurde, gelöscht wird
-v "$PWD":/home/gradle/ — montiert den aktuellen Ordner mit unserem Android-Projekt in den internen Ordner des Containers /home/gradle/
-w /home/gradle — legt das Arbeitsverzeichnis des Containers fest
android-build:5.4.1-28-27 — der Name unseres Containers, den wir gebaut haben
gradle assembleDebug — das eigentliche Build-Team, das unser Projekt zusammenstellt

Wenn alles gut geht, werden Sie in ein paar Sekunden/Minuten etwas sehen, das ungefähr so aussieht BUILD SUCCESSFUL in 8m 3s! Im Verzeichnis app/build/output/apk liegt die erstellte Anwendung.

In ähnlicher Weise können Sie andere Gradle-Aufgaben ausführen – das Projekt überprüfen, Tests starten usw. Der Hauptvorteil ist, dass wir uns bei Bedarf um die Erstellung des Projekts auf einer beliebigen anderen Maschine nicht kümmern müssen. Es reicht aus, das erforderliche Image herunterzuladen und den Build darin zu starten.

Der Container speichert keine Änderungen, und jede Erstellung beginnt von Null. Das garantiert einerseits die Identität des Builds, unabhängig davon, wo er gestartet wird. Andererseits müssen wir jedes Mal alle Abhängigkeiten herunterladen und den gesamten Code neu kompilieren, was manchmal erheblich Zeit in Anspruch nehmen kann. Daher gibt es neben dem normalen "kalten" Start eine Option, den Build mit der sogenannten "Cache"-Speicherung zu starten, bei der wir den Ordner ~/.gradle einfach in den Arbeitsordner des Projekts kopieren und zu Beginn des nächsten Builds zurückgeben. Alle Kopierprozesse haben wir in separate Skripte ausgelagert, und der Befehl zum Starten sieht jetzt so aus

docker run --rm -v "$PWD":/home/gradle/ -w /home/gradle android-build:5.4.1-28-27 /bin/bash -c "./pre.sh; gradle assembleDebug; ./post.sh"

In der Folge hat sich die durchschnittliche Build-Zeit unseres Projekts mehrmals verkürzt (abhängig von der Anzahl der Abhängigkeiten im Projekt, aber ein durchschnittliches Projekt wird jetzt in 1 Minute anstelle von 5 Minuten erstellt).

Das alles macht nur Sinn, wenn Sie einen eigenen internen CI/CD-Server haben, um dessen Unterstützung Sie sich selbst kümmern. Aber heutzutage gibt es viele Cloud-Dienste, in denen all diese Probleme gelöst sind und um die Sie sich keine Gedanken machen müssen. Die erforderlichen Eigenschaften des Builds können ebenfalls in den Projekteinstellungen angegeben werden.

Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte einloggen.

Halten Sie das CI/CD-System intern oder nutzen Sie einen externen Dienst

  • Wir verwenden einen internen Server

  • Wir nutzen einen externen Dienst

  • Wir verwenden kein CI/CD

  • Sonstiges

42 Benutzer haben abgestimmt. 16 Benutzer haben sich enthalten.

Quelle: habr.com

60GB SSD 8Gb DDR4