Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The most important question for every cross platform framework is what happens to the UI?

Adobe products (both the Creative Suite, and their Flex Builder environment for Flash app) had their own design system that felt foreign on every platform it shipped on. If you wanted something that felt native, you had to reimplement e.g. Apple Aqua in Flash yourself.

Flutter goes out of its way to do that work for you, aiming for a "Cupertino" theme that looks-and-feels pixel-perfect on iOS.

React Native tries to delegate to platform primitives for complex widgets, so scroll views still feel like Apple's when on Apple's platform.

Just about every top-level comment here is talking about that in one way or another; yet the blog post doesn't mention it at all.

It's possible that Apple/Swift's mindshare among developers will lead to a significant number of apps shipping the Swift version for Android even if it means using Apple's UI, simply because they can't be bothered to make something bespoke for Android. Then again, Apple takes so much pride in its design language that it might not be willing to implement anything that feels good on a platform they don't own. If they were to ship an API-compatible widget toolkit, it might e.g. use intentionally bad spring physics to remind you you aren't on an iPhone.

I wonder how big the community part of this is. Is this an open source project of non-Apple people who are trying to break Apple's platform out of its walled garden? Is a lot of it funded by Apple? Ultimately, that's going to shape a lot of how this plays out.



> The most important question for every cross platform framework is what happens to the UI?

I kindly disagree. The first feature I want from a cross-platform framework is that it lets me write a native UI. That's why I like KMP: I can just share a framework with an iOS app built with SwiftUI.

Sharing business logic makes a lot of sense in a ton of cases and has been done forever (C/C++/Rust/Go libraries, etc). Sharing UI in complex apps, in my experience, always ends up being a "write once - debug everywhere" nightmare.

