-
Notifications
You must be signed in to change notification settings - Fork 20
Development Setup for Android
This page describes how to set up a development environment for testing the OX COI Messenger app in a local Android emulator.
The prerequisites section so far only describes Debian Linux. You are welcome to add descriptions for other operating systems.
The main prerequisites are:
- Git to access the source code,
- A C development toolchain to compile some native dependencies,
- A Rust development toolchain to compile DeltaChat Core,
- Android Studio with Flutter support to compile the app,
- A hypervisor to accelerate the emulation of Android devices.
This setup assumes Debian 10. Other versions and other Debian-based distributions should work pretty much the same. Other Linux distributions might need to use a different package manager and maybe slightly different package names.
Git, the C tool-chain and the KVM hypervisor can be installed from the main package repository. Also, curl
is needed to install the Rust tool-chain.
sudo apt install git build-essential libvirt-daemon curl
At the time of writing, the Rust tool-chain requires the nightly build and cross-compilation, so it cannot be installed from the package repository yet (even from sid). Instead, install rustup
by following the instructions on https://rustup.rs/. When prompted, customize the installation and select the nightly toolchain. Letting rustup
modify the PATH
variable is not likely to work, since it modifies $HOME/.profile
, which is not (supposed to be) used by terminal emulators in graphical environments. Instead, add the $HOME/.cargo/bin
directory to your PATH
manually by adding the following line to the end of your $HOME/.bashrc
:
source "$HOME/.cargo/env"
It might actually be possible to build and run the app entirely from the command line and/or using packages from Debian repositories. Any experience reports or documentation are welcome. But for now, the full Android Studio from Google is going to be used here.
Download Android Studio from https://developer.android.com/studio and unpack it somewhere you'll be able to find later. Start Android Studio from the unpacked directory with
android-studio/bin/studio.sh
On first run, the Android Studio Setup Wizard will start automatically and offer to download an SDK and other components. The rest of the documentation will assume a standard install, but the only important option is the path of the SDK Folder, which is displayed on the Verify Settings page. It defaults to $HOME/Android/Sdk
and is used to run various command line tools, as seen below.
The last page of the Setup Wizard contains a link to installation instructions for the hypervisor for your platform. Since KVM was installed as the very first step above, it should already work. To verify this, use the following command:
$HOME/Android/Sdk/emulator/emulator -accel-check
The expected output is:
accel:
0
KVM (version 12) is installed and usable.
accel
After the Setup Wizard is finished, the Welcome to Android Studio window is displayed. Further configuration will be done via the Configure menu in the bottom right. If you already opened a project, the same entries are available in the Tools menu instead.
Launch the SDK Manger by selecting Configure/Tools → SDK Manager. In the tab SDK Tools, select NDK (Side by side) and install it. After the download is finished, the log window should contain a line like
Installing NDK (Side by side) 20.1.5948944 in /home/…/Android/Sdk/ndk/20.1.5948944
This installation directory, and its subdirectory toolchains/llvm/prebuilt/linux-x86_64/bin
need to be added to your PATH
, e.g. by adding something like the following to $HOME/.bashrc
:
export PATH="$PATH:$HOME/Android/Sdk/ndk/20.1.5948944"
export PATH="$PATH:$HOME/Android/Sdk/ndk/20.1.5948944/toolchains/llvm/prebuilt/linux-x86_64/bin"
Use the Android Virtual Device Manager to create an Android virtual device by selecting Configure/Tools → AVD Manager → Create Virtual Device… On the first two pages, you can select any device and image, but latest versions are recommended. The system image probably needs to be downloaded first. After finishing the creation, the virtual device can be launched from the Your VirtualDevices page by clicking on the green Play button.
Install Flutter by following instructions on https://flutter.dev/docs/get-started/install. To get a perfect score in the output of the flutter doctor
command, follow these steps after unpacking the SDK and adding it to your PATH
:
flutter config --no-analytics
flutter doctor --android-licenses
Install Flutter support in Android Studio by selecting Configure/Tools → Plugins → Flutter → Install. This should also install Dart support. Restart the IDE afterwards.
Now launch the created Android device from the AVD Manager and run
flutter doctor
It should not find any issues.
The source code of the app is distributed over several Git repositories. Currently, they expect to be checked out into the same parent directory. This parent directory will be referred to as $GIT
from now on.
cd $GIT
git clone https://github.com/open-xchange/ox-coi.git
git clone -b ndk20 https://github.com/open-xchange/flutter-deltachat-core.git
The branch ndk20
is only needed until the corresponding pull request is merged.
If you are not going to work on DeltaChat Core or any other Rust code, then you can let Git submodules and Rust's package manager Cargo take care of downloading the necessary Rust code:
cd $GIT/flutter-deltachat-core/android/jni
git submodule update --init deltachat-core-rust
If, on the other hand, you want to test Rust code which you modified locally, then you also need check out the corresponding Rust sources, preferably into the same directory:
git clone -b coi-metadata https://github.com/open-xchange/deltachat-core-rust.git
git clone -b interruptible-idle https://github.com/open-xchange/rust-imap.git
git clone -b metadata https://github.com/open-xchange/tokio-imap.git
The branches might change in the future, and you will of course use other branches while working on your code. If you are not going to modify a dependency, then you don't need to check it out.
To use the checked out sources in the app, replace the Git submodule with a symlink to the separate workspace:
cd $GIT/flutter-deltachat-core/android/jni
rmdir deltachat-core-rust
ln -s ../../../deltachat-core-rust
Take care to never commit this change to Git!
Common for both of the above variants, the correct Rust libraries for cross-compilation need to be installed. Since deltachat-core-rust
sepcifies an exact version of the nightly toolchain in its rust_toolchain
file, the installation of the toolchain needs to happen from that directory:
cd deltachat-core-rust
rustup target add aarch64-linux-android armv7-linux-androideabi \
i686-linux-android x86_64-linux-android
Finally, Rust needs to know where to find some Android-specific tools. These are configured in $GIT/.cargo/config
:
paths = ["tokio-imap", "tokio-imap/imap-proto", "rust-imap"]
[target.armv7-linux-androideabi]
ar = "arm-linux-androideabi-ar"
linker = "armv7a-linux-androideabi21-clang"
[target.aarch64-linux-android]
ar = "aarch64-linux-android-ar"
linker = "aarch64-linux-android21-clang"
[target.i686-linux-android]
ar = "i686-linux-android-ar"
linker = "i686-linux-android21-clang"
[target.x86_64-linux-android]
ar = "x86_64-linux-android-ar"
linker = "x86_64-linux-android21-clang"
The first line contains relative paths and is only necessary if locally modified dependencies of deltachat-core-rust
are used. The path to the local deltachat-core-rust
itself was specified by the symlink in Rust and Flutter. Currently, this method of overwriting dependencies prints a warning, and might stop working in the future. Cargo issue #6713 hopefully provides a better solution until then.
The rest of the file relies on the PATH
entries added in Native Development Kit (NDK) and can be put in any other directory where Cargo will find it, e.g. in particular $HOME/.cargo/config
.
Once all the installation steps above are complete, the actual compilation and building of the app should be very easy, and require only CPU time.
First, build the Rust part:
cd $GIT/flutter-deltachat-core/android
./ndk-make.sh
This will take some time the first time, since everything is built for all 4 supported target platforms (32bit and 64bit for each ARM and Intel).
In the mean time, open the $GIT/ox-coi
project in Android Studio. If it's the first time, several notifications will pop up:
- Welcome to Flutter! is just polite spyware: select No thanks.
- Frameworks Detected has only one option: Configure. It opens a dialog. Just select OK there.
-
'Packages get' has not been run appears at the top of the automatically opened editor for
main.dart
: select Get dependencies.
If you miss any notification pop-ups, they can be found again in the Event Log in the bottom right corner.
For now, one more manual one-time adjustment is necessary: Select
Run → Edit Configurations… and in the configuration for main.dart
find the setting Build flavor and enter the value development
.
Before launching the app, several checks are useful to avoid most frequent errors:
- Check that the Rust build finished without errors.
- Ensure that the virtual Android device is running
- Select the Android device in the Flutter Device Selection drop-down in the toolbar.
Finally, you can launch the app by selecting either the green Run or the Debug button in the toolbar.
On repeated runs, the ndk-make.sh
step is only necessary whenever any local Rust code was modified. The Flutter parts are built automatically before the updated app is launched.