Swift for Android: Call for the Community

linux SPM with droid target lets you use various AWS plumbing for builds: lambda, code build, etc. - so we like that.

I haven't seen this problem on Android generally- though I have not yet built a Swift shared library to invoke from a regular Java GUI app, only command-line executables so far- but if you open an issue on my Android SDK github repo, maybe we can dig into it there.

I just got a report that Swift executables that work on Android up through version 10 stop working on Android 11: anybody else seeing issues with running Swift on the latest Android 11 release?

I had a try to use "Hello World" project with Dispatch, Foundation, Networking and ProtoBuffers routines on Android 11 Simulator. The application works as on, say, Android 8 Simulator. No differences.

1 Like

Given the work being done on #swiftwasm I believe @Max_Desiatov has noted that this could be leveraged for Android also. Feels like a consolidated conversation would be good... over zoom, drinks?

2 Likes

I don't want to hijack this thread with a more abstract discussion, but I'm personally most interested in seeing Swift directly compiled to JVM bytecode. I'm convinced there's some non-trivial overhead in JNI, both in performance and developer experience. E.g. if your Android application crashes in Swift parts of code, you don't get a consistent stack trace across the JNI bridge out of the box. Attaching with a debugger and crossing the bridge also doesn't work smoothly, as far as I understand.

Compare this to Kotlin, which can be currently compiled to JVM bytecode and interact with other JVM languages with little hassle. At the same time Kotlin can be compiled to native code on iOS and other platforms. Essentially, Kotlin feels like a first-class citizen on all platforms (modulo the Xcode integration), while Swift on Android has enough caveats due to which it doesn't compare as favorably.

At some point I want to prototype a compiler backend that lowers SIL to JVM bytecode. There's an argument to be made that Swift value types don't map really well to JVM objects, but I didn't see a good explanation for why it can't be done in principle. For example, ARC and CoW could be implemented on top of sun.misc.Unsafe API. I don't know if that's the best approach, but I guess we won't know until we try. If anyone is interested in this or has already done a similar investigation, please get in touch.

11 Likes

Afaik, Kotlin made some compromises for Java-compatibility, just like Swift was influenced by its Objective-C legacy...so I'm pretty pretty sure bringing both worlds together will not only be a really challenging task, but it might also be impossible to clean up all rough edges.
On the other hand: GitHub - davidar/lljvm: Low Level Java Virtual Machine
It would be pretty cool to have the JVM as a supported architecture for llvm...

1 Like

For the bytecode peoples, some questions:

  1. In what use cases would this idea perform better than Kotlin?
  2. How would you call the swift runtime from the byte code? (JVM byte code ABI is not host compatible)
  3. Would ARC / GC interactions be desirable ?
  4. Is there another way to ease Java<--JNI-->Swift code interactions?

The use case is existing Swift codebases that aren't easy to port or develop with JNI. Too frequently in my consulting experience clients ask for an app for multiple platforms with a single codebase, or a codebase where the majority of the code (especially the UI code) is shared. When I suggest a dedicated native app for iOS built in Swift and separate codebases for other platforms to them, most frequently they aren't even open to this idea. It's easier for them to go with React Native, Flutter, or multiplatform Kotlin than to invest in a Swift codebase, substantial amount of which currently can't be shared between mobile platforms and their frontend web apps.

The main goal is to perform not worse than Kotlin. If it turns out to be better, I'd be very satisfied, but becoming "good enough" is a fine goal in itself, in my opinion.

Isn't Kotlin runtime compiled to JVM bytecode? If so, Swift runtime has to be bundled in the same way for this to work well.

Too hard to say at such an early stage. We would need to understand what interactions are important in the first place.

I don't know of any that would make Swift as easy to use as Kotlin on Android.

On point (2), all the JVM languages use JNI to call native, with the exception of some semi exotic runtime stuff companies like Apple have done in the past to "auto jni" which is to generate shims to allow easier function calling to native. The point is - swift code converted to byte code wouldn't be able to call native code anymore- and much of the swift libs are c/c++. In our case we have very large C++ libraries that we pull with us. Those would all now be uncallable. So we want to think through that part of this.

