Android
There are a few different ways to integrate with our Android binaries when building for Android. None are particularly outstanding:
- An "Ivy Repository"
- Works great, but impossible to test changes on an emulator locally or in CI :(
- Raw Groovy & Gradle
- Works in theory, but tedious to have to write all needed logic in Groovy/Gradle
- Starting an OS Shell
- Similar to iOS & macOS, see that section for more details on this
- Wouldn't work on Windows development machines unfortunately; the started shell would not be
bash
- CMake
- We call to CMake from Gradle to take care of fetching and processing our Android binaries
- A somewhat odd approach, but works cross-platform and has code re-use from Windows/Linux!
Due to the above reasoning, we cover how to use CMake on this page. But do note, there are other possibilities out there.
CMake (/packages/flutter_library_name/android/CMakeLists.txt
)
Unlike windows and linux CMakeLists.txt, the android equivalent does
not actually build anything, which may come as a surprise.
Instead, its sole purpose is to download & extract our Android binaries
in a cross-platform friendly way. Here is our android CMakeLists.txt
:
set(LibraryVersion "library_name-v0.0.0") # generated; do not edit
set(PROJECT_NAME "project_name")
# Unlike the Windows & Linux CMakeLists.txt, this Android equivalent is just here
# to download the Android binaries into src/main/jniLibs/ and does not build anything.
# The binary download/extraction is difficult to do concisely in Groovy/Gradle,
# at least across host platforms, so we are just reusing our Linux/Windows logic.
# The Flutter tooling requires that developers have CMake 3.10 or later
# installed. You should not increase this version, as doing so will cause
# the plugin to fail to compile for some customers of the plugin.
cmake_minimum_required(VERSION 3.10)
project(PROJECT_NAME)
# Download the binaries if they are not already present.
set(LibRoot "${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs")
set(ArchivePath "${CMAKE_CURRENT_SOURCE_DIR}/${LibraryVersion}.tar.gz")
if(NOT EXISTS ${ArchivePath})
file(DOWNLOAD
"https://github.com/YourGitHubAccount/repo_name/releases/download/${LibraryVersion}/android.tar.gz"
${ArchivePath}
TLS_VERIFY ON
)
endif()
# Extract the binaries, overriding any already present.
file(REMOVE_RECURSE ${LibRoot})
file(MAKE_DIRECTORY ${LibRoot})
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xzf ${ArchivePath}
WORKING_DIRECTORY ${LibRoot}
)
Replace all instances of library_name
above with your library name.
Also, replace other variables (i.e. YourGitHubAccount
and repo_name
) as needed.
build.gradle
Changes
Replace the android {...}
section at the bottom of build.gradle
with the following:
android {
compileSdkVersion 31
defaultConfig {
minSdkVersion 16
}
// Trigger the binary download/update over in CMakeLists.txt
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
.gitignore
Add the following to android/.gitignore
# Ignore Rust binaries
src/main/jniLibs/
*.tar.gz
Build Script (/scripts/build-android.sh
)
#!/bin/bash
# Setup
BUILD_DIR=platform-build
mkdir $BUILD_DIR
cd $BUILD_DIR
# Create the jniLibs build directory
JNI_DIR=jniLibs
mkdir -p $JNI_DIR
# Set up cargo-ndk
cargo install cargo-ndk
rustup target add \
aarch64-linux-android \
armv7-linux-androideabi \
x86_64-linux-android \
i686-linux-android
# Build the android libraries in the jniLibs directory
cargo ndk -o $JNI_DIR \
--manifest-path ../Cargo.toml \
-t armeabi-v7a \
-t arm64-v8a \
-t x86 \
-t x86_64 \
build --release
# Archive the dynamic libs
cd $JNI_DIR
tar -czvf ../android.tar.gz *
cd -
# Cleanup
rm -rf $JNI_DIR