Building an Android project in a Docker container

When developing a project for the Android platform, even the smallest one, sooner or later you have to deal with the development environment. In addition to the Android SDK, it is necessary to have the latest version of Kotlin, Gradle, platform-tools, build-tools. And if on the developer's machine all these dependencies are solved to a greater extent using the Android Studio IDE, then on the CI / CD server, each update can turn into a headache. And if in web development, Docker has become the standard solution to the environment problem, then why not try to solve a similar problem with it in Android development ...

For those who do not know what Docker is - if it is quite simple, then this is a tool for creating the so-called. "Containers" which contain the minimum OS kernel and the necessary set of software that we can deploy wherever we want, while maintaining the environment. What exactly will be in our container is determined in the Dockerfile, which is then assembled into an image that can be launched anywhere and has idempotency properties.

The installation process and the basics of Docker are beautifully described on his the official website. Therefore, looking ahead a little, we have such a Dockerfile

# Π’.ΠΊ. основным инструмСнтом для сборки 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"

We save it to the folder with our Android project and start building the container with the command

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

Parameter -t sets the tag or name of our container, which usually consists of its name and version. In our case, we called it android-build and in the version we specified a combination of gradle, android-sdk and platform-tools versions. In the future, it will be easier for us to search for the image we need by name using such a β€œversion”.

After the build has passed, we can use our image locally, we can download it with the command docker push to a public or private image repository in order to download it to other machines.

As an example, let's build a local project. To do this, in the project folder, run the command

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

Let's figure out what it means:

dockerrun - the image launch command itself
-rm - means that after stopping the container, it deletes everything that was created during its life
-v "$PWD":/home/gradle/ - mounts the current folder with our Android project to the container's internal folder /home/gradle/
-w /home/gradle - sets the working directory of the container
android-build:5.4.1-28-27 - the name of our container that we have collected
gradle assembleDebug - the build team itself, which assembles our project

If everything goes well, then after a couple of seconds / minutes you will see something like BUILD SUCCESSFUL in 8m 3s! And in the app/build/output/apk folder there will be an assembled application.

Similarly, you can perform other gradle tasks - check the project, run tests, etc. The main advantage is that if we need to build the project on any other machine, we do not need to worry about installing the entire environment, and it will be enough to download the necessary image and run the build in it.

The container does not store any changes, and each assembly is launched from scratch, which, on the one hand, guarantees the identity of the assembly regardless of where it is launched, on the other hand, every time you have to download all the dependencies and compile all the code again, and this can sometimes take a significant amount of time. Therefore, in addition to the usual "cold" start, we have the option of starting the assembly while maintaining the so-called. "cache", where we save the ~/.gradle folder by simply copying it to the working folder of the project, and at the beginning of the next build we return it back. We moved all copying procedures into separate scripts and the launch command itself began to look like this

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"

As a result, the average project build time was reduced by several times (depending on the number of dependencies on the project, but the average project thus began to build in 1 minute instead of 5 minutes).

All this by itself only makes sense if you have your own internal CI / CD server, which you yourself support. But now there are many cloud services in which all these problems are solved and you don’t have to worry about it, and the necessary build properties can also be specified in the project settings.

Only registered users can participate in the survey. Sign in, you are welcome.

Do you keep your CI/CD system internal or use a third party service

  • Using an internal server

  • Using an external service

  • We don't use CI/CD

  • Other

42 users voted. 16 users abstained.

Source: habr.com

Add a comment