On point (4)- I think its best to talk about how people like to make UI's in Android at this time. What's your favored way to make Android UI? How might Swift play in that fishtank ? The byte code stuff is interesting- but another thing is playing nicely with the high productivity tooling.

Our use is the following (WIP):

  • we use Flutter for the UI (iOS, Android, and we target Linux someday)
  • we use Swift for the mobile backend ( the business logic layer, data layer and network layer)

Flutter communicates with the platform via Channels and the platform code communicates via JNI on Android.

We chose this architecture because we know and love Swift, an Flutter because we are too small of a team to support 2 code bases for 2 platforms.

1 Like

ion - Did you write a channel pump to push the channel handler that lands in java to swift for Droid?
Or do you see that one would be useful ? And then your swift code would look the same on both platforms?

From my own experience... Our business has chosen Xamarin. Some places keep development resources "sparse". Also, DevOps is still not a thing for some companies. Packaging and deploying is still manual. I was a purist for a while but when you have to deliver product based on timelines... reducing effort through reducing languages can be important for delivering value for customers.

My $0.02, I'd rather have swift on everything. If JVM bytecode could be a target, why not move down that path?

1 Like

We have swift on Android. The question is it integrated with the ways and means to make high quality UI on Android. It currently isn't. And further, if you moved Swift to bytecode, it would no longer be able to call its c & c++ based runtime libraries. JNI exists for a reason- the Java ABI isn't compatible with the host OS Abi. So let's not think getting a bit of Swift on byte code takes us the whole way.

SwiftUI isn't going to be on Android. Flutter seems to provide great UI on both platforms. Perhaps getting Swift to work with Flutter might show the way a little further. Take ion's use case, and add a channel bridge so the swift code gets the channel "endpoint".

There are other things that can be done. An async message handler with endpoints in both languages would be easy to do, it could be FlatBuffers, protobufs, etc. Better to think ahead to what would work, and what would enable high quality apps. Then act.

2 Likes

And thanks A TON to VGorloff and Buttaface!

Making an implementation of the SwiftUI API available on Android is my personal end goal. In Tokamak we already provide a subset of the SwiftUI API with renderers for WebAssembly and GTK. Architecturaly, assuming that we can seamlessly call Android UI APIs (say Jetpack Compose), I don't think anything would prevent implementing a renderer for Android. With that working one could then write multi-platform SwiftUI apps that work on Android.

10 Likes

How does JJLVM differs from the new Kotlin JVM IR compiler? Starting from Kotlin 1.4.20 and beta in 1.4.30, all Kotlin code will be first translated into IR code and then into JVM bytecode/JS code, iOS native code.

The JVM languages use JNI to communicate to their C/C++ runtime libraries.... JNI is there both because the ABI doesnt match and because you have to let the GC know you are messing with its memory. The point is you would have to put JNI interfaces at all the runtime swift <--> c/c++ boundaries..

This is already true for Java, Kotlin, Scala, or any language targeting JVM for that matter. For me personally that wouldn't be a downside when comparing a hypothetical Swift compiler JVM target to existing compilers of those languages.

If that's a downside for you, I don't think I ever mentioned that you should abandon your current approach. I'm not proposing a replacement for it, just an alternative.

Either way, I think that targeting JVM bytecode directly is off-topic in this thread. Apologies to the OP for polluting it. If anyone is interested in continuing the discussion of a hypothetical JVM bytecode target, please create a separate thread for it. Thanks!

Max, just helping you guys see the way ahead. The point is the JVM languages all call into the java runtime and libraries that were built when we made the runtime at Sun, and Google subsequently copied it from the open source quite a while ago. As Google then added Android specific libraries, they made JNI shims for each of them. That's why all that stuff works. Because swift has its own runtime libraries, that weren't built with that in mind, that would have to be added, and maintained. At Apple in the old days, we had an auto JNI feature (JDirect) for calling native functions. Maybe you guys can whip something like that up.