Improving Swift support and interoperability experience for Android

For the record, here is a destination.json that can be used with the Homebrew-installed toolchain. You can substitute /opt/homebrew/share/android-ndk for your own NDK location and /opt/homebrew/Caskroom/swift-android-toolchain@6.0.1 for your own SDK download location. You shouldn't have to specify any additional linker flags from the command line.

{
  "extra-cc-flags" : [
    "-fPIC"
  ],
  "extra-cpp-flags" : [
    "-lstdc++"
  ],
  "extra-swiftc-flags" : [
    "-tools-directory",
    "/opt/homebrew/share/android-ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin",
    "-resource-dir",
    "/opt/homebrew/Caskroom/swift-android-toolchain@6.0.1/6.0.1/swift-6.0.1-RELEASE-android-sdk/usr/lib/swift",
    "-L",
    "/opt/homebrew/Caskroom/swift-android-toolchain@6.0.1/6.0.1/swift-6.0.1-RELEASE-android-sdk/usr/lib/aarch64-linux-android",
    "-I",
    "/opt/homebrew/Caskroom/swift-android-toolchain@6.0.1/6.0.1/swift-6.0.1-RELEASE-android-sdk/usr/lib/swift/clang/include"
  ],
  "sdk" : "/opt/homebrew/share/android-ndk/toolchains/llvm/prebuilt/darwin-x86_64/sysroot",
  "target" : "aarch64-unknown-linux-android24",
  "toolchain-bin-dir" : "/opt/homebrew/Caskroom/swift-android-toolchain@6.0.1/6.0.1/swift-6.0.1-RELEASE-android-sdk/usr/bin",
  "version" : 1
}
2 Likes

As part of this, does anyone have a good CI integration for Android builds, especially on GitHub? compnerd has a nice action setup method that can be used with multiple Swift versions for Windows (compnerd/gha-setup-swift), it would be great if something similar existed for Android.

1 Like

That should also enable android builds :slight_smile:. We are using it for cross-compiling to Android. If you would like an example to see: GitHub - thebrowsercompany/swift-firebase: Swift Interface for Firebase should provide one where we build the Swift library for Android in GHA.

Just on a Windows host, right? Workable for open source projects, though slower, but expensive for anyone who pays for minutes.

Looking at the example, it looks like the cross compilation is done with cmake? Is there a way to do it with a simple swift build command, like Windows itself?

No, no reason it would have to be limited to Windows. The TBC builds don't have a Linux toolchain currently (but are working on the macOS toolchain builds). That would allow a different host to use the same mechanism.

The cross-compilation support in SPM is not as fleshed out as CMake's support is when I last tried. You might be able to build out the necessary destination.json for it, but I don't know the state of that support very well.

I plan to add one after releasing an Android SDK bundle for Swift 6. It will definitely work on linux and mac CI, and I will try it on Windows at some point.

2 Likes

Yes, check out the Swift Android Action. We discuss it in our recent Native Swift on Android blog post.

The standard usage is to build and test a Swift package for each of macOS, iOS, and Android from a single workflow. I have a variety of popular packages that are successfully running tests cases with it, such as swift-algorithms, swift-syntax, and swift-numerics. And we will soon be submitting a PR to the Swift Package Index to add Android to their build matrix in order to facilitate the addition of Android support for your packages.

Exciting times!

4 Likes

how far along are you? any ETA's?

Marc put together a pull for the CI to start packaging multi-arch SDKs, which you can download and use just like the doc says for the last 5.10 multi-arch SDK. I recommend the latest Swift 6.0 Oct. 8 snapshot tag, as SwiftPM 6.0.1 had an Android-specific bug that required modifying the executable to use, which is fixed in that 6.0 snapshot and in the upcoming 6.0.2 (you'll need to download the official Oct. 8 snapshot toolchain build for mac or linux from swift.org also).

As for the final SDK bundle, probably this weekend, if nothing else comes up.

1 Like

I just posted a Swift 6 SDK bundle for Android, my first time creating an SDK bundle and its creation is completely scripted on my CI. It really makes cross-compiling with Swift much easier, thanks to @Max_Desiatov and the other SwiftPM devs who designed and implemented that SDK bundle feature.

Try it out with your Swift packages and report any feedback on my repo. It is the first release with the new Android overlay that Alex started this thread about almost six months ago, thanks to him and his collaborators for getting that in.

11 Likes

I needed to get onto this before @Finagolfin and @marcprux beat me to it ;)

I've successfully built swift-java with the Swift Android SDK.

Extremely WIP branch is here. My goal is to integrate this with FlutterSwift.

14 Likes

This is extremely exciting, thanks for your work here @lukeh :slight_smile:

We're looking forward for this all to converge nicely and become a viable option for folks! :tada: If you bump into any issues please ping us here or on the github repo :+1:

7 Likes

The diff is tiny. :upside_down_face: Lots of cleaning up to do, but when I have something that's suitable for upstream consumption I'll file a PR.

4 Likes

Glad to hear it, but I wasn't planning on trying to port that repo any time soon. The main reason I'm using Swift on Android is that I don't want to use Java, and I don't have some legacy Java codebase that I need to integrate with. I'm happy to use this new swift-java effort for the few Java-only Android system APIs that I'm forced to use and will contribute back where I can, but it's not something I plan to use much.

In other news, I just posted the Swift 6.0.2 Android SDK bundle, and am currently looking into making sure a subsequent version works well with C++ interop.

Hey, first thanks for all your work on swift-android.
Your comment made me wonder : on android, what are you using to communicate between your business logic (in swift) and the UI layer of your app ? I was under the impression that having to call at least a bit of java APIs wasn't an option on android.

1 Like

No plan to use Java here either (or even Kotlin, which incidentally appears to be quite Swifty). But it's a necessary evil to integrate with Flutter. (And yes, I'm using your 6.0.2 SDK.)

1 Like

:+1:

I don't, as I've never used Swift in an Android app myself, only been porting it and building command-line executables so far. I was thinking of using some Swift GUI or Swift-wrapped C GUI layer for OpenGLES, as many Android games do (they don't use Swift, of course, but their own C/C++ OpenGLES-backed GUIs), and cutting Java out of the GUI too. I have written small prototype apps in other non-JVM, AoT-compiled languages before using this approach.

Yes, most Android system and framework APIs are only in Java, so if I want to access something like Bluetooth, I will have to call those Java-only Android APIs. I hope to keep such Java usage to a minimum.

Another approach:

Flutter uses platform channels to separate UI code written in Dart from business logic written in a native language. (It does also support FFI, but this is harder to use.) If you can live with the serialisation overhead, it provides a very straightforward interface between the two.

(FlutterSwift is, at least on non-embedded platforms, essentially just a Codable serialiser for platform channels.)

1 Like

Awesome!

Doug

1 Like

New WIP: AndroidLooper, allows you to schedule structured concurrency tasks on Android run loops. @UIThreadActor is equivalent to @MainActor. (Could probably support Foundation run loops as well, if required.)

10 Likes