Primary: Swift • Also : Kotlin, Ruby, TypeScript… My fun • Travel • Natural language (not programming) How Swift runs on Android X: @yutk_941 GitHub: @taka-2120 2 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4. How is memory managed across both runtimes? 5. What is different from KMP? 6. What is it like to write? How Swift runs on Android 3 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4. How is memory managed across both runtimes? 5. What is different from KMP? 6. What is it like to write? How Swift runs on Android 4 / 60
only for Apple platform • Linux (since 2015) • Windows (since 2020) • Embedded (since 2024) • Java (since 2024) * Officially announced How Swift runs on Android 7 / 60
logic with “Swift” = Write Kotlin code like Swift (a.k.a. Kotlish) Regulations • Most third-party packages cannot be used • Does not accept implementation that has no Kotlin equivalent How Swift runs on Android 9 / 60
existed • finagolfin / swift-android-sdk • Led Swift-on-Android as an individual for years • Became the basis of today s Swift SDK for Android • Many other community toolchains ’ How Swift runs on Android 12 / 60
on Android Community Working Group formed • Kicked off by the Skip team to unify scattered toolchains 2025/06 • Approved as an official Swift Android Workgroup 2026/03 • Swift 6.3 ships the first official Swift SDK for Android How Swift runs on Android 13 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4. How is memory managed across both runtimes? 5. What is different from KMP? 6. What is it like to write? How Swift runs on Android 14 / 60
The SDK officially released in Swift 6.3 • Share code with • SPM dependency for iOS • Maven or project dependency for Android • Over 25% of Swift Packages can be built for Android (As of Oct 2025) How Swift runs on Android 15 / 60
do • Working on iOS and Android • Sharing business logic What cannot do • Sharing UI related code • Using Apple platform or UI related libraries How Swift runs on Android 16 / 60
Shares Logic only UI only Both Skip (Lite) Swift Kotlin Skip (Fuse) Swift SDK for Android KMP CMP Flutter Other React Native How Swift runs on Android 17 / 60
Link NDK on cross-compiling Swift code • Share pre-built Swift runtime files So the compiler can emit a shared object (.so) to work on Android via JNI How Swift runs on Android Native Development Kit (NDK) Build C/C++ native code for Android Java Native Interface (JNI) Kotlin / Java call C/C++ native code for Android 18 / 60
they required? • NDK • Provides Android s C library, headers and sysroot • The Swift compiler needs them to emit Android binaries • Swift Runtime • Android has nothing that can run Swift code ’ How Swift runs on Android 19 / 60
does Swift SDK for Android provide? 3.How does Swift run on Android? 4. How is memory managed across both runtimes? 5. What is different from KMP? 6. What is it like to write? How Swift runs on Android 23 / 60
package swift build --swift-sdk aarch64-unknown-linux-android28 Target triple: <arch>-<vendor>-<os>-android<api_level> arch : one build per supported ABI vendor : unknown on Android (apple on Apple platforms) os : linux (macosx14.0 for Mac) api_level: Equivalent to minSdkVersion → Resolve Swift runtime & NDK paths by swift-sdk.json How Swift runs on Android 26 / 60
Swift from Kotlin / Java? jextract in swift-java • Call Swift from Kotlin / Java • Analyze Swift code • Generates Swift wrapper for JNI & Java caller code • Named after OpenJDK s jextract (C → Java) ’ How Swift runs on Android 27 / 60
code for JNI @_cdecl("Java_yutakahashi_TestPackage_TestTarget__00024myFunc__Ljava_lang_String_2") public func Java_yutakahashi_TestPackage_TestTarget__00024myFunc__Ljava_lang_String_2( environment: UnsafeMutablePointer<JNIEnv?>!, thisClass: jclass, Just wrapping the name: jstring? original function ) -> jstring? { return TestTarget.myFunc(name: String( fromJNI: name, in: environment )).getJNILocalRefValue(in: environment) } How Swift runs on Android 29 / 60
code public final class TestTarget { ... public static java.lang.String myFunc(java.lang.String name) { return TestTarget.$myFunc(name); } } ... Call Swift function in .so How Swift runs on Android 30 / 60
import yutakahashi.TestPackage.TestTarget val greeting = TestTarget.myFunc(“Kotlin") println(greeting) // “Hello, Kotlin!” How Swift runs on Android 31 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4.How is memory managed across both runtimes? 5. What is different from KMP? 6. What is it like to write? How Swift runs on Android 33 / 60
Swift manage memory? • Automatic Reference Counting (ARC) • Counts references & frees on zero • Reference types (class) • One instance = a and b point to the same thing • Managed by ARC • Value types (struct) • Copy on assign = a and b become separate values • Not managed by ARC How Swift runs on Android 34 / 60
think… "Swift is compiled to native code, so the GC has nothing to do with it.” Not quite. What Kotlin holds is a Java object that lives on the Java heap. Java heap Native heap Calculator Calculator reference Store memory address The actual instance Managed by GC Managed by ARC How Swift runs on Android 35 / 60
everything at once when the scope exits SwiftArena.ofConfined().use { arena -> HogeClass.init(arena) } // Dispose the class instance How Swift runs on Android 37 / 60
automatically determined by Java GC private val arena = SwiftArena.ofAuto() // no explicit closing val hoge: HogeClass = HogeClass.init(arena) fun onTapButton() { val result = hoge.doSomething() println(result) } How Swift runs on Android 38 / 60
top-level functions in Swift Why No self. No Swift instance to keep alive. import yutakahashi.TestPackage.TestTarget val greeting = TestTarget.myFunc("Kotlin") How Swift runs on Android 39 / 60
Java code public final class Calculator implements JNISwiftInstance { ... public static Calculator init(SwiftArena swiftArena) { return Calculator.wrapMemoryAddressUnsafe(Calculator.$init(), swiftArena); } } public long plus(long lhs, long rhs) throws SwiftIntegerOverflowException { return Calculator.$plus(lhs, rhs, this.$memoryAddress()); } private static native long $plus(long lhs, long rhs, long selfPointer); ... How Swift runs on Android 41 / 60
code import yutakahashi.TestPackage.Calculator import org.swift.swiftkit.core.SwiftArena SwiftArena.ofConfined().use { arena -> val calculator = Calculator.init(arena) val result = calculator.plus(1L, 2L) println(result) } How Swift runs on Android 42 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4. How is memory managed across both runtimes? 5.What is different from KMP? 6. What is it like to write? How Swift runs on Android 43 / 60
for Android Shared code Kotlin in shared module Swift in an SPM package Android side Kotlin, compiled with the app .so, called through JNI iOS side a framework, called through Obj-C Swift, compiled with the app App projects Generated by the template Prepared by yourself How Swift runs on Android 44 / 60
SDK for Android Already have an Android app an iOS app Sharing UI Possible with CMP Not possible Maturity Since 2023 Since 2026 APK size Minimal approx. + 80 MB How Swift runs on Android 45 / 60
does Swift SDK for Android provide? 3. How does Swift run on Android? 4. How is memory managed across both runtimes? 5. What is different from KMP? 6.What is it like to write? How Swift runs on Android 49 / 60
projects (on local) 1. Make your SPM product .dynamic, so it produces a .so 2. Add gradle.properties and settings.gradle 3. Copy build.gradle from swiftlang/swift-android-examples How Swift runs on Android 50 / 60
projects 4. Publish swift-java to your local maven repository, because swift-java has not been available in Maven Central yet. ./gradlew --project-dir … :SwiftKitCore:publishToMavenLocal How Swift runs on Android 51 / 60
perfectly • Nested arrays of custom types • [[String]] works fine, but a custom one like [[MyStruct]] does not • #if DEBUG • Not wired to the Android build type, so a debug-only path can ship • 3rd party libraries (e.g. Alamofire) • Builds and runs, but OS-dependent features do not How Swift runs on Android 55 / 60
{ public let name: String public let age: Int } public func getGroupedUsers() -> [[User]] { [ [ User(name: "Yu Takahashi", age: 23) ], [ User(name: "Taro Droid", age: 23), JExtractSwiftLib/JNISwift2JavaGenerator+NativeTranslation.swift:103: Assertion User(name: "Hanako with Swift", age: 23), failed: Not synchronized JavaTranslation, User[][] != long[][], ], name=getGroupedUsers ] } [98/101] Generate Java wrappers for Swift types How Swift runs on Android 57 / 60
Most unsupported things fail at Swift build time • Unable to set breakpoints to the Swift code • Logcat does not capture Swift s print() #if os(Android) import Android func print(_ items: Any..., separator: String = " ", terminator: String = "") { let message = items .map { String(describing: $0) } .joined(separator: separator) + terminator __android_log_write(Int32(ANDROID_LOG_DEBUG.rawValue), "Swift", message) } #endif ’ How Swift runs on Android 58 / 60
not covered every Swift type yet • SPM packages may not provide full functions for Android • Outside a monorepo, every shared-logic change needs a tag and two dependency updates Practical use cases • Turning a shared core used by several apps into an SDK • Sharing logic between an iOS and an Android app in one monorepo How Swift runs on Android 59 / 60
and ships a prebuilt Swift runtime • That is enough to compile Swift into .so for Android How Kotlin calls it • swift-java generates Java bindings that call the .so through JNI Memory • The GC manages the Java wrapper, ARC manages the Swift instance • SwiftArena decides when the Swift instance is released Compared to KMP • KMP can share UI with CMP, the SDK cannot and UI stays native on both sides • They can coexist, add the Swift package to both projects in a KMP repo • The Swift runtime adds roughly 80 MB to your APK How Swift runs on Android 60 / 60