Ask HN: Best language to share code between an Android and iOS app?

116 points by mevorah ↗ HN
Hello app developers of HN!

My team owns an Android (Kotlin) and iOS (Swift) app. The app is responsible for processing data, submitting to ML models, and then displaying results in a UI. We chose to do a lot of that processing in a shared Rust component. What we have found is a high overhead of bridging Kotlin/Swift to Rust. Some core logic has also seeped into our bridging code resulting in some duplication (exactly what we were trying to avoid).

With that, those of you who have found yourselves in similar situations, which language would you choose to be shared between your Android and iOS app (if any)?

122 comments

[ 3.5 ms ] story [ 206 ms ] thread
I use c++ rather than rust because as much as I would love to use the best language its just not so well supported on mobile compared to c/c++. I'm not sure how well flutter ffi does using rust compared to more mainstream approaches its possible that flutter ffi is more friendly to rust than jni/kotlin.
One way would be to host a script engine and run the script language, e.g. JavaScript. Another would be to create your own grammar and simultaneously translate to Kotlin and Swift. You could even use a strict subset of either Kotlin or Swift then you'd only have to deal with one translator.
In Go, there is an official, experimental project called gomobile [0] that allows one to generate a Java or Objective C binding to be used in mobile projects based on Go source code.

It comes with some restrictions and is still deemed experimental. But it could be a viable choice in the days to come.

[0] https://github.com/golang/mobile

Gomobile bridges Java and ObjectiveC/Swift to Go, and probably entails the same overhead the author is trying to avoid.

Shameless plug: If you like Go and immediate mode UIs in particular, Gio[0] runs the same Go code across desktop and mobile alike. No bridging or native code required.

If you like a more mature framework and don't mind Dart, I think Flutter is an attractive toolkit. I started Gio wanting to write a Flutter clone in Go before going for the immediate mode design.

[0] https://gioui.org

I'm not an expert but you could consider sharing Swift (or Kotlin) code between platforms. Nim (https://nim-lang.org) could also be explored.
You can't really share that between platforms.
Ah shame, I remember reading about targeting iOS at least with nim but didn't look to closely into it.
Came here to mention nim that I've followed with great interest. As it compiles to C you can probably use it just about everywhere.

As far as android support this guy is working on adding support to android via Dalvik assembly. The usual approach to get nim to work with android would be JNI but that might cause problems for example with x86 android machines if I am not mistaken. https://github.com/akavel/dali

Nim generates C, C++, Objective-C and js - so yes, you can target Android and iOS
Right, thought so. Thanks.
I did one cross iOS/Android platform project using Kotlin/Native with its MPP plugin with reasonable success. However, this was 6 months ago and the JetBrains people surely haven‘t stopped moving forward.
Just use JavaScript.

Javascriptcore is a lightweight way to execute JavaScript on iOS and you can use V8 context or duktape on Android. This way you can also update code in your app without an app store update.

which is not allowed on iOS ...

Edit: Sorry for being unclear, was only referring to the updating JS on the fly and circumventing App Store part. Obviously (facepalm) ... ️

Which part isn't allowed? A project I worked on did this a few years ago.
I think there is some confusion around this. You can use Javascript with iOS if you use Webkit + JavaScript Core, and ship all your features in the binary that your app uses.

2.5.2 "Apps should be self-contained in their bundles, and may not read or write data outside the designated container area, nor may they download, install, or execute code which introduces or changes features or functionality of the app, including other apps."

and

4.7 " your app must use WebKit and JavaScript Core to run third-party software and should not attempt to extend or expose native platform APIs to third-party software"

What specifically is not allowed? Microsoft provide CodePush as a service which allows you to push updated JavaScript bundles to Android and iOS apps.
It is totally allowed on iOS.

Perhaps your thinking about downloading such JS code at runtime from your servers, thus escaping Apple's control on the app, which was indeed forbidden (it is now ok as long as you don't drastically change the app)

Bundling JS in the app and running it has always been just fine.

Supporting a JS Engine is non-trivial. See React Native and Native Script. For example stacktraces etc.

With C++ in both Android Studio and X-Code you can put break points in the same IDE.

With JS you would use the browser to debug JS code, and Android Studio and X-Code to debug the native code. That split can be annoying.

I guess if the team that supports the JS engine is sufficiently large, i guess you can get more out shared JS code. The majority of the devs should be able to focus on JS development only. And a couple of specialists deal with "JS engine issues".

I have great success using Kotlin Multiplatform to share code between iOS and Android. Have a look at my Android Jetpack Compose and iOS SwiftUI project sharing the common logic for a game https://github.com/SimonSchubert/Braincup
It's worth to mention that it also supports native Linux, Windows and macOS buildings. Plus web via JavaScript and server via jvm.
This is really cool. Care to share some resources from which others can learn to get started?
This is the official docs

https://kotlinlang.org/docs/reference/multiplatform.html

I've also done multi platform recently.

I've taken a contract first approach. Swagger / openapi for rest clients. Outside of that I use vertx which has bindings for almost every platform. With those two I can account for interoperability across all platforms.

Big hitches

* No ts.d defintions at this time. But: https://github.com/vojtechhabarta/typescript-generator

* Dukat for automatic typescript definition importing (beta) https://github.com/Kotlin/dukat

* I've not done LLVM iOS. But I've read of some generic issues.

They are improving dependency management to handle multi platform. I can't find a link but it was on their blog

D allows you to export an obj-c api. This won't help much on the android side, but would definitely help with talking to swift on the ios side.
C++ is first-class in Android via NDK. You can write directly to your app's memory from a C++ library without having go through FFI. I'm pretty sure it's the same for iOS but through a C ABI.
I wouldn't call C++ through the NDK "first class", especially compared to Objective-C++ on iOS.
C++.

It is part of both SDKs, you have direct support for mixed mode debugging on the IDEs.

No need of extra tooling.

On Android JNI is always going to be a pain, but at least with C++ Studio gives you an hand on accessing JNI APIs.

I want to like this answer but not sure it's true. Do you mean bridging ObjectiveC++ and Swift? Apple is now deprecating ObjectiveC++ (after all the work we went to to make it work back in the NeXT days).

I would like to integrate C++ code into a SwiftUI app but am not sure how to do it. Are there some iOS C++ APIs I'm overlooking?

> Apple is now deprecating ObjectiveC++

How so? Objective-C++ drives a number of Apple projects, so I don't see how they're deprecating it.

Documentation seems to have vanished.
Apple’s documentation for all sorts of things is in a sorry state lately. That includes mass “retiring” of perfectly good documentation for non-deprecated things with no replacement. I wouldn’t take missing or hard-to-find documentation for any specific thing as an indication that it’s deprecated. As far as I know, Objective-C++ is as supported as ever. That is to say, it’s not exactly a banner feature, but it works fine, and there’s no reason not to use it if it’s the best solution to your particular problem. I use it in a number of places, including to expose C++ code to Swift, which doesn’t interop directly with C++.
So far I never saw anything in that regard.

In any case it isn't as if extern "C" isn't part of the language.

My answer regards using only SDK available languages, not that you write 100%bof the app in one of them

> Apple is now deprecating ObjectiveC++

I’d be very surprised if this was true. Apple’s own frameworks are all C++ under the hood, e.g. CoreAnimation, AVFoundation, AutoLayout (part of UIKit and AppKit), Metal, etc. The meat of these frameworks is in C++ with an Objective-C++ layer on top, exposing an Objective-C (and thus Swift) API to developers.

I would say use C. Interfacing C with Java is simple JNI. Interfacing C with Swift is very simple, too.
I'd push for Rust/C++ with C linkage.
Toolchain integration matters. Just use c++.
C is also very simple to add security exploits to your app.

I would never advise C unless the platform is lacking of a C++ compiler.

Just use extern "C" at the boundaries.

A super thin layer made of C between say Objective-C or Swift and C++ is quite convenient though and doesn't add much of an security risk. See it as the lowest common denominator.
What’s the threat of a security vulnerability in a 3rd party mobile app that tightly sandboxes your app - especially for a none financial app? I would think that if even a vulnerable app could affect other running processes or the OS itself, you’ve found a vulnerability in the underlying OS.
Presumably the user of the app cares about their own data...
And only their data in the app in question or any data that the user allowed the app to have would be vulnerable. If not, that’s an issue with the sandbox on the mobile OS.
If users care about their own data the best thing they could do is to stop using smart phones and signing up to google, facebook, saas providers etc. etc. They would leak your data with the efficiency any pirate will be jealous of.
The threat depends on what the app is used for.

If nothing else it can be used for piracy.

Software Engineering should strive for quality and best practices.

How do you propose that an security vulnerability in an iOS app that doesn’t result in a jailbreak will allow someone to copy the app from an iOS device on to another device?

Also, are you claiming that using C == “not striving for quality” or that it is not “best practice” to use C?

And on a side note, most corporations don’t care about “quality” or “best practice”, they care about shipping and selling software. Two decades in the industry has shown that those two things aren’t as highly correlated as you wish.

Industry is young, but thankfully returning goods on app stores and suing companies for delivering bad software is starting to happen.

I am claiming both when using a language whose security reports from Google, Apple, Microsoft, ARM, Linux kernel just increase in size every year with the amount of memory corruption and UB induced security exploits.

Like those reports advise, usage of C should be constrained to environments where no other safer alternative is made available, or due to constraints on already deployed software.

Even the personal computer software business has been around almost 45 years if you count when Bill Gates was selling BASIC interpreters in the mid 70s.

What “safer” alternatives are better that give the performance needed, with tooling available and the cross platform requirements that the poster needs?

Also, you haven’t explained how a security vulnerability from a third party app can be “used for piracy”.

Where are all of the corporations that are being sued because of software quality and not using “best practices? I would say just the opposite, companies are being sued if anything for not meeting delivery dates.

The definition of enterprise software is basically poor quality software where the user is not the buyer and they have to work around bugs.

Consumer software is no better.

Can I please have some links to unbiased reports with real world data on how much damage is attributed to the use of C vs other languages? Not from the entities you mentioned as they all have their own agenda. Otherwise what you say sounds more like unsubstantiated FUD.
What vulnerabilities does C introduce that C++ doesn't?
For example it is easier to avoid buffer overflows with std::string than with C-style strings.
It’s also easier to avoid buffer overflows in C by using the “n” variants of C string library functions.
Why subject yourself to that risk when you can just use C++ and make everyone's lives easier? Is there a benefit to using C?
What “risk” is there in an overflow from using strncmp, strncpy, etc?

C++ still isn’t as easy to interop with other languages as C and the low level APIs built into operating systems are not going to use C++/STL and you still end up converting to standard C strings and arrays.

strncpy notoriously doesn't necessarily 0-terminate.

