Command-line tools for building and testing Swift packages on Android devices. Works with any SDK compatible with the official Swift SDK for Android. Used at Readdle to build Spark for Android.
These tools work with any Swift SDK for Android that follows the official artifact bundle layout:
- Official Swift SDK for Android - provided by the Swift Android Working Group of the Swift open source project, available for macOS and Linux.
- Readdle Swift Android Toolchain - a fork with Readdle-specific patches. Used as the default SDK path (see Environment Variables).
Any other SDK that is compatible with the official one can be used by setting SWIFT_ANDROID_SDK_HOME.
This toolkit provides two commands through a unified swift-android dispatcher:
| Command | Description |
|---|---|
swift-android build |
Cross-compile a Swift package for Android |
swift-android test |
Build, deploy, and run XCTest suites on a connected Android device |
Both tools wrap Swift Package Manager and use the configured SDK artifact bundle to produce native Android binaries. Test execution is handled over ADB.
- Swift toolchain (managed via Swiftly, defaults to 6.2)
- Swift SDK for Android artifact bundle (see Supported SDKs)
- Android Debug Bridge (ADB) on your
PATH(from Android SDK Platform-Tools) - Python 3 (for the test runner)
- A connected Android device or emulator (for
swift-android test)
Clone the repository and add it to your PATH:
git clone https://github.com/nicklama/swift-android-buildtools.git
export PATH="$PATH:/path/to/swift-android-buildtools"| Variable | Default | Description |
|---|---|---|
SWIFT_ANDROID_SDK_HOME |
~/Library/org.swift.swiftpm/swift-sdks/readdle-swift-6.2.1-RELEASE_android.artifactbundle |
Root of the Swift SDK for Android artifact bundle. The default points to the Readdle SDK on macOS. When using the official SDK or running on Linux, you must set this to your SDK installation path. |
SWIFT_ANDROID_ARCH |
aarch64 |
Target CPU architecture. See Architecture Support. |
SWIFT_ANDROID_API_LEVEL |
29 |
Minimum Android API level (Android 10 by default). |
ANDROID_SERIAL |
(none) | Default ADB device serial. Can be overridden per-invocation with --device. |
X_ANDROID_* |
(none) | Any environment variable prefixed with X_ANDROID_ is forwarded to the Android device at test execution time with the prefix stripped. For example, X_ANDROID_MY_VAR=1 becomes MY_VAR=1 on the device. |
Three Android architectures are supported:
SWIFT_ANDROID_ARCH |
SDK Triple | NDK Triple | Android ABI | Notes |
|---|---|---|---|---|
aarch64 (default) |
aarch64-unknown-linux-android |
aarch64-linux-android |
arm64-v8a |
Most modern phones and tablets |
x86_64 |
x86_64-unknown-linux-android |
x86_64-linux-android |
x86_64 |
Emulators, some Chromebooks |
armv7 |
armv7-unknown-linux-androideabi |
arm-linux-androideabi |
armeabi-v7a |
Legacy 32-bit ARM devices |
| Set the architecture before building: |
export SWIFT_ANDROID_ARCH=x86_64
swift-android buildCross-compiles a Swift package for Android using Swift Package Manager.
swift-android build [options...]
All arguments are forwarded directly to swift build, so any flag accepted by Swift PM can be used.
- Resolves the target architecture from
SWIFT_ANDROID_ARCH(defaults toaarch64) - Resolves the API level from
SWIFT_ANDROID_API_LEVEL(defaults to29) - Constructs the Swift SDK triple (e.g.
aarch64-unknown-linux-android29) - Auto-detects the Swift version from the SDK's
sbom.spdx.json(falls back to 6.2) - Invokes
swift buildvia Swiftly with:--swift-sdk <triple>to target Android-Xbuild-tools-swiftc -DTARGET_ANDROIDcompile flag-Xbuild-tools-swiftc -D<TRIPLE_FLAG>architecture-specific compile flag
- Forwards all additional arguments to
swift build
The build tool automatically defines these compile-time flags for build tool plugins and package manifest conditions:
| Flag | When Defined |
|---|---|
TARGET_ANDROID |
Always (every Android build) |
TRIPLE_AARCH64_LINUX_ANDROID |
SWIFT_ANDROID_ARCH=aarch64 or unset |
TRIPLE_X86_64_LINUX_ANDROID |
SWIFT_ANDROID_ARCH=x86_64 |
TRIPLE_ARM_LINUX_ANDROID |
SWIFT_ANDROID_ARCH=armv7 |
These flags are passed via -Xbuild-tools-swiftc and are available in your Package.swift build tool plugin code. |
Build for the default architecture (aarch64, API 29):
swift-android buildBuild in release mode:
swift-android build -c releaseBuild for x86_64 emulator:
SWIFT_ANDROID_ARCH=x86_64 swift-android buildBuild targeting a specific API level:
SWIFT_ANDROID_API_LEVEL=24 swift-android buildBuild a specific product:
swift-android build --product MyLibraryBuild with verbose output:
swift-android build -vBuilds, deploys, and runs Swift XCTest suites on a connected Android device via ADB. This is a three-phase tool: build, push, and execute.
swift-android test [options...] [-Xbuild <arg>] [-Xtest <arg>]
| Flag | Description |
|---|---|
-s, --serial, --device <serial> |
Use the Android device with the given serial number. Overrides the ANDROID_SERIAL environment variable. |
| Flag | Description |
|---|---|
-f, --fast, --just-run |
Fast mode. Skip both building and pushing; only execute tests on the device. Equivalent to --skip-build --skip-push. |
-d, --deploy |
Deploy mode. Build and push to the device but do not run tests. Equivalent to --skip-testing. Useful for manual execution with profiling or debugging tools. |
| Flag | Description |
|---|---|
--skip-build |
Skip the build step. Only deploy and run. Useful when the binary is already compiled. |
| Flag | Description |
|---|---|
--skip-push |
Skip all file deployment. Only run tests with whatever is already on the device. |
--skip-push-stdlib |
Don't push Swift standard library and runtime .so files to the device. Saves time if the stdlib hasn't changed. |
--skip-push-external |
Don't push externally built dependency libraries (.so from artifact outputs). |
| Flag | Description |
|---|---|
--skip-testing |
Don't execute tests on the device after building and deploying. Useful for deploying, then manually running with tools like simpleperf, lldb, etc. |
| Flag | Description |
|---|---|
-Xbuild <arg> |
Forward an argument to Swift Package Manager during the build phase. Can be specified multiple times. Example: -Xbuild -v for verbose build output. |
-Xtest <arg> |
Forward an argument to the XCTest runner on the device. Can be specified multiple times. Example: -Xtest --filter -Xtest MyTests.testFoo. |
Note: Thanks to a custom argument parser, you can write
-Xbuild -vinstead of the more verbose-Xbuild='-v'syntax.
The test runner executes up to three phases:
Invokes swift-android build --build-tests (plus any -Xbuild arguments) to compile the test bundle.
Deploys the following to the Android device at /data/local/tmp/<Package>PackageTests-<arch>/:
| Component | Source | Skip Flag |
|---|---|---|
| Test binary | .build/<target>/<config>/<Package>PackageTests.xctest |
(always pushed) |
| Project shared libraries | .build/<target>/<config>/*.so |
(always pushed) |
| Swift runtime libraries | $SWIFT_ANDROID_SDK_HOME/swift-android/swift-resources/usr/lib/swift-<arch>/android/*.so* |
--skip-push-stdlib |
| C++ standard library | $SWIFT_ANDROID_SDK_HOME/swift-android/ndk-sysroot/usr/lib/<ndk-triple>/libc++_shared.so |
--skip-push-stdlib |
| External dependency libs | .build/artifacts/*/*/*/<triple>/*.so |
--skip-push-external |
Runs the test binary on the device via adb shell with LD_LIBRARY_PATH set to the deployment directory. Any X_ANDROID_* host environment variables are forwarded as environment variables on the device.
Full build-push-run cycle:
swift-android testRun all tests in a specific module:
swift-android test -Xtest MyModuleTestsRun all tests in a specific test class:
swift-android test -Xtest MyModuleTests.SomeTestClassRun a specific test case:
swift-android test -Xtest MyModuleTests.SomeTestClass/testSpecificCaseRun on a specific device:
swift-android test --device DEVICE_SERIALQuick re-run (skip build and push):
swift-android test --fastDeploy only:
swift-android test --deploySkip only the stdlib push (already on device):
swift-android test --skip-push-stdlibIterative development (rebuild, only push project libs):
swift-android test --skip-push-stdlib --skip-push-externalBuild in release and test:
swift-android test -Xbuild -c -Xbuild releaseForward environment variables to the device:
X_ANDROID_MY_DEBUG=1 X_ANDROID_TRACE_LEVEL=verbose swift-android testMIT License - Copyright (c) 2017 Readdle Inc.
See LICENSE for details.