Swift on Android: A new competitor to Kotlin Multiplatform or just NDK with sugar?



This content originally appeared on Level Up Coding – Medium and was authored by Dmitry Glazunov

Swift on Android sounds bold. The official SDK makes it possible to compile Swift for Android targets, plug the resulting library into an app, and call it from Kotlin — without rewriting in C++. But what does it mean in practice: a new cross-platform competitor, or just a more convenient path to NDK-level native code?

To figure this out without guesswork, I decided to go through the whole path hands-on: from setting up the toolchain and cross-compilation to a minimal check on a device, turning Swift code into a shared library (.so), loading it via System.loadLibrary(…), and wiring it to Kotlin through JNI (with a brief look at swift-java to avoid hand-written glue code). Along the way, key nuances surfaced—the runtime components, ABI/API choices, memory ownership, and two-way calls (Swift → Kotlin callbacks). The final takeaways and the answer to the question in the title—“a competitor to KMP or NDK with sugar?”— are reserved for the conclusion.

How does it work? The concept of cross-compilation

Unlike compiling for macOS or iOS, where you are working on the same platform that you are building the application for, development for Android requires cross-compilation. This means you will use your computer (the host, e.g., macOS or Linux) to build code that will run on a different platform (the target, i.e., Android).

To do this, you will need three key components.

1) Setting up the work environment

Before you can write the first line of code, you must set up the environment for cross-compilation.

1. Host toolchain (Swift tools)

You need a specific version of Swift that matches the Android SDK version. The easiest way to manage Swift versions is to use swiftly:

# Install the required version (example version, see docs for current)
swiftly install main-snapshot-2025-10-16

# Switch to this version
swiftly use main-snapshot-2025-10-16

2. Swift SDK for Android

This is the set of libraries and resources needed to build for Android. It is installed using the built-in swift sdk command:

# Download and install the SDK (URL from official documentation)
swift sdk install https://download.swift.org/development/android-sdk/.../swift-SDK.artifactbundle.tar.gz

3. Android NDK (Native Development Kit)

The NDK contains the tools (such as clang and ld) and libraries that the Swift SDK uses to compile and link your code.

  • Download the Android NDK (e.g., version r27d) from the official Android site.
  • Unzip it and set the ANDROID_NDK_HOME environment variable to point to the NDK folder:
export ANDROID_NDK_HOME=$PWD/android-ndk-r27d
  • Link the NDK with your Swift SDK. This is the most important step. The Swift SDK includes a special script for this:
# The path to the script may vary slightly
~/.swiftpm/swift-sdks/YOUR_SDK_NAME.artifactbundle/swift-android/scripts/setup-android-sdk.sh

After completing these steps, your environment is ready for cross-compilation.

2) “Hello, World!” (Console version)

Let’s try to compile a simple console program in Swift and run it on an Android device.

  1. Create a new Swift project:
mkdir hello-android
cd hello-android
swift package init --type executable

2. Open main.swift and ensure it contains print("Hello, world!").

3. Compile the project for Android (e.g., for the aarch64 architecture):

swift build --swift-sdk aarch64-unknown-linux-android28 --static-swift-stdlib

This command will create an executable file in .build/aarch64-unknown-linux-android28/debug/hello.

4. To run this on a device (or emulator), you need to copy the executable file and the required C++ library from the NDK using adb (Android Debug Bridge):

# Copy our program
adb push .build/aarch64-unknown-linux-android28/debug/hello /data/local/tmp

# Copy the dependency from the NDK
adb push $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/*/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so /data/local/tmp/

# Run it!
adb shell /data/local/tmp/hello
# Output: Hello, world!

This proves that Swift code can run on Android. However, real applications don’t work this way.

3) Integrating Swift into an Android app (the right way)

In a real Android application (written in Kotlin or Java), you don’t run executables. Instead, you compile your Swift code into a shared library (an .so file).

Your Android application then loads this library and calls functions from it using JNI (Java Native Interface).

The swift-android-examples repository provides excellent templates for this.

4) Practical examples from the repository

Let’s look at the key examples from swiftlang/swift-android-examples that show how this works in practice.

Example 1: hello-swift (Basic call)

This example shows how to call a simple Swift function from Kotlin.

  1. Swift code (compiled into an .so library): It defines a function that returns a string. CChar is used for C compatibility.
// Swift Code
import Foundation

@_cdecl("getHelloString")
public func getHelloString() -> UnsafeMutablePointer<CChar> {
let swiftString = "👋 Hello from Swift"
return strdup(swiftString)
}

@_cdecl("getHelloString") makes this Swift function available to C (and, therefore, to JNI).

2. Kotlin Code (in the Android app):

// Kotlin Code
class MainActivity : AppCompatActivity() {

// 1. Declaration of the "external" (native) function
private external fun getHelloString(): String

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// 2. Loading our compiled Swift library
System.loadLibrary("hello-swift") // Library name

// 3. Calling the Swift function!
val swiftMessage = getHelloString()

// Setting the text in the TextView
findViewById<TextView>(R.id.text_view).text = swiftMessage
}
}

Example 2: hello-swift-callback (Two-way communication)

This example is more complex: it shows how Swift can call back to Kotlin code. Swift starts a timer and periodically updates the Android UI.

  • Swift uses a Timer and calls a function pointer (passed to it by Kotlin) to send the updated time.
  • Kotlin passes a function to Swift that knows how to update the TextView, and Swift calls it every second.

Example 3: swift-java-hashing-example (JNI Automation)

Writing JNI code manually (“glue” code between Java and Swift) is tedious and error-prone. This example uses the swift-java tool, which automatically generates the JNI code, allowing you to call Swift methods from Java/Kotlin almost as if they were native.

Example 4: native-activity (100% Swift)

This is the most advanced example. It shows an application written entirely in Swift, including handling lifecycle events and rendering graphics with OpenGL ES. This demonstrates the full potential of Swift on the platform.

So, is it a competitor to KMP?

Not yet, IMHO. Swift on Android is more like an experimental bridge for native performance modules rather than a full cross-platform solution. It’s powerful for shared algorithms, crypto, or rendering layers, but lacks UI, tooling, and ecosystem maturity to rival KMP today.

Let’s pin down the scope by comparing Swift on Android and KMP across key criteria:

Swift on Android vs. Kotlin Multiplatform

Conclusion

Swift on Android isn’t a replacement for KMP. It’s a practical way to bring Swift into Android as a fast, native library — closer to NDK with sugar than a full cross-platform stack.
Use it where it shines: reusing existing Swift code, speeding up heavy algorithms, crypto, parsing, or rendering. Be ready for the trade-offs: no shared UI, early tooling, and some care around JNI and memory.
Today’s verdict: use Swift on Android for sharp, targeted pieces. Keep KMP for the broader product story.


Swift on Android: A new competitor to Kotlin Multiplatform or just NDK with sugar? was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding – Medium and was authored by Dmitry Glazunov