What KMP (and I'm hoping Swift for Android) bring is the possibility to share a Kotlin (respectively Swift) library instead of sharing code with C/C++/Rust/Go. So that an Android/iOS team can keep using Android/Swift without having to introduce a third language for sharing logic.


Indeed, "cross-platform UI" can only be as good as the average between all the platforms it supports and it usually ends up costing a lot more than using the native UI kits of each platform. Kotlin Multiplatform has been and continues to be the "happy path" for buildings apps in our studio - native UI + shared business layer. Also, in terms of API stability and mental load, Kotlin is a lot more productive than Swift... and it doesn't come with a yearly breaking cycle.


« kotlin is a lot more productive than swift »

care to elaborate ?


Having worked a long time with client teams as a lead - this is always the biggest pain in the ass.

At one of my last phase startups I started shifting all our business logic stuff into our graphql server and treated it like it was part of the client teams. (we had ios/android/web as independent full apps with a very small team of devs).

Business logic is the real killer. Have one person suck it up and do it in typescript (sorry y'all) on the GQL/apollo server and all the clients can ingest it easy.

Send down viewmodels to the clients not data models. etc etc.

This helped DRAMATICALLY with complexity in the clients.


So your takeaway is that business logic should be done on the server. Hasn't it always been like this?


Has been the true core vision of the web if not mobile. If I remember correctly, that is how the original Basecamp was implemented, or Craigslist (still is?)... or this very website


Also I just realized the irony of them using GraphQL. They've really come full circle


OP is likely talking about local business logic, ie password field is min 3 chars long. You validate that in the FE before sending it up to get instant feedback to the user.


Your API should be fast enough and hosted on the edge so that the server side validation is instant feedback


There are external factors apart from your own API that can impact latency, for example a user could be in an area of poor internet connection or have a slow connection. Users do not live in our perfect development environment bubble where everything just works, it’s important not to assume that.


If it takes 1 second for a small percent of users to get form validation back it won't impact the business


That's how we got to "download 50 GB before playing a game on a console is fine", feels like we just stopped carying. Sending the form to the BE just to do same basic validation adds so much latency to the UI that it feel unusable for many/most users.

Related: A few Sundays ago I wanted to play Anno again. Sadly it was not installed on the Laptop I used. So i started downloding it because you won't get it on DVD/as iso-file today). Now it's a few Sundays after and I didn't play yet - because the download took 7 hours.


That's such a ridiculous logical falacy. You already have to send the form input to submit the form in the first place and you already need server side validation.

I just checked one of my app's register page (which makes > $2M ARR). If you submit a short password it returns an error from the backend that says "Password should be at least 6 characters.". (It uses Supabase). But yeah, that is so unusable it is basically the same as taking 7 hours to download a game onto your Playstation. Great logic!


What if you want your app to work offline?


And not just off-line, but as we learned last week, if us–east-1 is down you have spotty connectivity, not hard down, and your device needs to not cook your users; literally in the case of Sleep8.


We've really hit a strange level of dystopia when your bed doesn't work because a server is down


It was a near real-time messaging application. So not really applicable (other than seeing messages you already received - which could be cached from previous sessions).


I guess I'm not clear on what you mean about putting business logic in the client. It can't only be on the client side. If you do so, then obviously you have to replicate it on the server to check that the client was sending the right results, no? Not to mention avoiding thread races and double inserts and whatever else may have gone stale on the server before you allow a client to validate something? Even if your code isn't public-facing, the server still needs to check everything. As a solo dev it seems insane to me to ever put business logic in the client, unless the client and server literally share the same typescript codebase for crosschecking ops, and even then the server needs the same code plus additional safeguards. It baffles me that anyone would write a platform from the ground up with primary business logic on the client side, if the server isn't written in the same language. Maybe some simple initial validations and checks to avoid bombarding the server, but the server has to be the central source of truth.


That’s the exact opposite of what the GP is suggesting. Read this again:

> Business logic is the real killer. Have one person suck it up and do it in typescript (sorry y'all) on the GQL/apollo server and all the clients can ingest it easy.

Move the logic to the GQL retriever so that clients don’t have to implement business logic.


Yeah, I understood what they said. I'm wondering why the previous owners of the code decided to put business logic in the client.


we had a lot of very talented iOS devs that started running away with feature development when the server team couldn't keep up.

This really hurt the android + web client teams.

Eventually our backend started changing (mono-rail -> microservices) and it turned into an absolute cluster of trying to massage/cram new data models into the existing ones the iOS team created.

Late stage startup and then post finding product market fit problems.


OP is likely talking about local business logic, ie password field is min 3 chars long. You validate that in the FE before sending it up to get instant feedback to the user (yes you also have it on the server).


  > What KMP (and I'm hoping Swift for Android) bring is the possibility to share a Kotlin (respectively Swift) library instead of sharing code with C/C++/Rust/Go. So that an Android/iOS team can keep using Android/Swift without having to introduce a third language for sharing logic.
have gone down this route before, and tbh the biggest issue is dev ux (ios devs cant debug easily, model mismatches vs kotlin e.g kotlin exceptions cant be caught from swift) and in the end even kotlin multi platform isn't the same as kotlin for android, so in a sense you are still introducing a 3rd language after a fashion...

if you can fix the dev issues and have a dedicated team behind the shared logic it could work out, but still then again if you also have a website your re-implementing that logic on the front-end twice...


> e.g kotlin exceptions cant be caught from swift

FWIW the approach that swift-java takes in managing interop with Java (and potentially Kotlin) function calls means it is perfectly possible to to catch exceptions thrown by the JVM using wrappers that catch and rethrow them as Swift errors. So there would be a distinction here with bringing Swift calling into JVM-based code running on Android.


  > catch and rethrow them as Swift errors
yes, in fact we implemented some wrappers for that which was done using custom annotations from the kotlin side, though if you forgot to apply it, an exception would crash our ios app… which was unfortunately not the greatest experience for ios users (who were the majority of our customers anyways)


Sure. I guess my point was that maybe your devs are more comfortable doing it in Kotlin than in C/C++/Rust.

And IMO not everything should be shared; it's worth sharing complex logic because the overhead of sharing beats the overhead of writing it twice. But in many situations it is not slower to write it twice. And I am an advocate of writing the UI on each platform to have a truly native experience for the users.


> if you also have a website your re-implementing that logic on the front-end twice...

Which argues for react-native, warts and all.


Until Static Hermes gets here it seems like a big performance loss to move to React Native.


I’ve experienced much the same as you but that’s one of the reasons I’m interested to see where Swift on Android goes. These problems are solvable, it’s just that current implementations haven’t solved them satisfactorily.


> Sharing UI in complex apps, in my experience, always ends up being a "write once - debug everywhere" nightmare

Compared to the tried and true method of "write many times - debug everywhere".

there is not a world in which you won't have issues on $PLATFORM because $PLATFORM themselves have their own individual bugs / issues


> Sharing UI in complex apps, in my experience, always ends up being a "write once - debug everywhere" nightmare

Amen!


> > The most important question for every cross platform framework is what happens to the UI?

> I kindly disagree. The first feature I want from a cross-platform framework is that it lets me write a native UI.

I don’t understand – aren’t you agreeing?


Actually you're right, I am :-).


>> The most important question for every cross platform framework is what happens to the UI? >I kindly disagree.

You're still discussing the question of UI though, whether it's native or not.


React Native is pretty good at cross platform but yes, it must be tested right away on all platforms.

Retrofitting an iOS-only React Native app to Android later is possible but can be of a pain, at least initially.


My experience as an Android user is that React Native apps don't feel "Android native". Maybe it's because I only notice the apps that have the poorer UI, I don't know.


React Native apps can be made to feel native but it takes some knowledge and skill. In certain cases, a bit of native code might be required instead of off-the-shelf libs.

For example, I was looking for a way to perform certain computations on a stream of frames from the camera. Most libraries available I found would send the image frames to the JavaScript side first and do the computation there. Unfortunately, that was never 60fps because the amount of data being copied/serialized was too large. The solution was to write a bit of custom code that performs the computation on the native side and only ship the computed result (tiny JSON) to the JavaScript side. The end result was easily 60fps and felt 100% native.


> Sharing UI in complex apps, in my experience, always ends up being a "write once - debug everywhere" nightmare.

Was that with UI framework that wraps platform's UI framework or with one that draws controls on its own? Shared complex UI is not much of an issue with frameworks that fully implement their own controls. But quality implementation of controls from the ground up is a lot of work so there's not many good UI frameworks that do this.


This isn't disagreeing


Just realising now. Fortunately I was only "kindly" disagreeing! :-)


It's worth noting that this doesn't add any expectations for how your UI is built. The example shown in the screenshot continues to use Jetpack Compose (Android's native UI) with Kotlin invoking Swift business logic. You can also use other UI frameworks on Android, of course, including some that are written in Swift.

One nice thing about this implementation is that it shares many of the same characteristics as Swift on other platforms: unlike some common alternatives, it's not garbage collected but uses reference counting; it uses the same underlying libraries, concurrency primitives and memory model.

Excited to see how folk use it... it's technology that will hopefully springboard some other interesting innovations.

[Disclosure: I work on developer tools and frameworks at Apple.]


This seems great, we are looking for a code sharing language between platforms and the options so far are the Usual Suspects:

- TypeScript: we have a few million lines already, but it runs poorly on Android midrange devices.

- Rust: very efficient on Android / iOS but on web there’s very expensive memcopy between WASM memory and JS. Safe but hard to write and refactor casually. Would be great for server perf tho. Async has many footgun for our JS devs. Biggest long term downside: borrow checker speed limit on developer velocity for business logic.

- Kotlin: can target JS directly avoiding bridge cost. iOS devs are uneasy about it. Async story is extremely confusing. Biggest long term downside: how Byzantine the JVM ecosystem is on the server.

Until I saw this Swift wasn’t really in the running. I need to explore the web target situation. Swift is maturing but still weak in ecosystem on non-Apple platform compared to other options. Still swift is moving towards a great combo of speed + safety + usability.

Biggest long term downside: type inference pain. Swift is the only language I’ve used that will tell me “the types seem wrong / ambiguous, but the compiler has no idea what your specific mistake is” and there’s no way to fix it other than trying random code permutations. I hit that one with node-swift yesterday and gave up.

Is there anything in the works for taming the type inference or some way to force-select which overload I want?


How does transpiration work without GC? I would think all the Kotlin equivalents would be GC heap allocated objects.


This doesn't transpile. It cross-compiles to Android architectures using the NDK. You can see a very simple "hello world" example at the bottom of this article:

https://www.swift.org/documentation/articles/swift-sdk-for-a...


Oh thanks, I was reading about Skip and it seemed to be a transpilation tool. The new thing is Swift compiled to a native binary with the NDK and using a JNI bridge to interoperate with Kotlin APIs.


The Swift SDK for Android doesn't specify or mandate any user-interface technology, but leaves it open for other projects to build upon. For example, Skip.tools re-implements SwiftUI for Android by bridging it to Jetpack Compose, so you can use the same codebase for both your business logic as well as UI layer.

We write about it at https://skip.tools/blog/fully-native-android-swift-apps/ and an example of an app on the Play Store that demonstrates this is the Skip Showcase app: https://skip.tools/docs/samples/skipapp-showcase-fuse/

[Disclaimer: I work on the Skip product, and I am also a founding member of the Swift Android Workgroup and am the release manager for the Swift SDK for Android]


Appreciate the response!

Respectfully, the demos on your page look like impostors on Android. For apps that wouldn't bother supporting Android in the first place, maybe this is an improvement. But for apps that want all customers to feel considered, that's not a direction I would recommend.

Would still like to see a call out to this in the blog post above ("For UI, you can use Swift for business logic and use Android's SDK to create the interface. Or you can use a library like our partner skip.tools to write SwiftUI apps directly.")


> the demos on your page look like impostors on Android

On the Android side, Skip apps utilize Jetpack Compose directly, which is the officially recommended toolkit for creating Android apps these days (https://developer.android.com/compose). It isn't mimicking native UI like other x-platform tools, but is actually using the Google-recommended API.


The three buttons dialog (ContentView.swift Showcase) in particular looks like iOS rather than Android.


Pretty sure that was a design choice, not a tech limitation. It's just a four row stack or a table with a custom header, and a border with rounded corners.


The Browser Company did an amazing job of porting SwiftUI to Windows, where the element primitives in the language map to native Windows UI C++ classes under the hood.

Perhaps the future of Swift for Android is similar, where SwiftUI will map to Jetpack elements. That would be cool.

Remember on iOS and MacOS, SwiftUI is not "native". It's a description language that system frameworks interpret and create NSViews and UIViews and CGLayers etc out of.


It exists already.

SwiftUI to Jetpack Compose: https://skip.tools

And a less mature but very interesting project with a SwiftUI-like API for UI across macOS/Linux/Windows plus some emerging support for Android and even a TUI target contributed by Miguel de Icaza: https://swiftcrossui.dev

> It's a description language that system frameworks interpret and create NSViews and UIViews and CGLayers etc out of.

This is out of date. FYI parts of SwiftUI are "native" now. Notably the new Liquid Glass UI was written in "native" SwiftUI. UIKit and AppKit actually wrap SwiftUI views to render Liquid Glass now. Although SwiftUI-exclusive APIs have always existed, this was a notable step in a new direction and suggests the future of UIKit and AppKit is a unified "native" SwiftUI implementation.

They've also been ripping out UIKit/AppKit implementations of SwiftUI views... IIRC List is no longer a UITableView for instance (could be confusing with another component though).


I think using a closed source solution (except the platform native solution) for such a core part of an application is a big no.


I agree it makes me very nervous. Though as I understand it, it's mostly open source (edit: not the build tool tho).

Their transpiler solution at least results in maintainable Kotlin code that one could begin working in directly without needing Skip. But the transpiler way is more limiting than the native Swift SDK on Android.

I'm considering using it just as a way to bootstrap as my main focus has been iOS/Mac. If I can use it to generate enough of a new revenue stream on Android, I could then afford to hire an Android developer to take care of doing it without Skip, too.


That makes perfect sense imho. I don't see it as a long term solution.


They didn't port SwiftUI to windows; they wrote a Swift wrapper for WinUI. Impressive in its own right, but not SwiftUI.


Is their code available somewhere.

I need this for UIKit so that I can make my UIs in Go. I have the gist of what it would require but have yet to implement everything. (if swiftUI allowed more control over the UI tree, I would even target it but full declarative à la react with vdom diffing is no bueno for fine grained rendering control)


SwiftUI in many cases generates views that were written specifically to back the description you requested. I think that’s pretty native.


> It's possible that Apple/Swift's mindshare among developers will lead to a significant number of apps shipping the Swift version for Android even if it means using Apple's UI

It doesn’t sound like this release includes bringing SwiftUI or UIKit to android, so unless you did a ton of work to replicate it (ala flutter) using Apple’s UI on android probably still isn’t really possible.


> Flutter goes out of its way to do that work for you, aiming for a "Cupertino" theme that looks-and-feels pixel-perfect on iOS.

Key word _aiming_ lol


Didn’t Flutter decide not to support Liquid Glass, because it’ll be too much work?


> The most important question for every cross platform framework

I don’t think this is a cross platform framework. AFAICT, It’s a Swift toolchain (compiler + Swift standard library) that allows you to call Android APIs.


I would understand people's craving for pixel perfection, smooth 120Hz scrolling, etc, if we had nothing else to want. But I believe that we are now in a totally different era when overall software quality is degrading and we lack some basic stuff here and there, even in the apps of multi-billion-valued companies. In this situation UX should be much more important than UI.


i think traditional UI should be decoupled from the language - only providing CLI and web UI (w3c web standards).

Apple's ui is very nice, but you're stuck with a whole ecosystem for life. If you want to cross-platform, as you mentioned, well, all hell breaks loose: React & co, Flutter, web assembly.

a unified, all-batteries-included system is excellent for the manufacturer/provider - they can plan, invest, manage and rollout products at a desired rate. but for developers, third-party, and consumers is very costly, intense and risky.

fun-fact from Steve Jobs bio, he was interviewing a tech hopeful for a job, the guy showed him a prototype of what would become the Dock (aqua + animations), created using an Adobe product. Abobe etc had powerful, flexible platforms - unfortunately the market was driven by eager tech geeks - so it was easy to get curried away with fancy UIs. However, that was (20 years ago) an educational issue - not a tech issue.


Very unpopular opinion but i like apps that ashew looking “native” for an original ux. Maybe it is my love for gamedev and all the crazy designs they come up with but i personally loath boring uninspired native apps esp when the native ux is terrible.

Apple wants everyone to conform because historically their ux is on point but the last update really reinforces my view.


IMHO, Apps can look (and maybe even "feel") any way they want. But when it comes to integration into the system, they should be as native as possible. It'S 2025 and I can't drag and drop from/to the Gmail app on iOS - that's ridiculous (especially because I can't have real-time push notifications for IMAP in the mail app for Gmail account, which as far as I know is also a limitation by the Gmail servers, not by IMAP itself).


I would like to see an UX research of what is actually important to match to the platform for the users.

The matching of the look is, from my experience, pretty low on the list. It's usually some interaction that doesn't exist or match that people complain about.


The debate has been settled anyways, none of the top apps (Facebook, Whatsapp, Youtube, Tiktok..) uses the native design, users simply do not care.


For the big ones the consistent familiar design language of the app becomes more important, or at least they can argue/get away with that, for the random crap companion app to a £5 drop-shipped FYGUIO-'brand' gizmo, it's much nicer and better-working app if it just follows the platform.


I share your unpopular opinion.

While I understand that having identical UI elements across apps aids in discoverability, I just love it so much when an app has its own bespoke interface that was clearly made with love.

Like you, it might be my love of games that has given me this preference. Would StarCraft II have a better UX if its menus used the standard Windows widgets where applicable? I think certainly not. And I think the same can be true for many non-game apps.


Except Flutter hit a wall with the liquid glass on IOS and Material 3 on android since they implement all the widgets from scratch implementing the new UI language will take considerable amount of effort and they are saying this is not even their roadmap RN.


Liquid Glass is meh anyway. Apple's Windows Vista moment.


I don’t like it much but it’s the platform look and users definitely notice when you spurn the platform.


They notice, but do they care? The most popular apps don't mimc the platform's look. Maybe they even like and find different designs more interesting as long as UX is good.


Huh? Did you read the link? Did you notice the ONE screenshot clearly shows the app has a material-ui look.

I'm going to say this because I think you might not know this, but also because I think many others might not have thought about this:

Almost always, a programming language is UI agnostic. Swift SDK for Android means: You can now write Android Apps in Swift. This doesn't magically include Apple's components / SwiftUI. When you write code for a platform, specifically an SDK for an OS, all you do is expose that platform to that language.

So, as long the SDK/bindings are there, a new "Window" means whatever a the OS thinks is a Window. A Button is what is defined (or exposed/binded to) as a Button in Android.

Swift was sorta released for Windows: a new Window looks like a generic Win32 Window. The same one you would get if you used C, C++, Rust, etc..

All your examples are GREAT examples to explain how this works: - Flutter has "Cupertino" to allow people to use Flutter to make Apple apps, and not have to learn names/methods/interface of the native Apple UI. - React Native: A LOT of work was put in to make/bind Apple native objects to a React component. And the same for Android.

So again:

The Swift SDK for Android means you can write your Android apps in Swift. The same apps you might of wrote in Java or Kotlin, you can now use Swift. Meaning whatever it looked like in Java/Kotlin (using native api's), it would look like in Swift.

The SwiftUI, Apple's component library written/exposed to Swift, is something completely different.


> Almost always … a new "Window" means whatever a the OS thinks is a Window. A Button is what is defined (or exposed/binded to) as a Button in Android.

But not always, and when it’s not true, it sticks out like a sore thumb. It’s convenient for developers, but produces apps that have this uncanny valley “this isn’t quite right” quality to them. Adobe used to do this when I worked there 20 years ago (honestly don’t look at modern Adobe software if I can help it so I don’t know if they still do) with an internal component called Adobe Dialog Manager that was built expressly so developers didn’t need to worry about native widgets. The result was this “adobeness” to all the ui elments on both platforms (at this point we are talking windows vs macOS). There was no os-level button. There was an ADMButton on both platforms and it was hand-rolled behavior for rollovers and drawing styles and general interaction rules and it was this pleasantly uniform experience that sucked equally everywhere.


> The most important question for every cross platform framework is what happens to the UI?

They don't give a fsck. Compare Windows, Adobe, Apple, Google products from 10 years ago with the present ones.


Think of this more like Kotlin Multi Platform. Shared logic, not UI.


> The most important question for every cross platform framework is what happens to the UI?

For that, there needs to be a single definitive agreement on UI somewhere.

Like what does it mean to be a "list"? How does it behave with mouse, touch, keyboard?

How many different kinds of lists? (for example, a list for "favorites" behaves slightly differently than a list for "bookmarks", vs lists of "products/offers" and so on)

I bet any example you can give I or others can nitpick some flaws in that.

Hell, there are differences of opinion right off the bat: Should content move up when I scroll/swipe down or move down when I scroll up?


Looks like this is package compatibility, not a cross-platform UI system (although maybe that’s in the works. SwiftUI could probably port well).


Nobody cares about native UI, not even Apple, the strength of a UI toolkit is to empower creative design while retaining consistency and intuitiveness across devices

Only the UX has to feel native, the pixels are yours


I wrote this in another thread: I'm confident that with Liquid Glass, even more companies aren't interested anymore in the Apple UI look and rather want their own UI language, because Liquid Glass is just that bad.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: