The Swift stdlib can be compiled for Android armv7 targets, which makes it possible to execute Swift code on a mobile device running Android. This guide explains:
If you encounter any problems following the instructions below, please file a bug using https://bugs.swift.org/.
Let's answer a few frequently asked questions right off the bat:
No. Although the Swift compiler is capable of compiling Swift code that runs on an Android device, it takes a lot more than just the Swift stdlib to write an app. You'd need some sort of framework to build a user interface for your application, which the Swift stdlib does not provide.
Alternatively, one could theoretically call into Java interfaces from Swift, but unlike as with Objective-C, the Swift compiler does nothing to facilitate Swift-to-Java bridging.
To follow along with this guide, you'll need:
You may have noticed that, in order to build the Swift stdlib for Linux, you needed to apt-get install libicu-dev icu-devtools
. Similarly, building the Swift stdlib for Android requires the libiconv and libicu libraries. However, you'll need versions of these libraries that work on Android devices.
The steps are as follows:
curl
, autoconf
, automake
, libtool
, and git
installed.git clone https://github.com/SwiftAndroid/libiconv-libicu-android.git
.which ndk-build
. Confirm that the path to the ndk-build
executable in the Android NDK you downloaded is displayed. If not, you may need to add the Android NDK directory to your PATH
.libiconv-libicu-android
: cd libiconv-libicu-android
./build-swift.sh
libicuXYZswift.so
libraries are located in the armeabi-v7a
directory.Enter your Swift directory, then run the build script, passing paths to the Android NDK, as well as the directories that contain the libicuucswift.so
and libicui18nswift.so
you downloaded or built in step one:
$ ARM_DIR=path/to/libicu-libiconv-android $ NDK_PATH=path/to/android-ndk16 $ utils/build-script \ -R \ # Build in ReleaseAssert mode. --android \ # Build for Android. --android-ndk $NDK_PATH \ # Path to an Android NDK. --android-api-level 21 \ # The Android API level to target. Swift only supports 21 or greater. --android-icu-uc ${ARM_DIR}/libicuucswift.so \ --android-icu-uc-include ${ARM_DIR}/icu/source/common \ --android-icu-i18n ${ARM_DIR}/libicui18nswift.so \ --android-icu-i18n-include ${ARM_DIR}/icu/source/i18n
hello.swift
to run on an Android deviceCreate a simple Swift file named hello.swift
:
print("Hello, Android")
To compile it, we need to make sure the correct linker is used. Symlink the gold linker in the Android NDK into your PATH
:
$ sudo ln -s \ /path/to/android-ndk-r16/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.gold \ /usr/bin/armv7-none-linux-androideabi-ld.gold
Then use the built Swift compiler from the previous step to compile a Swift source file, targeting Android:
$ NDK_PATH="path/to/android-ndk16" $ build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swiftc \ # The Swift compiler built in the previous step. # The location of the tools used to build Android binaries -tools-directory ${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin -target armv7-none-linux-androideabi \ # Targeting android-armv7. -sdk ${NDK_PATH}/platforms/android-21/arch-arm \ # Use the same NDK path and API version as you used to build the stdlib in the previous step. -L ${NDK_PATH}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a \ # Link the Android NDK's libc++ and libgcc. -L ${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x \ hello.swift
This should produce a hello
executable in the directory you executed the command. If you attempt to run this executable using your Linux environment, you'll see the following error:
cannot execute binary file: Exec format error
This is exactly the error we want: the executable is built to run on an Android device--it does not run on Linux. Next, let's deploy it to an Android device in order to execute it.
You can use the adb push
command to copy build products from your Linux environment to your Android device. If you haven't already installed adb
, you may do so via apt-get
:
$ sudo apt-get install android-tools-adb
Once you have adb
installed, verify your device is connected and is listed when you run the adb devices
command - currently this example works only in devices / emulators with at least Android 7.0, API 24 - then run the following commands to copy the Swift Android stdlib:
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftCore.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftGlibc.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftSwiftOnoneSupport.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftRemoteMirror.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftSwiftExperimental.so /data/local/tmp
You will also need to push the icu libraries:
adb push /path/to/libicu-android/armeabi-v7a/libicudataswift.so /data/local/tmp adb push /path/to/libicu-android/armeabi-v7a/libicui18nswift.so /data/local/tmp adb push /path/to/libicu-android/armeabi-v7a/libicuucswift.so /data/local/tmp
In addition, you‘ll also need to copy the Android NDK’s libc++:
$ adb push /path/to/android-ndk-r14/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so /data/local/tmp
Finally, you'll need to copy the hello
executable you built in the previous step:
$ adb push hello /data/local/tmp
You can use the adb shell
command to execute the hello
executable on the Android device:
$ adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/hello
You should see the following output:
Hello, Android
Congratulations! You've just run your first Swift program on Android.
When running the test suite, build products are automatically pushed to your device. As in part one, you'll need to connect your Android device via USB:
adb devices
. You should see your device listed.$ utils/build-script \ -R \ # Build in ReleaseAssert mode. -T \ # Run all tests. --android \ # Build for Android. --android-ndk ~/android-ndk-r13 \ # Path to an Android NDK. --android-ndk-version 21 \ --android-icu-uc ~/libicu-android/armeabi-v7a/libicuuc.so \ --android-icu-uc-include ~/libicu-android/armeabi-v7a/icu/source/common \ --android-icu-i18n ~/libicu-android/armeabi-v7a/libicui18n.so \ --android-icu-i18n-include ~/libicu-android/armeabi-v7a/icu/source/i18n/