(It also always pads the full length with zeroes if necessary, so it's almost never what you actually want to do.)

The C standard library is full of these footguns.

I won't say C++ doesn't have its bad parts, and I certainly wouldn't say that it's impossible to avoid the bad parts of C (some would), but you probably aren't going to manage.

If all of your string manipulation is working with the knowledge of the maximum size, how is that any different than the standard Pascal or BSTR string handling where the size of the string can be found in the first two bytes of the string?

The typical error case with C is something like

  char *a = “abcd”; //5 bytes
  char *b = “efgh”;

  char c[8];
  strcpy(c,a);
  strcat(c,b); //buffer overflow by 1 byte. 
If you used the “n” equivalents, c would have 8 bytes and every other function would know to stop 8 bytes - assuming you always pass in a size parameter.
That might work - if you always use that pattern, and never, never deviate from it, including in all library functions that you ever call with your strings. That seems very brittle and error prone, though.

And why, when you have C++ strings that just handle all of that for you?

It's not. But plenty of other standard C functions like to use 0-terminated strings without explicit lengths, including most of the system interfaces, and others make it awkward to pass in the length that you're actually tracking. You only need to call one of those with an unterminated string and it doesn't even matter whether your code knows the string's length.

You could say that just means you have to be very careful whenever you pass a pointer to a string around without also passing in its length, but that's a lot of places.

Oh god no, because then you have to add string growth logic when you run out of space, and there's all sorts of opportunities to fuck that up.
Smart pointers make it exponentially easier to write memory-safe code in C++ than in C.
C is pretty rudimentary for more complex logic - not having nice containers, things like std::thread or smart pointers can mean a lot of pain when trying to write code portable across platforms.

I don't think it's worth staying there - especially since C++ is a first party supported language on pretty much all platforms.

Can concur, we had huge success sharing our core business logic as a C++ library which was then used by UI on Android/iOS/Web and even desktop native apps.

Using Dropbox Djinni (https://github.com/dropbox/djinni) also helped with the horrible pain of JNI... although it's unmaintained these days. I guess people use SWiG now.

You might want to have a look at https://www.boden.io. Looks as if this might greatly simplify the task of sharing business logic (and UI if needed/desired).
Dart+flutter?
Yeah, definitely worth a try. Includes progressive approach.
This would definitely be my choice - for almost anything except certain types of game development.

Flutter makes cross platform life so much easier - why do anything else?

I agree fully. Please consider that the Flutter team are having a hard time keeping up with iOS changes with regards to developer tooling. For example, print() is now broken due to iOS 13 in everything but xcode and while using a debugger/tests is the right solution, it sure is nice to be able to add a print() statement in there for quick and dirty...
So I'm sure lots of people will think that this definitely doesn't qualify as "Best language to share code...", but Haskell has stuff for getting web, desktop, iOS, and Android out of one code base. It's called Obelisk (https://github.com/obsidiansystems/obelisk) and it's actually getting to be a pretty good development experience.
I love hacker news. This is the comment I came here for.

Just use this : A language that is (at best) fringe on the platform you are using. Here's a toolset nobody has ever heard of. Now build your mission critical bit of infrastructure on this house of cards, wait for the toolset maintainers to be outpaced and under-resourced by underlying OS/platform changes and then have to rewrite the whole thing which if it doesn't kill your startup, will certainly massively impact its resources.

Go! (THIS IS A JOKE)

Well, developers are the kind of people that love to be contrarian, so it shouldn't be that surprising. Half the fun (in my mind) is doing something no one else is doing. Being novel. It's probably unwise in a business sense, but if everyone was being wise all the time, there wouldn't be much fun in software development.
You're not obligated to be a brutal capitalist as an engineer. It's okay to make decisions that are suboptimal (but still passable) for your employer but highly aligned with your own career interests.

If you always optimize for whichever company is employing you currently, you're doing yourself a disservice and essentially "leaving money on the table" :)

(comment deleted)
"LINUX is obsolete", A.S. Tanenbaum, 1992.

A bit of nowadays tech scaled out from pet projects.

I would say React Native. For the things you are doing it works perfectly.
We use JavaScript for sharing code between devices(iOS & Android), browser as well as the server. Surprisingly, we haven't faced any of the problems, that Dropbox claims to have faced (https://blogs.dropbox.com/tech/2019/08/the-not-so-hidden-cos...).

Pros:

1. Sharing native APIs with JS runtime and vice versa, was well supported & trivial to implement.

2. Easy to find skill-set.

3. We can run the same code in browsers as well.

Cons:

1. The app will be slightly heavier in Android (as V8 has to be bundled with the app. iOS allows using native JsCore runtime.)

2. The shared code runs slower (Obvious, because dynamic language).

> as V8 has to be bundled with the app.

Cant you make use of Webview somehow? It has the benefit of being updated from the market if a security issue is found.

I'm not completely sure about your requirement, but as a game developer who uses Unity everyday, I would recommend it. Core graphics and UI components are available out of the box, and sometimes even when we need an app(nothing like a game) that need to access native APIs of the platform, we use Unity. It used C# as the default language, and platform-specific core logic can be separated within the code, using #directives so it's pretty straightforward.[edit: typo]
We're using kotlin native, after considering rust for a bit. It's been working great, we've had it in production for about six months.

Main advantages are

* kotlin is a nice language with good type support

* has good swift bindings out of the box

* also compiles to js and cpp so we can use it in our Web product as well

How much work do you have getting it into js?
What's the debugging experience like?
What tipped the scales over to Kotlin Native for your team over Rust?
ActionScript 3.0

with the Adobe AIR runtime you will be able to publish to iOS, Android, Windows and macOS, see "Adobe AIR" [0]

ActionScript is something similar to TypeScript

you will have access to the whole Flash stack and more, see "Building Adobe AIR Applications" [1]

with ActionScript Native Extension (ANE) you will be able to add your native code with an easy to use AS3 interface, see "Extending Adobe AIR" [2] and "Using native extensions for Adobe AIR" [3]

Note, the latest Adobe AIR SDK are now maintained by Harman [4]

[0] https://www.adobe.com/products/air.html

[1] https://help.adobe.com/en_US/air/build/index.html

[2] https://www.adobe.com/devnet/air/articles/extending-air.html

[3] https://help.adobe.com/en_US/air/build/WS597e5dadb9cc1e0253f...

[4] https://airsdk.harman.com/

Actionscript? Really?
yep really

I know it, few other dev know it too, and the rest well...

they will keep spewing stupid stuff about how flash is dead and ignore that wonderful tech

their loss

Another concept would be using Haxe Lang: You wrote shared logic in haxe which will be transpiled to c++ and java (and many more languages).
Xamarin iOS and Xamarin Android using C#