Swift and SwiftUI are Apple’s recommended technologies for app development, and with good reason. Their emphasis on safety, efficiency, performance, and expressiveness have made it easier than ever to build fast, polished, and robust apps for the Apple ecosystem.

Recent stories about Swift on Windows, Swift on the Playdate, and a SwiftUI-like library for Gnome highlight some of many the ongoing projects to expand Swift and SwiftUI’s reach beyond Apple devices. One effort that hasn’t received much publicity, however, is Swift for Android.

Dedicated members of the Swift community have been working on a native Android toolchain for some time, and they are making very encouraging progress. If you’re a mobile developer, the arrival of such a toolchain would be exciting news indeed! Mobile devs are currently in a no-win situation: you must either write every app twice, leave half the market unaddressed, or accept the stark tradeoffs inherent in most of today’s cross-platform solutions. The prospect of running Swift programs on Android sounds like a promising alternative.

From Programs to Apps

1> print("Hello World")

Unfortunately, there is a large gulf between a program and an app. A native Android toolchain would include the Swift language, the Swift standard library, and portions of Foundation. This means that only business logic is guaranteed to be supported out of the box. For everything else your app needs - UI, platform services, third-party libraries, and so forth - you would have to rely on Swift’s ability to interoperate with C and C++.

Using any sort of bridging between software layers can be difficult: impedance mismatches abound. But the situation on Android is additionally complicated by the fact that Android apps run on the Java Virtual Machine (JVM). From system utilities to the user interface, the vast majority of Android frameworks are JVM-based. Swift can take advantage of C’s Java Native Interface (JNI) to communicate with JVM objects, but this introduces yet more complexity and inconvenience. And have we mentioned that Jetpack Compose, Android’s modern UI framework, has its own compiler and runtime that make it almost impossible to use from JNI?

Skipping Ahead

It would appear that while native Swift on Android is tantalizing, the goal of easily sharing a Swift codebase between iOS and Android apps is far off. The Skip team, however, is making significant advancements on this front.

Cross-platform development in Xcode

Skip is a tool for building cross-platform iOS and Android apps from a single Swift and SwiftUI codebase. Skip currently works by transpiling your Swift source to Android’s native Kotlin development language using Apple’s SwiftSyntax parser. It bundles the generated Kotlin with a suite of open source Swift Package Manager modules that mirror standard iOS frameworks on Android, including a module that adapts your SwiftUI to Jetpack Compose. Skip’s Xcode plugin leaves your source code untouched on Apple platforms, but generates, packages, and compiles the equivalent Kotlin and Jetpack Compose code alongside it, on every build. One Swift and SwiftUI codebase, two fully native apps.

Diagram of Skip's Swift-on-Android build process

Transpiling to Kotlin maximizes interoperability: you can call Kotlin and Java API directly from your Swift, with no bridging required. But it also comes with limitations and behavioral differences that you must always keep in mind. Your logic may be written in Swift, but when it runs on Android, it runs as JVM code.

We believe, therefore, that using the native Swift toolchain will be the best long-term strategy. And we are happy to announce that internally, we have successfully integrated key aspects of our technology with compiled in addition to transpiled Swift. This includes the ability to transparently call Kotlin and Java API from Swift business logic, and even to create Android UI using Skip’s ever-expanding SwiftUI support!

struct DemoView: View {
    #if os(Android)
    let message = "Android Native"
    #else
    let message = "iOS Native"
    #endif
    @State var rotation = 0.5

    var body: some View {
        VStack {
            Text(message)
                .font(.largeTitle)
            Text(verbatim: "😀")
                .font(.system(size: 100))
                .rotationEffect(.degrees(-180 + 360 * rotation))
                .padding()
            Slider(value: $rotation)
            Button("Reset") {
                rotation = 0.5
            }
            .buttonStyle(.bordered)
        }
        .padding()
    }
}

The video below depicts a modified version of “HelloSkip”, our most basic SwiftUI sample app, running on both iOS and Android. We’ve replaced the app’s middle tab with the DemoView above. But while the rest of the app is being transpiled for Android, DemoView is being compiled for Android instead! Using Skip technology, the compiled view is able to interact with the JVM and with Jetpack Compose to power the Android emulator as well as the iOS simulator:

It is important to point out that even with Skip, “going native” is not without its downsides. When new versions of Swift become available, the Android version may lag behind. Android app binaries will also be significantly bigger than Skip’s transpiled apps, because they must bundle native Swift libraries. Debugging native code will - initially, at least - be more difficult than generated Kotlin. And finally, bridging to Android’s vast ecosystem of Java and Kotlin libraries will be more complex and will incur JNI’s performance costs. Skip will generally be able to hide this complexity, and our initial tests indicate that JNI overhead is minimal for most use cases. But these are tradeoffs to be aware of.

Present and Future

Swift and SwiftUI are often associated with development for Apple devices, but their principles and paradigms are universal, and their use beyond Apple platforms is spreading. Thanks to the hard work of the Swift community, a native toolchain for Android is emerging. It will take time to fully develop, and more time to prove itself stable enough for general use. Even then, it is only the first step towards the dream of writing cross-platform Swift and SwiftUI apps.

Skip realizes that dream now, using Swift-to-Kotlin transpilation. But we are also dedicated to fully supporting a native future. The transpiled Swift and SwiftUI apps you build with Skip today will become your compiled Swift and SwiftUI apps of tomorrow!