Improving Swift support and interoperability experience for Android

Hey everyone,

Over the past several weeks @compnerd and I have been working on improving Swift support for Android. We now can build Android standard library on Windows (Linux still works as well!), and we now can also build Swift test programs for Android that use C++ interoperability and depend on NDK’s libc++.

As part of this work I have added a new ‘Android’ module to Swift’s standard library. This module imports Android’s C standard library (Bionic) and some other posix and Android APIs into Swift. Additionally the ‘Bionic’ clang module can also be imported into Swift to access the C standard library APIs without pulling in the other Android and posix APIs. The support for the ‘Glibc’ module for Android is removed. These overlay changes are not yet merged, so please provide any feedback that you might have here:

I would like to merge these changes in the next week or two.

Now that these changes are ready, we will be starting to explore how to let Java/Kotlin use Swift APIs. We would like to have a level of interoperability that lets Java/Kotlin invoke a subset of Swift APIs in an effective and ergonomic manner. Please let us know if you have ideas for how such interoperability should look like and/or work!

We would like to see Swift for Android succeed, and we think that as part of that Android should start to move in the direction of being a supported platform that Swift can target. More specifically, it would be great if there was a way to set up a pre-commit CI for Android, in addition to currently existing post-commit CI (https://ci-external.swift.org/). What do other community members think of that idea?

40 Likes

Yes please! This would be absolutely wonderful.
I'm all for Android being a supported platform. It deserves some resources and would strengthen Swift as a language choice similar to how Windows did.

2 Likes

This is great to see, Alex!

I tried playing around a bit with the Android build a couple months ago but struggled to get a compatible working toolchain. Is there a good reference for how to set up an environment from scratch to compile a sort of “hello wold” and run it in an emulator? Maybe in a docker container or something like that?

1 Like

Great, good to see more people working on Android support again.

This would require some small changes to the few current Android users' packages, but is the right move for the future. Pinging @drodriguez, @Geordie_J, @mstokercricut, and @johnburkey, as they've all tried building for Android in the past. Let us know if you are okay with making this change with Swift 6.

That would be great. I discussed moving Android from the community CI to the official CI, but keeping it post-commit, with some members of the core team last November. They OK'ed the move, but I've since been bogged down with some non-tech work at home since December and have done nothing for that move to the official CI, using my lessened time for smaller items like upstreaming the nullability annotation changes for NDK 26.

If you want to set up a pre-commit official CI instead, that would be even better, and I'd be happy to discuss the ins and outs of setting that up, if you'd like.

Have you tried the official Android doc? I wrote a lot of that, let me know if it doesn't work in some way.

3 Likes

I built a swift 5.8 GitHub Action change using a lot of @Finagolfin 's excellent work for examples, and added it to alamofire for android. I need to update my tool chains since it's been a bit but I would love to do this with newer tool chains.

I've built entire apps for android with swift doing rendering and business logic with minimal interoperability surfaced up to the JVM side. I plan to continue doing that once my need for android arises again. I know it's possible and a joy once you get it working well.

Would love to see this process continue to improve

6 Likes

We are not planning to cherry-pick these changes to Swift 6, so they would be aligned with the release after Swift 6.

I think improving the state of the post-commit CI is the right first step, so it's great to hear you're already working on it! I don't have much insight into setting up a pre-commit CI yet, but I'll do some digging into the current post-commit CI setup to understand it better before we propose a concrete action plan for pre-commit CI.

Why not? Your changes are limited to Android and so far no Android users have complained.

The current post-commit community CI simply compiles the Android stdlib on linux and then runs the compiler validation suite in host test mode, ie skipping the 1k executable tests that would need to run on Android.

It has been broken for more than a month because it doesn't have a prebuilt Swift toolchain installed, and Swift trunk is currently broken when bootstrapping on linux, pretty much requiring a prebuilt host toolchain at this point.

I plan to get that running on the official CI by installing a prebuilt Swift toolchain for linux, then expanding it to run the executable tests in the Android emulator, before getting it to cross-compile the corelibs like libdispatch and foundation for Android also, the last of which my daily Android CI has been doing for years.

We can use that post-commit CI config for a pre-commit CI when we feel it's ready.

2 Likes

This all sounds great! I plan to add Android support to FlutterSwift, perhaps I'll wait for this to land.

1 Like

Good point! We don't need it in Swift 6 ourselves, but it sounds like the community would benefit from this change being in Swift 6. It does make sense to switch from Glibc to the Android module now in Swift 6, since it will be a major release, and thus anyone who depends on Glibc for Android now will know that there's a clear boundary that denotes when the Android module is introduced.

I will put up the PR to cherry-pick the Android overlay changes to the Swift 6 branch this week, and will ask the release owners to sign off on it.

7 Likes

I’m all for improving correctness. It’d be simple to update our code accordingly!

I do feel like there are multiple layers that could be targeted here. At the bottom, improving Swift’s interoperation with JNI would be one direction to go: declaring native functions, or at least a standard JNI_OnLoad; non-copyable and non-escaping wrappers for low-level JNI types; support for the JVM’s Modified UTF-8; providing a convenient way to spell JVM type signatures; and perhaps even generating APIs from class files. A level up from that might be direct support for Kotlin coroutines in some way, and other Kotlin-isms that work better in Swift than they do in Java. Finally, you also have everything in the Android SDK—how much of that can be nicely wrapped in a way that makes it more idiomatic for Swift? (Without trying to make it a UIKit clone.) Any such effort is necessarily incomplete, i.e. an app developer will probably have to drop back to raw Java calls at some point, but that doesn’t mean it’s not useful to have it in one place instead of everyone building their own wrappers.

(I don’t work day-to-day on Android specifically, but I am on a team that maintains a Rust library with JNI-based bridging. The Rust jni crate is much nicer to work with than the raw C API.)

5 Likes

As a junior dev I built a somewhat incomplete and admittedly fairly inconsistent JNI wrapper in the era of Swift 2/3. We’re still using 8+ years later in production GitHub - SwiftAndroid/swift-jni: Wrap JNI functions (WIP)

I’m in the process of starting a new app project at the moment, so 90% of my energy is going into that. I would love to revisit Swift JNI someday though now that I have more experience and now we have more Swift features available to us. In the meantime it might be interesting for someone to play around with improving it.

Since you mention it in passing, we also built a large chunk of UIKit for Android that we’re also still using for cross platform purposes. We are a small company so never had a lot of resources to dedicate to these projects full time, but they do what they’re supposed to quite well :slight_smile:

3 Likes

Excited to see Android support improvement. Currently is building android standard library only supported Linux and Windows or is it supported for macOS as well?

Great, good to know. :slight_smile:

People have been building it on macOS for a long time, but the official doc instructions I linked a couple weeks ago have only been validated on linux. If you want to try them on macOS, I recommend using the Homebrew OSS toolchain.

3 Likes