Android Emulation on Docker

ccarcaci
6 min readFeb 27, 2019

--

Overcome the Android emulation ecosystem pain using Docker

(Versione in italiano)

If you are a lazy expert that don’t want to read the article go to: https://github.com/ccarcaci/templating-rn

How often we found ourself in the case where before to start writing a single line of code we had to follow countless tutorials just to setup our development environment or just to debug some lines of code.

Those tutorials often became the sum of very “fast” and “simple” steps leading everything to an unmaintainable burden. As newbie I have started to follow them until I got myself stuck into some unconsistencies.

A good example of those mess is React Native environment for Android. If I want to be able to to test my code I have to face these technologies and frameworks:

          +---------------+         +---------------+
| Code +---------+ Expo |
| | +----+ |
+-------+-------+ | +-------+-------+
| | |
| | |
+-------+-------+ | +-------+-------+
| js libraries | | | ADB |
| | | | |
+-------+-------+ | +-------+-------+
| | |
| | |
+-------+-------+ | +-------+-------+
| $ npm +----+ | Emulator |
| | | |
+-------+-------+ +-------+-------+
| |
| |
+-------+-------+ +-------+-------+
| npm | | Android SDK |
| registry | | |
+---------------+ +-------+-------+
|
|
+-------+-------+
| Android |
| Device |
+---------------+

(Skilled people should forgive me about some mistakes into this drawing)

Briefly, with some useful links.

  • Code: IDE + git
  • npm: js libraries
  • Expo: packager and debug
  • adb: debug bridge through the emulator
  • IntelliJ + Android Plugin: I was already using the CE edition of IntelliJ thus I prefer to avoid Android Studio just for the emulator
  • Android SDK Tools: see below

All of these technologies need a proper setup, following some tutorials, for example:

Moreover this kind of setup is composed by multiple steps and additional packages. Their dependencies could generate some conflict with pre-existing software on the system. For example I have tried Genymotion but it fails because it gave to me an unclear “emulation error” that I wasn’t able to overcome even if I spent a lot of hours on StackOverflow.

To avoid those problems we can use a physical device jumping all of emulation parts by installing the Expo app. Unfortunately this solution implies several switches between the code and the device that make our development process cumbersome and unfitting (not so “Lean”).

Our desiderata is:

Unfortunately even if on Windows and Mac it is not so difficult to install Android emulation solutions, on Linux (Ubuntu) we have to face with this burden. Anyway we should consider that on each OS we need to spend some time to setup the entire ecosystem and every update could raise some problems.

So, to satisfy our desiderata we need something that allow us to write the code, push some magic button and, “voilà”, our code on emulated device. And hot reloading would be a (an amazing) nice to have.

First failed attempts

The journey to a suitable solution has been very hard and plenty of failures.

  • Shell script: I tried to translate the tutorials into a script. Yep, the process was automated but I still had the host system dependencies problem. Moreover I am a scarced rookie with shell scripting and I won’t use him for scripts larger than 20 lines of code. Anyway I have created a script that is a little more than 20 lines of code, “shame on me” (cit.), that installs the entire Android emulation suite and runs the emulator. I’m still working on it, but it is available here: https://github.com/ccarcaci/android-emu
  • Single Dockerfile: packing everything to a Dockerfile is a minimal solution but the layering over the base emulator image (https://github.com/budtmo/docker-android) has not been possible. I’d like to go deep with the author because I don’t understand the inner running mechanism

What brings us some results

Wise man says: “Microservices lesson can help us”

An (ugly) running application

By using Docker for microservices architecture, the setup and run of inner services is an easy game. Using docker-compose we are able to specify the entire ecosystem that provides the service.

Can we use the same technique to improve the React Native application development?

The response is: yes. We can use docker-compose to link the emulator with our container that deploys the React Native app using ADB.

I have written some shell script, as usual with Docker

How is it made?

We can start downloading the code from repository:

$ git clone git@github.com:ccarcaci/andocker.git

We have two folders into our repository: /code and /ecosystem

The first folder contains the React Native code that will run into the emulator. The latter one (/ecosystem) has the code to build the entire Docker ecosystem.

The Docker ecosystem starts from compose.sh script. This script starts by setting up the Docker emulator version:

export butomoVersion=8.1 

Then stops any running instances of Docker compose and clean up any dangling Docker images. After this process it builds the Docker composition and runs it.

docker-compose build --build-arg butomoVersion=$butomoVersion emulator expodocker-compose up -d

The first run of the Docker composition will take some minutes to download and install all the involved Docker images, even after the updates. After the first run the following ones will take around a minute to start.

Once the starting phase has done the composition opens a Chrome instance to NoVNC server (http://localhost:6080) provided by the Android emulator inside the Docker container.

The docker-compose.yml file describe the entire composition that is composed by the Android emulator (https://github.com/butomo1989/docker-android) and the Docker image with all the dependencies for React Native development.

The Dockerfile-expo includes the React Native ecosystem specification. It is build over the node base image by adding the Android platform-tools needed by ADB (Android Debug Bridge). ADB allows the execution of the React Native application on the emulator.

Application is started by the run-expo-app.sh script that installs the dependencies through npm and waits for 20 seconds that the emulator starts. After this waiting time it creates the bridge (using ADB) and starts the application using Expo.

Some troubles

I’m still working on them

Unfortunately the Android emulator is not reliable. Sometimes it reboots, I’m trying to investigate the reasons.

Furthermore to start the application npm installs the Expo packager on the emulated device, during this installation an annoying popup about permits is shown.

It is enough to click on “OK” over the popup, enable the “Allow display over other apps” and push the bottom-right “back” button on the phone.

[FIXED! v0.0.2] The application code is copied during the creation phase of the Docker composition, I’m working on shared volumes between the /code folder and the Docker image. This should also enable the hot-reload.

In the end the 20 seconds waiting into the starting script must be eliminated. The best solution should be an event raised when the emulator has started, but it is a very high goal.

Advantages

The first clear advantage is that the application starts by executing a script and we can see the changes on our code immediately. Moreover, as it happens in CI/CD environments, through an automated process we don’t have to lose our time with weird and complex commands that will make us to do some mistakes.

This solution follows the “Infrastructure as Code” philosophy thus another pros is that every change could be traced and managed by changing the code (and committing it on git).

Finally this is a portable solution. By using Docker we don’t have dependencies with the host system and we don’t have to lose our time to reconfigure our development machine. The entire ecosystem is shareable, even if the Docker images are big, but this is not our problem. The network will be happy to help us.

This project will be updated all the time, I’ll wait for your forks and contributes of my GitHub project.

2020–05–10 update: take a look to the technical limitations.

--

--

ccarcaci

Don’t waste your time explaining your work, let your code speak and be ready to improve it