With the right libraries and clean code, going native for iOS/Android is usually the solution. Building UI/networking/etc quickly in Swift/Kotlin just isn't an issue anymore. RN/Flutter won't be used in 5 years.
Strongly disagree. Both frameworks save on dev time to a very significant degree. I actually foresee better cross platform solutions being introduced in 5 years
I don't agree, and I have worked with this significantly as a consultant and core contributor to react-native. What typically happens is people convince themselves what you are saying is true then there ends up being huge delays to spin up all the infra app side... THEN eventually, they kinda are okay. until the next react-native release.
edit: would like to clarify that of course I would recommend better ways... but... clients do as clients do.
You are looking at this with hindsight bias and are assuming that for some reason the future will remain the same as the past. There are no fundamental reasons why ios and android development occur with two different ui frameworks in two different languages.
With low interest rates companies will not be able to justify paying 3x to maintain 3 different apps when they could theoretically just pay 1x for one app that works everywhere
The key word here is “theoretically”. These cross platform solutions are great in theory - who wouldn’t want to share code across all platforms? It’s a great sell, especially to the folks holding the purse.
The reality though is it doesn’t work well. The tooling, performance, debugging, library stability and observability are all substantially worse. Your team might save a ton of time spinning up a React Native app, but lose it all right back once you keep hitting gnarly Android performance issues.
In the future, once we have a proper cross platform development kit officially supported by Android and Apple, code sharing will be great. But today it doesn’t exist. And that’s why none of (the good) apps you use are written in a cross platform way.
Good metrics for proposal to VCs .. to steel the cake from native platform overlord. Lets eat the apple and google cake to boost our return margins. Bam! VCs alliance for new scene graph renderer for the web on any device.
Apparently Jetpack Compose for iOS has zero accessibility support so far, if the Droidcon NYC app is a representative sample. I'm sure that will come; just don't use it yet for anything more important than the iOS version of an Android conference app.
I don't think that works as a metaphor. IE got MS in trouble because it was so embedded into the OS that it was literally required, and MS did everything they could to force users to use it.
Android works fine when built from source with no Play Store at all, using F-Droid as the primary store.
Yeah seriously. Just a worse version of the bridge. IMO the cart is leading the horse on this one. Might be more convenient for their dev team to just have a web codebase (though I’d argue if they took the time to transition their web codebase to react native web they’d see the same benefit), but it will definitely hurt UX.
There's no reason it has to hurt UX in theory. The difficulty is just in spending a lot of extra time perfecting the animations and interactions, which is 100% doable. We just released navigation present and dismiss animations a few weeks ago, which feel pretty great imo. They're non-interactive, and again, this will take a lot of extra work you get for free with native, but the tradeoff is worth it for us, and again, amenable.
You seem to be in very heavy denial. This will never be as nice to use as a native app, because you cannot replicate all of the small details of how native UI works on each platform. And say you manage to get close to emulating a native app on one platform — when the OS UI updates, you’ll be behind again.
I get that it’s inconvenient/expensive for you to build three UI layers. But that’s the only way to do this well. This was true for cross-platform apps in 1989 and it remains true decades later.
> This will never be as nice to use as a native app, because you cannot replicate all of the small details of how native UI works on each platform.
Not sure how much of that is necessary. I mean, a button doesn't "look native", so what? It's a button.
Apps written to require network requests to resolve a navigation are much worse than JavaScript handling a user event.
> And say you manage to get close to emulating a native app on one platform — when the OS UI updates, you’ll be behind again.
Not really the goal. You have this backwards. Keeping up with OS churn is one of the reasons to use an abstraction like this. It doesn't break your app nearly as much. The browser is a much more stable target than native mobile APIs.
> I get that it’s inconvenient/expensive for you to build three UI layer. But that’s the only way to do this well.
Inconvenient is dramatically understating the case. 3x spend is flat out impossible for many places.
> Not sure how much of that is necessary. I mean, a button doesn't "look native", so what? It's a button.
Is it? Native buttons also come with things like affordances, accessibility, recognizability.
"So what" is what lead Google to spend money on user research involving hundreds of people to figure out that text boxes looking like text boxes is good, actually.
> Is it? Native buttons also come with things like affordances, accessibility, recognizability.
And web views come with things like scaling, accessibility, page/document search. The recognizability and discoverability is up to the designer. Between the two, I miss browser features a lot more than native look and feel.
Then let's not forget the privacy nightmare that mobile apps have been.
I can also often fix poorly built web with some css or other hacks that I cannot do on mobile for poorly built apps. I helped a user do just that the other day, if it had been native he would not have been able to work around the design issue.
The native bias here is crazy. Most users just don't care and can't tell if they are on something that's native vs a web view. What they care about is, does this provide me value? That's real UX. Not blowing out development budgets on duplicating the same features on 3 platforms. You can spend that potential budget on refining and improving the features.
Does it matter sometimes? Yes! The are limits to what you can reasonably do in a web view. But most of the time a web view works fine.
> The native bias here is crazy. Most users just don't care and can't tell if they are on something that's native vs a web view.
They can. You just don't know how to listen. "It's slow to open", "it's janky", "it stutters when it scrolls", "I tap/click and nothing happens" etc.
Does this happen with native apps? You betcha. It is significantly more prevalent with web because web has never been and never will be an app platform. It's core is to display text and images, and it can barely manage that.
I've worked on many mobile products. This has been true of none of them. Please provide some evidence of otherwise?
> Does this happen with native apps? You betcha.
Something I agree with. It is the indian and not the arrow. I've seen native, multiple cross platform apps of different flavors, and web views. All of the major problems were due to institutional shortcomings. If our app is bad, it isn't a tooling problem it's because we fail to execute.
> It is significantly more prevalent with web because web has never been and never will be an app platform.
Ummm... I sell web apps. Many major vendors have products that are, at heart, web apps. Progressive web apps, web apps, electron, phone gap, Cordova, capacitor, etc. I find this observation a demonstration of your ignorance of this market.
> Ummm... I sell web apps. Many major vendors have products that are, at heart, web apps. Progressive web apps, web apps, electron, phone gap, Cordova, capacitor, etc. I find this observation a demonstration of your ignorance of this market.
As a user I've seen and used this crap. My understanding of the market is much better than yours, it seems, because I approach it as a user. And yeah, you definitely don't listen to the users.
I've yet to see a single [1] web app that didn't have the shortcomings I partly listed. I've seen this crap in banking apps, ride sharing apps, hotel apps, calendar apps, travel apps, ride and car sharing apps... The list is endless. Every time there's web, there's deficiencies: long loading times, bad scrolling, elements out of bounds, bad touch and tap targets, abysmal animations, layout shifts, you name it.
[1] This is a slight exaggeration. I vaguely remember a couple when I went "hmmm... it's a webview, but nicely implemented"
> As a user I've seen and used this crap. My understanding of the market is much better than yours, it seems, because I approach it as a user. And yeah, you definitely don't listen to the users.
Declaring that you always know best. When you are asked for evidence your only cited evidence is yourself. That your personal experience is representative of the primary needs of entire markets of users. And that you know better than what transpired between myself and hundreds of users. You seem to be remarkably arrogant.
3x spend may well be impossible for some places—but maybe that means great UI is impossible for them, too. The fact that I can’t afford a Ferrari does not magically make “the best car I can afford” be as good as a Ferrari.
If my customers don't really need a Ferrari, then making them pay for one is expensive. Most cars work just fine for most people.
Software is expensive. People resent high rate subscriptions as it is. Including on here. They resent it a lot more than lack of native toolkit. Ironically, price resistance on mobile is at legendary levels.
But so many can't seem to escape the gravity pull of dev strategies that blow up budgets like multiple code bases, micro service backends, etc etc.
Very very few of my customers actually want a Ferrari with the accompanying price tag. They want stuff that is convenient and works, the car is less important than the destination I can take them to. They don't really care about the last 5% percentile UI flexibility that is a native toolkit.
The big reveal is that React Native is still their future.
TLDR: Their app continues to use React Native, but they've given up on using it to provide a native user experience, and instead just use it to access OS APIs.
What they decided to do is really quite strange. Something like Capacitor makes much more sense but they said they wanted access to React Native libraries... I hope https://github.com/OpenNative/open-native can address their requirements in the future. It's goal is to make things like React Native native modules work across frameworks (e.g., react native libraries working in capacitor and native script)
I don't have personal experience with this, but React Native Web claims to solve this issue: https://necolas.github.io/react-native-web/, not sure if anyone has had experience with this. Of course, you will have issues with dependency hell/package maintenance.
Another great option seems to be Flutter web. I was really impressed by the "batteries included" approach to Flutter, and Dart has a pretty comprehensive standard library. This is in contrast to React's "just find a random package on npm and pray it doesn't bite you in the future."
Obviously rewrites are expensive, but I personally think both approaches are worth considering versus abandoning native components completely. WebView isn't without problems (and also, you don't need React Native to use WebView).
I've done it. Once you're setup, it really does work quite out of the box. What you do have to be mindful of is clear separation of concerns when designing platform specific components - you have to think in terms of Button.native.ts and Button.web.ts when you're doing things like haptic feedback or animations.
The only thing that's really a pain is that react dev tools has a harder time dealing with RNW components, and debugging in general can be a bit of a pain.
Perf seems totally within reasonable bounds for a react app, no issues so far.
In terms of resources or guides, it's pretty spotty out there. The project has definitely slowed down in terms of dev and i'm not sure where things like react 18 fit into the picture across platform, but we've setup our own config that works just fine for now.
We may need to reappraise in 2-3 years if react does change architecturally too much.
>combining RN and RNW is a pain in practice. It can be done, but not easily.
It's completely painless with Expo. With the tradeoff being you are locked into the Expo compatible ecosystem. Incredible devX if you go all in on it though.
I was considering using RN for a cross platform app and for some reason got the impression (earned or not) that Expo was for beginners, and people who have "non trivial" apps will have to "eject" (as it's called in Expo) sooner or later. So I was going to avoid it.
not so. you can build complex apps with the expo libs.
The reason people "eject" is primarily to add 3rd party native modules for functionality not available in expokit, or to optimize build size by removing unused expokit functionality. This isnt neccessary in the vast majority of cases as you can use Expo App Services to do this (locally, or remotely if you dont have mobile sdks installed)
And you still get the other benefits of expo - e.g. "batteries included" api, OTA app updates, not having to install the mobile SDKs, etc.
This is (effectively) false. You don't need to eject to use third party modules (including, but not limited to, react-native-webrtc). You can use expo-dev-client to build your own "Expo Go"-esque development app, and EAS Build provides a fully transparent build environment.
To be precise, EAS Build does actually eject IIRC, but you never notice this during development. I haven't ejected or seen an android/ or ios/ directory in the past year of developing an Expo app, using many third party libs.
I agree with Expo being pretty painless. Anytime people are really set on using RN I tell them, just use Expo. Now a day, you can integrate external libs and such quite easy.
It gets harder if you want to retrofit it to an older app using older third party libraries that have no or limited support. You have to pick through everything to work out what's playing up.
I would prefer imitated components any day compared to dealing with the actual SDK native components. Especially when there is "one code" that compiles into corresponding these components on different platforms. These things always change with each SDK version on each platform, and there needs to be a lot of messy hand-stitching in the library (React Native) to keep things working as expected.
Imitating native components is actually the only realistic approach. Those components are guaranteed to work on newer OS versions, they work on any platform and they give you easy access to the low level guts.
I don't - but check out WKWebViewController ... and its WKScriptMessageHandler delegate, which lets you receive messages from javascript embedded in the currently viewed page.
One codebase sounds great but I always feel devs try to ignore that there just are significant differences between platforms that you must address if you want a well integrated app. Writing separate codebases in native iOS, Android, and web has a huge amount of waste but you can achieve higher quality and os integration, writing react native and react on web means you get just 2 codebases and higher dev productivity but at the cost of pain in libraries which typically also means less native integration, the solution proposed here means 1 codebase and even less native integration. If it is right for you great but like everything it is tradeoffs, pick your poison.
Agreed. Although the economic reality is that it’s borderline impossible for a company to develop a cross-platform native product unless they have significant amounts of money. Cross-platform is a terrible necessity to that end.
Eh. Not sure I agree, unless you mean taking a non-native already made react bit and try to turn it into RN.. that is far harder and does require lots of money.
too many people don't realize just how non-portable react code can be.
No I mean building a product that works on web, android, and iOS, and has a native experience on all platforms. It’s hard enough to find a good web dev, but it’s far harder to find good iOS and Android devs. It’s a very large and expensive endeavor.
It is definitely a challenge, but as prev EM / hiring manager of many iOS / Android devs it certainly isn't impossible. Not sure about large and expensive. Surprisingly most of my best devs were all inbound, not via recruiters. Felt recruiters usually wasted our time and small teams of native devs can get a lot more done than web teams (at least so it seems based on my subjective exp).
My previous company had probably well over a dozen web engineers and then for our mobile side we had a total of 3, myself included. We also often had to adapt designs ourselves and work with product to fix flows for native. But we still managed to keep up with web.
edit: and not "keep up with web" in the we are working 80 hour weeks type thing, very normal working hours, 9-5. Possibly more normal than the web team.
As somebody who did it several times in multiple companies, it's not as hard as it looks. Usually you don't want to replicate your complete frontend experience, only the user facing part (and admin panel/etc can be a lot of product). Also things like notifications, emails, etc are all usually dispatched from your backend.
So in a lot of cases having just 1 engineer per each mobile platform would be enough. And if you spend say 3 years building backend + web frontent, it would take about 6 months for each to replicate user facing experience on mobile. With current average global quality engineering cost of 70k/year, this means it only costs about $70k total to ship both mobile apps.
There are many ways to do it less efficiently, but this is my personal experience (as a CEO, EM and also iOS engineer in different setups) and it's really achievable.
Besides companies, there are also solo web developers working on cross-platform apps. It opens up mobile/desktop app development to them. Learning new languages and platforms to create native apps might simply not be an option. And users benefit from more apps on the app store, more options for them.
On the other hand, I have used some web apps that, when I "Install as an app" on Android, work pretty well.
Sure, there are a couple of annoyances mostly related to notifications and how it works when switching between apps, but these are quite minor parts of the app - sure, they're annoying and need to be fixed but it's also important to acknowledge that the other 99% of the app was running correctly and with decent performance on my mid range phone. I think that the remaining issues, including perform, are fixable and will be fixed over the next few years.
You might not write one fully unified code base but you'll at least be able to use 99.9% of the same code with just a little bit of glue on top to make user accounts and notifications work on other platforms.
The thing is that most paying customers are most often on iOS, so target that experience while using react native and you will get some Android users for free. Android users are less likely to pay anyway.
It's all about trade-offs; you decided to trade better performance and native look&feel for faster/easier development. Perfectly reasonable, but for others that are making different trade-offs React Native totally is the future.
I think RN is a great middle-ground where you get native looking&feeling UX, but still get to share 95%+ of the code across platforms.
Tried it out on Android and it feels janky. It just feels like a web app and it's not working well. To just give one example, if I click on the header of a note, a menu with "options" shows up. But Android also selects the text in the header and pops up a menu with "Cut, Copy, Paste, etc." which is exactly on top of that menu I was actually trying to get to...
Eh, these are easy fixes. We're making progress daily on making it feel more "native" (i.e recently added present/dismiss animations). Try the demo[0] in your mobile browser, should feel pretty smooth. We've tested extensively on a whole range on devices and performance wasn't an issue. It's really the animations (or lack thereof) that make or break perception of "jankiness." What we have now is our first solid functionality-oriented release; next releases focus on tidying up the edges.
Depends on the user’s expectations, I guess. The demo you linked does not feel close to native yet. Lots of reflows, small shifts, inconsistent rough animation… even for a web app it’s not smooth enough (iOS Safari)
You guys are technically correct, but also dead wrong with your outlook
They're trying to make a useful app for humans, not trying to win the HackerNews Award for Excellence in UX. If accepting a little unfixable edge case jank makes their goal way easier to attain, they're going to end up with a much better app overall
I am not trying to nitpick - just giving my honest feedback. This submission is not for a technological breakthrough that I would admire from a theoretical perspective.
This problem has been solved many times over the last decade or so. So claiming that _this_ is the future and not the more established (and smooth!) solution has to be supported by at least some evidence.
I don't lose a tab among hundreds others if I need to reference something. It has all the necessary navigation on-screen (language switch, search inline, table of contents)
Don't get me wrong, wikipedia website is also brilliant: fast and reaponsive. The app is simply adjusted to the platform it's on, including all the mobile interactions you've come to expect. For example, there's no hover on mobile. In the app I can tap-hold a link and see the preview that you see on hover on Wikipedia's site.
UX is a real thing. Any user that feel your app is crappy, slow, inconsistent, ugly, breaking OS paradigms, janky. Will just dump it, and just get another one (there are plenty) Users are the real judges giving you the Award of Excellence, any minute they keep using your app
Nothing says “I don’t give a crap about our users or the user experience” like building a web app or using a cross-platform toolkit. It telegraphs you mainly care about doing it as cheap as you can instead of just building a good app.
The only way to build a decent mobile UX is by making an actual native app.
My experience with XP tools is that if you build anything but the most trivial of apps you keep running into issues where you have to do platform specific workarounds. Eventually it becomes an unmaintainable mess of exceptions and workarounds.
In the long run it’s faster and easier to just build a native app for each platform. That way you can provide the native UX a user of each platform expects without compromise.
> Nothing says “I don’t give a crap about our users or the user experience” like building a web app or using a cross-platform toolkit. It telegraphs you mainly care about doing it as cheap as you can instead of just building a good app.
What a better world we'd have if
Apple and Google agreed upon a common UI toolkit baseline.
I'd rather a small, scrappy company spend their limited resources on solving their core competency and value prop than fitting to these two stupid and needlessly different platforms.
Web should have won. It still has a good chance. We should have a "native web" in the future: WASM, hardware renderer access, device control, and more. That'll be the target to develop for.
Building for Apple and Android is a total waste of annual human cognitive resources. I hope every company starts doing cross-platform.
the web has won for a lot, but the companies that want to own their ecosystem, and have learnt from their past mistakes. Mobile is a fresh start, and they specifically made it so that web is a 2nd class citizen.
Web is a 2nd class citizen because it’s designed for documents, not for interactive applications. All the application bits are afterthoughts and bolted on and it shows.
By the time mobile was established as a platform, the web is known to be an application delivery platform.
The fact that platform owners such as apple (or indeed any of them, not just singling out apple) did not make it first class is evidence that they prefer to own the platform rather than operate an open platform.
Microsoft, with windows, did not understand this at the time when they had huge advantage with win32, and thus did not lock down the windows platform. You see them trying now, with windows app stores (which i'm glad is not succeeding).
apple has more foresight, and decided to lockdown their app ecosystem. They deliberately removed flash as a form of application delivery, because they know that it can be good (if only adobe could pull their shit together).
The fact that the web still can remain, and that people still use it, is testament that even for a system being hindered, it provides enough value. Unfortunately, it just cannot complete against platform owners who would preferentially make their own native platforms better than web.
Apple actually wanted to have only web apps on iOS initially. They only published the iOS SDK after the outcry of developers, because web apps sucked so much.
I remember this well, as I was already developing with Cocoa on Mac OS X and was pretty disappointed in the beginning when there was no SDK for iOS.
PS: As Steve Jobs was good friends with Larry Ellison, I can imagine he truly believed web apps would be sufficient (as Ellison was a long time proponent of them already).
However I think while web apps can be „good enough“ [1] for many business applications (i.e. basically data entry and reporting), they weren’t good enough for what consumers wanted.
[1] I mean people still accept suffering from stuff like SAP
Google was and still is the canonical Web Company. Android went with Java and custom APIs over the web stack. More than a decade later and this hasn't changed. The new Android UI layer is Jetpack Compose - again, not the web.
At the same time, Palm decided to redo their own OS and they went all-in on the web stack. They even called it WebOS. Palm were a well known name with momentum and talented staff, but WebOS was a failure partly due to poor performance.
>The only way to build a decent mobile UX is by making an actual native app.
But React Native is an actual native app. It is entirely compiled down to native code for your respective platform. I agree that the "hybrid" approaches of days gone by (Ionic, Cordova, Phonegap, et. al) were a terrible mess. But there is fundamentally no reason why RN cannot be equally performant to Swift/Kotlin based apps.
> It is entirely compiled down to native code for your respective platform
Has this changed recently? It’s been my understanding that react native has corresponding native components for many UI elements and uses them. But your react logic is still executing as JavaScript.
> But your react logic is still executing as JavaScript.
Yes, but this is no different than how native works. On iOS, The JS Bridge compiles to bytecode and talks to the Obj-C runtime for native needs like Cocoa, just as Swift does.
Sure you could get better performance by writing your apps directly in Obj-C, but I don't think many people want to go back to those days.
I don’t think many people left those days TBH. I personally saw how 2 large RN efforts have been rolled back to native at a big tech company. I don’t know whether RN is gaining traction or is stagnating - would love to see some stats.
You mean Facebook sized large? Not every company has the resources to hire a full on Android and iOS team. So they write React Native instead, which is good enough for most.
Sorry... what? The more I read this, the more asinine it sounds.
Some definitions:
- The Obj-C runtime is just a shared library that Swift links to on compilation (/usr/lib/libobjc.A.dylib). The performance to call into it is identical for Swift and Obj-C.
- "Sure you could get better performance by writing your apps directly in Obj-C..." Swift code is native code. Cost to access the runtime is identical.
- There is one "hop" to go from Swift to the Obj-C runtime.
That's an interesting take that I don't agree with.
It could be extended to pretty much anything: "I'm insulting your clothes, not you".
Calling something that a person says, or writes "asinine" is inflammatory. If I were to call your defense of it "naive, brain dead and utterly absurd" are you sure you wouldn't interpret that as a personal attack?
> Calling something that a person *says or writes* "asinine" is inflammatory
Yes, inflammatory. But personal, no.
> If I were to call your defense of it "naive, brain dead and utterly absurd" are you sure you wouldn't interpret that as a personal attack?
Correct, because it's not personal. That would be attacking the quality of the argument, not me, although it would certainly be inflammatory. I certainly wouldn't take it well — but for a totally different reason than you originally specified.
"Personal" and "inflammatory" are two different things.
I’m sorry what?? Native code gives you access to libdispatch and concurrency. RN is single threaded. There are a myriad of processes, shared memory, optimizations, and daemons that run on your phone that coordinate better with native binaries.
Web won’t beat native on mobile phones, I’m sorry this argument has been had every single year it’s just absurd we keep arguing about it.
RN is implemented due to developer productivity at the cost of user experience. Which is fine more power to you, but understand that it doesn’t imply better UX.
The barriers to creating apps is also getting smaller (SwiftUI & Jetpack Compose).
Source: Multiple years working on Core Apple systems at Apple and also multiple years at Google
Objective-C actually gets compiled down to machine code at compilation down. When you download an app from the app store, there is no more Objective-C.
RN doesn't "compile" the Javascript to bytecode or machine code. Instead, the closest competition you could get from RN is a JIT. But AFAIK iOS doesn't allow a Javascript JIT to run, so the JavaScript running is not being JITed to Bytecode.
Even if you assume that iOS allows a JS JIT now, you still have a JavaScript->Native bridge to cross. This adds a performance hit that Objective-C does not have.
This is not accurate. There’s a JS bridge to a lot of non native elements. You can get acceptable performance out of RN if you know what you’re doing but it will never match true native code.
You do realize that RN runs on single thread right? Have you tried implementing background processes in RN? I suggest you try also implementing push notification in RN.
Hmm, I was really intrigued by this post and am thinking about digging into capacitor a bit. It does seem to me, however, that there are often subtle ways in which the fact that an app isn't native bleeds through. For example, trying the demo you linked to: if I click on one of the notes in the list and then swipe right from the edge of the screen in order to go back (gesture navigation), I expected it to behave the same way the arrow in the top left would, but it doesn't and I found myself back on some other website. Maybe it doesn't work like this if I actually download the app on Android?
Sorry but it is janky asf... and if it's easy to fix why deploy without said fix. Uninstalled. Unsubscribed. Alone for the condescending tone of this comment. At least the export is easy. sic.
One more thing to tidy up: your full screen hamburger menu in notes on android chrome/Firefox can't be dismissed with a back button press. Instead that closes the entire app, because apparently you're also missing a navigation stack?
As someone who uses this off an on amount, I was really disappointed when I opened the app to the new web app. It was slow, janky, required me authenticating multiple times (biometric then username and password). I'm now looking for alternatives because "as fast as possible" is an important feature for me. I keep the app on my android home row, not because I use it a lot, but because when I need it, I need it instantly. Massive downgrade for the user imo, this only benefits the developer.
I spent the last 6 years building an Ionic app for “enterprise”. The still-not-native UX is the main reason why it’s not more popular, in my opinion.
In our case, our users had little say in their respective organizations’ decisions to buy our product, and “good enough” was still better than what our competitors were offering anyway.
We spent a lot of time of time debugging native layer issues, and WebGL bugs that would crash the webview (vector maps using the ArcGIS JS SDK) so it’s not a magic bullet in those respects either.
I reckon there is space for a drop in replacement ui for Angular and Ionic that respects screen real estate and users ability to interep a more dense set of information. Less padding etc. I'd pay for it. Or there could just be a few small modifications to make what is there more workable.
It fell out of favour for one of the same reasons the author cites - that third party dependencies were a dumpster fire. I would say that as frustrating as this can be with React Native, Cordova was substantially worse.
We did Fotolog.com using mobile and it gave us several problems. Webviews aren't good at all. We tried Flutter, and we also had complete troubles, but not related to the technology but finding people who were able to do it. The answer was react-native with a good balance of performance, pool of people who knew how to work on it.
Is the actual view rendering done in webviews? I've struggled with that because the compatibility between different Android webviews can be very janky, and lead to some really obscure bugs, plus on many phones it just feels "off".
Ive been an iOS dev for 10 years now and every few years a new cross platform framework comes along. They all suck. Either the development experience is awful, or the user experience is awful. Actually, it's usually both.
The thing is that its easy to get 90% there with these things. But getting that last 10% is often a huge hurdle, erasing most of the efficiency gains you just made.
Then, when a new hot framework comes along, the old hottness you bet your project on quickly becomes deprecated, and you have to rewrite your whole project under duress.
I tried the new hotness recently - Kotlin Multiplatform. Sharing code was great, debugging sort of worked but not really, and it wasn't long before I was pen pals with an overseas developer - no documentation on the bleeding edge! Ive been developing iOS for 10 years and my all-native workflow never relied on the mercy of a kind Bulgarian...
How long before people give up on that and move on to the next thing?
Hiring is really tough as well. With cross platform, at the end of the day, when you get that crazy memory issue or app crash, you need native expertise. So to be an effective cross platform engineer, you have to be an expert in iOS, Android, and whatever hot framework you bet on.
If you need to get to market very quickly and are OK with throwing it all away in a few years, cross platform is a great choice. But if you want your app to stand the test of time, the best thing you can do is to write it in the only framework which is officially supported by the platform - all native.
... which means you have to write the application at least twice for mobile and at least three times for desktop.
On desktop nobody does it any more, not even big companies. Everyone just uses Electron or something similar. It's a worse experience for the user but it's not bad enough to be a major barrier to adoption in most cases.
On mobile I guess only two platforms is not quite as bad so more people cope with it?
> It's a worse experience for the user but it's not bad enough to be a major barrier to adoption in most cases.
One thing I don't quite get is why giant companies with zillions of dollars of recurring revenue just keep using Electron (other than the obvious reason that it's there and it works already), when they could massively improve the user experience & make themselves significantly less vulnerable to competition by building native applications.
I mean, I get that making native applications is really hard, and trying to keep feature parity between version is a huge challenge (indeed, the the point of TFA). But it's obviously possible & some large organisations do it despite the difficulty (indeed, even some open source projects run by volunteers have it figured out).
I think about this every time I use Slack & feel the janky horribleness every time I click around the interface and have to deal with all the latency of waiting for it to update. I get that average users might not notice this but anyone who grew up with native applications surely can "feel" it and despair.
Slack used to feel better than it does now, and from my outside perspective it feels like most of the slowness that's started to happen comes down to lazier caching and slower back-end requests (loading conversations, etc)
They do it because coding a large UI project is brutally hard and money doesn't help that much. Building a new UI team is hard, hiring is hard, managing is hard, designing is hard, it's all brutal. Now do that 2-3X in parallel and manage that efficiently and ship new features on time.
Couple that with the fact that web devs are much easier to recruit than devs for any native platform and it's easy to see why they don't bother with native.
The real choice is (1) be single-platform (Mac only, Windows only, etc) or (2) use a cross-platform UI with Electron being the easiest to adopt.
I think a big part of what people perceive as being Electron’s fault actually comes down to how the app code is written.
Beyond the regrettable (but hard to avoid) baseline memory usage, startup time, and bundle size, at the end of the day it’s just a browser. Native code might be faster than JS on benchmarks but at the level of clicking a button to perform an action, there’s no technical reason that the latency should be any different, certainly not at the level of 100s of milliseconds. It’s just slow UI code at that point. I daresay the bigger problem is the huge prevalence of slow UI code.
It reminds me of this article on why NetNewsWire (a native Mac RSS reader) is fast - turns out it takes a lot of work beyond just being native! (and a bunch of these strategies have analogs in the JS world too)
https://inessential.com/2020/05/18/why_netnewswire_is_fast
But the blame frequently lies with the bloated frameworks developers choose to use. Developers choose these frameworks because web development is pretty complex.
When done properly, light-weight responsive web apps can be smooth as butter and an amazing user experience.
I do think that it requires a higher degree of technical expertise and more development effort to achieve this on the web vs native, though.
In some cases, depending on the business model and audience, it's worth it.
Just the other day I did an experiment while writing a new Electron app. I created a Hello World -- once using React, and another with just static HTML & Vanilla JS. The React version, literally just the default Hello World page, was already noticeably slower and jankier at startup than the static HTML version.
Tack onto that experience however many NPM packages the average React app imports, maybe some hastily written synchronous calls that play fast and loose with your main thread, and it's not difficult to see why Electron and web apps in general get a bad wrap. It's not unavoidable, it's just lazy practices.
Yeah, and honestly I don't think it's even down to the framework all the time either, but some frameworks make it easier than others.
React, for instance, is famously the opposite of bloated ("it's just the V in MVC") and leaves it up to the user to shape it how they like. I think the trouble is that it's not really fast by default. You end up needing to be pretty careful to avoid excessive rendering, which in practice means thinking about referential equality a lot, and trying to make sure renders only happen when you mean them to. React can be plenty fast though, with care.
I think Svelte does a better job of being fast by default, and part of that is because it's more truly "reactive". Change a variable, and that specific part of the page is updated; if other variables depend on that one, then those parts are re-rendered too. It needs a lot less babysitting to avoid extra CPU cycles.
I've thought about this a bunch because I'm building a video editor with Svelte and Tauri. (Tauri is a Rust-based alternative to Electron that uses the system webview instead of Chromium). Of the things I'd expect to be hampered by being web-based, "video editor" is pretty high on that list! But I've yet to run into a performance problem that came down to the browser being just too slow. It has so far been something under my control, whether that's needing to optimize some canvas drawing, or finding the most efficient way to get video frames on the screen, or minimizing the messages I'm sending between Rust and the UI.
There are certainly inefficiencies that wouldn't be a problem with a native app, but it's been possible to work around them so far. And as the sole developer on the project, it's nice to be able to serve a larger market without having to keep 2 code bases in sync.
From my experience the reason why these kinds of platforms get used as much as they do is that it follows the concept of the fungible developer. It is painful and expensive to find an iOS/Android/Win32 developer because the pool of skilled developers limited.
The promise around much of these frameworks is that any dev with web experience can handle these and become a cross-platform generalist. Faster and less expensive to find more/backfill developers and, most of the time, it won't cost anything in lost sales.
// tangential rant follows
The experience suffers but when you look at the tech landscape as a whole, there is little to no native application niche that is presenting an opportunity. Quite the other way, the prevailing trend is that everything is bring brought down to the limits of the OS's webview components. You even see this in, what used to be, pure native applications like office. One of the latest changes they're doing is replacing the room finder with one backed by a webview2 control. It sucks and is a lot less capable from the native version, but it is following the same path being charted by our industry.
> I tried the new hotness recently - Kotlin Multiplatform. Sharing code was great, debugging sort of worked but not really, and it wasn't long before I was pen pals with an overseas developer - no documentation on the bleeding edge! Ive been developing iOS for 10 years and my all-native workflow never relied on the mercy of a kind Bulgarian...
I honestly can't count the number of times I've been down this road - Alfresco, Hazelcast, Sencha Touch, a bunch of others I can't remember right now. People skills become very important.
What are your users saying? Especially mobile users. Are they expecting a native experience? Engineering decisions that sacrifice user experience usually don’t have a happy ending. As a native iOS developer the best feedback I can get is when somebody tells me that my app looks like it was developed by Apple. I like using vanilla controls as much as possible. But as previously mentioned its all about tradeoffs.
I was waiting for "progressive web app" (PWA). Safari is lagging behind in stuff like native file system access. But for most apps a PWA would most likely do the job.
Apple's monopoly via an app store and its market share is the only reason why PWAs aren't already ubiquitous. It makes no sense why I can't download a web app to my phone directly from any browser other than "well, that would cut into our monetization through IAPs and the app store." Genuinely, fuck Apple for holding the web back.
fanbois have entered the reply 3 2 1: no no no it's evil google's agenda that will invade your privacy and security on your devices .. a lot of excuse.
“And then we wanted to write a widget or use the dynamic island and we realized we can’t, so we just delivered a subpar experience, but hey - who cares about user UX when our dev UX is so great”
I think the point is that they write their UI once. There will always be platform specific parts, but those are a lot smaller if your UI is shared between platforms.
> Quite simple really: a bridge between web-land and mobile native-land. Our new mobile app still uses React Native, but is literally just 1 component: a function that renders a webview.
I don't know about the wrapper, but the entire app being a webview is how Peapod (grocery delivery) has been for years.
This is an important technical discussion, one that the community needs to keep having to reduce unnecessary work and get more cross-platform support. There is a lot to be learned from (and reused) from history.
For example, part of the post here is "When web-land wants to access the device keychain, it sends a message to native-land, and native-land responds with a primitive value. Neither native-land or web-land ever have to think about "messages" though. They're just function calls. Web-land has no idea that its function calls are being converted to postMessage calls behind the scenes."
That is very similar to Microsoft COM, DCOM and COM+, which all appeared at the points when Microsoft had to cope with levels of complexity similar to those in the browser and mobile platform diversity observe todday.
I have read the post and 60 comments but the "future" is as clouded as ever. I wonder if there was ever a period where developers had such difficulty identifying how to best deliver applications.
There is no difficultly in identifying how to best deliver applications. The issue is entirely resources.
If you want to deliver the best applications, there is one answer - native.
If you want to deliver the best application given a small team or other constraints like time, then you have a plethora of hybrid options at your disposal (react native, flutter, etc.)
But at the end of the day the fact remains that almost every app written in a hybrid framework, would be better, smoother, and less of a frustration at scale, than hybrid.
Identifying a key variable (resources) helps but doesnt really solve the optimisation problem.
Resources depend on the context and business model and that might not be under the control of the developer.
Resources may also be variable over time, e.g when the funny money runs out. In the post and comments you see the anxiety about having to support diverse codebases.
Thinking longer term you also need to address how platforms and stacks and the application requirements might evolve over a few years. You dont want to compromise your future options. This is even more critical for open source projects.
Further, it is not even a binary choice as there are multiple types of "native" and "hybrid" per platform. E.g. on android you could have pure java, or some variable amount of kotlin (or even qt/c++, depending on your definition of native) and desktop is much worse.
The bottom line is that its much more of a gamble than might have been in the past.
Really do check out Turbo Native from the Basecamp team. They’ve taken this hybrid web approach a step further with a bridge and native navigation. It is quite difficult actually to distinguish between their apps and real native UI, the library is astonishingly good.
Interesting tech. Looks like it's developed by hey.com, and their email app on Google Play store is only 9MB, which is impressive.
From what sparse commentary I could find online, looks like this is a middle ground between web dev and native dev. It allows reusing server logic to emit html markup for mobile UI, but requires platform developers to put in the necessary native pieces piecemeal (sensible choice considering the leaky abstractions in react native).
I'd say it's the inherent foolishness of spending time and $$$ trying to get your web UI into the uncanny valley of looking "as close as possible to the native UI" instead of spending that time and $$$ actually using the native UI and components, but that's just me.
This sounds exactly like Notion’s mobile app tech stack roughly 4 years ago - a web app running in a React Native wrapper webview. We really struggled to get that architecture to perform well, in particular for local caching, although improved React Native bridge performance might make it more feasible these days.
What we noticed is that we’d incur substantial performance bottleneck for anything that needs to move data to/from native because of the number of encode/decode steps and “bridge hops”. For example to read a row from SQLite, count the bridge hops:
Webview JS -> Java: postMessage to read a row from SQLite
Java -> React Native JS: hey, a postMessage happened, what to do?
React Native JS -> Java: please select * from … where …
Java -> C: ok really run this SQL
Then the stack of conversions repeats on the way back to the webview:
The other thing that plagued us performance wise was boot-up speed. At the time (before Hermes JS VM for React Native), we’d have to wait for RN’s JS to boot, figure out our cache status, then boot the webview JS. And then the webview JS would do the bridge dance above to pull data from SQLite to render. Slow - 40 seconds on low end Android slow.
Today we are still mostly a web app, but our wrapper is pure native code. We cold start to a native view and boot the web app in the background. Our throughout & latency to native APIs is substantially faster without the extra bridge hops into and out of the RN JavaScript VM. We managed the original architecture swap from RN -> true native wrapper with a team of three - myself, our first iOS engineer, and our first Android engineer. We do have a large mobile team now though.
One thing I’d add is that deciding to use a webview wrapper is quite common for multiplatform rich text content editors. Google Docs, Dropbox Paper, Quip, Coda, Notion all use this architecture on iOS and Android because implementing an editor is extremely complex. It’s much more expensive to implement an editor 3x than say implementing a few list views and a form 3x.
Huh. At work, I did the same for a WYSIWYG editor we had to implement, but it always felt wrong for me. After looking for a native editor library I was surprised how little I could find.
I can sleep a little better knowing that even the heavy hitters resort to webview sometimes
> our wrapper is pure native code. We cold start to a native view and boot the web app in the background. Our throughout & latency to native APIs is substantially faster without the extra bridge hops into and out of the RN JavaScript VM. We managed the original architecture swap from RN -> true native wrapper
Does this mean you boot the web app in a native WebView in the background (not visible), while showing a [splash?] screen until the web-app sends a signal from the web-view to java (or swift?) that it's ready?
Or have you started to build out native-views too? eg. Splash screen, some other super top level screens, etc?
> Does this mean you boot the web app in a native WebView in the background (not visible), while showing a [splash?] screen until the web-app sends a signal from the web-view to java (or swift?) that it's ready?
Yeah, that's what the RN codebase did, and for our initial switch over to native, we did the same thing there too.
These days we launch into a native "Home tab" view that lists all the pages in the workspace, as well as recently edited pages. Our philosophy is to progressively convert views to native, working from the outside in towards the editor. Soon we'll be launching a beta for native-ifying another of our top-level tabs.
Cool, do you try to make it a seamless transition to native with the web views matching styles, etc.? Or do users know which sections are native versus not based on appearance or interactivity (slower)?
I occassionally use the Notion Android app - and you can feel the difference in the native interface and the webview in this case. But only due to the interactivity - appearance is similar and cohesive.
My experience wasn't good before the introduction of the native home tab - I experienced high loading times right on opening the app and degraded usability - which made me quit from that page most of the time. Opening a page from the home tab now still has delay associated and the transition is not yet seamless (for me - I get a blank screen and then the page starts to load). But the home tab helps significantly improve the overall experience as the initial wait time is no longer present. Like mentioned the experience is improving - and I'm looking forward to the beta with more native interfaces!
That's super interesting, I've read your previous comments about adopting SQLite. With WASM SQLite nearly ready and the origin privet file system API becoming available, do you expect to adopt that in the browser? And if so would you then align the mobile app closer to the web app by sharing that code?
A while back I was working on a notes app, tying to go the single codebase route with Capacitor. The biggest problem I found was with the text selection cursor on iOS. It sits on a layer above all other elements and even appears outside of scrolling overflow, so it would appear over toolbars, really nasty UX. Did you come up against that? As far as I could tell the only solutions were to have a native UI and only use with webview for the editor (that immediately meant writing the UI twice), or create a custom carrot and selection indicator (nasty!).
> do you expect to adopt that [SQLite via Origin-private filesystem] in the browser? And if so would you then align the mobile app closer to the web app by sharing that code?
I'm interested in WASM+SQLite+OPFS. We currently use native SQLite on iOS, Android, as well as in our Electron app for macOS and Windows. WASM+SQLite+OPFS means we can use the same SQLite schema + caching code in the browser that we use on those other platforms, which would align web more with our native apps. We won't go the other way, and try to replace native SQLite with WASM+SQLite+OPFS on iOS or Android, because we have native code on those platforms that also talks to the same DB; on those platforms we've also moved some sync logic from webview into native land so we can sync in the background when the webview may be paused or destroyed. We want to be more native, not more web.
We might consider replacing the native SQLite in Electron with WASM+SQLite+OPFS if the performance looks good, since we don't have any Electron-side code that interacts with the DB.
> The biggest problem I found was with the text selection cursor on iOS. It sits on a layer above all other elements and even appears outside of scrolling overflow, so it would appear over toolbars, really nasty UX. Did you come up against that?
This only occurs inside an `overflow: scroll` container; it doesn't happen if the body itself scrolls. Here's a possibly-related Webkit bug (opened in 2014): https://bugs.webkit.org/show_bug.cgi?id=138201
That means you can overcome with some clever structuring/styling of the DOM, which is how Dropbox Paper for mobile works IIRC. We also found a different work-around in 2018 but it costs too much performance. So, we still have this issue in Notion because our DOM is too tricky to rework to solve this mostly-unimportant issue.
> create a custom carrot and selection indicator (nasty!).
Google Docs does this and it sucks and feels super janky. None of the nice editing gestures work nicely in Docs. Instead of smoothly moving the cursor around via the long-touch -> trackpad gesture, the cursor jumps around in Docs. I'd rather have some weird render issue with the caret drawing over a toolbar at very specific scroll positions, than force my users to use a jank re-implementation of the native selection UX.
Thanks for the detailed response. I've also seen your contributions to CRDT discussions here and it seems Notion is doing lots of super interesting things at the forefront of "local first" collaborative development. (It's a pity you only hire in the US!)
Yes, I found the "overflow: auto" issue with WebKit, unfortunately even scrolling the whole page doesn't solve the cursor above a "position: fixed" toolbar... hopefully one day Safari on iOS will catch up!
That's what puzzled me about the article. Why even have React Native in the mix if all you need is a webview and some code to hit native APIs? Is it ease of build/deployment? Developer QOL/familiarity?
I think your way of doing things would provide a better experience for users and I'm not sure what value RN is adding here.
That said I am not a JS or mobile dev so I might be missing something obvious.
I don't know how big the Standard Notes team is. If your team is super small, using React Native as a glorified build system that produces a native app without needing to learn both the Android and iOS toolchains could make some sense. But given that they wrote separate iOS and Android apps before switching to React Native, I think it's more likely to be avoidance of duplicate code in some way by using React Native abstractions over native features via libraries.
An issue we had trying to do that was that we still ended up writing a bunch of platform-specific native code, but instead of doing so in a straight-forward way, we had to fork or vendor abandoned/broken libraries and write React Native flavored native code, then integrate that library into the RN app. If it had an issue, you have a lot more to mentally untangle to debug problems.
This is an architecture I’ve noticed most (if not all?) large cross-platform mobile apps land on: a native core to quickly get the user to an interactive state and have smooth navigation, that then gives way to some kind of web technology for the actual feature screens.
Even the first iPhone OS used WebView for all text inputs before they implemented "native" components. Literally, every text control was a WebView. Turns out they are really great for text editing :)
Where did you get that impression? Do you have a source?
A WebView may or may not be great for text editing, but it'd definitely be overkill for simple text input. The first iPhone was severely resource constrained, I can't imagine it had the luxury of using a WebView for each and every text input.
Of course, it was not the current multiprocess WKWebView, which requires more resources, and not the legacy UIWebView directly, more likely some of its internals.
> Web browsing on the iPhone was always on the feature list, so WebKit would be there, and the editing code came along with it. We needed to decide how other styled text would work, like in Notes. Should we bring over the AppKit text system?
> Eventually, we decided not to. We were so pressed for memory that fitting two styled text systems was judged too much, so I used WebKit to back UITextField and UITextView. I’m pretty sure it stayed that way until iOS 7.
340 comments
[ 2.2 ms ] story [ 306 ms ] threadedit: would like to clarify that of course I would recommend better ways... but... clients do as clients do.
With low interest rates companies will not be able to justify paying 3x to maintain 3 different apps when they could theoretically just pay 1x for one app that works everywhere
The reality though is it doesn’t work well. The tooling, performance, debugging, library stability and observability are all substantially worse. Your team might save a ton of time spinning up a React Native app, but lose it all right back once you keep hitting gnarly Android performance issues.
In the future, once we have a proper cross platform development kit officially supported by Android and Apple, code sharing will be great. But today it doesn’t exist. And that’s why none of (the good) apps you use are written in a cross platform way.
Any examples of simple and complex apps?
Complete separate toolkit with its own patterns and semantics. I’d rather use one then learn two.
https://touchlab.co/compose-ui-for-ios/
https://touchlab.co/compose-ui-for-ios/
Android works fine when built from source with no Play Store at all, using F-Droid as the primary store.
I get that it’s inconvenient/expensive for you to build three UI layers. But that’s the only way to do this well. This was true for cross-platform apps in 1989 and it remains true decades later.
Not sure how much of that is necessary. I mean, a button doesn't "look native", so what? It's a button.
Apps written to require network requests to resolve a navigation are much worse than JavaScript handling a user event.
> And say you manage to get close to emulating a native app on one platform — when the OS UI updates, you’ll be behind again.
Not really the goal. You have this backwards. Keeping up with OS churn is one of the reasons to use an abstraction like this. It doesn't break your app nearly as much. The browser is a much more stable target than native mobile APIs.
> I get that it’s inconvenient/expensive for you to build three UI layer. But that’s the only way to do this well.
Inconvenient is dramatically understating the case. 3x spend is flat out impossible for many places.
Is it? Native buttons also come with things like affordances, accessibility, recognizability.
"So what" is what lead Google to spend money on user research involving hundreds of people to figure out that text boxes looking like text boxes is good, actually.
And web views come with things like scaling, accessibility, page/document search. The recognizability and discoverability is up to the designer. Between the two, I miss browser features a lot more than native look and feel.
Then let's not forget the privacy nightmare that mobile apps have been.
I can also often fix poorly built web with some css or other hacks that I cannot do on mobile for poorly built apps. I helped a user do just that the other day, if it had been native he would not have been able to work around the design issue.
The native bias here is crazy. Most users just don't care and can't tell if they are on something that's native vs a web view. What they care about is, does this provide me value? That's real UX. Not blowing out development budgets on duplicating the same features on 3 platforms. You can spend that potential budget on refining and improving the features.
Does it matter sometimes? Yes! The are limits to what you can reasonably do in a web view. But most of the time a web view works fine.
They can. You just don't know how to listen. "It's slow to open", "it's janky", "it stutters when it scrolls", "I tap/click and nothing happens" etc.
Does this happen with native apps? You betcha. It is significantly more prevalent with web because web has never been and never will be an app platform. It's core is to display text and images, and it can barely manage that.
I've worked on many mobile products. This has been true of none of them. Please provide some evidence of otherwise?
> Does this happen with native apps? You betcha.
Something I agree with. It is the indian and not the arrow. I've seen native, multiple cross platform apps of different flavors, and web views. All of the major problems were due to institutional shortcomings. If our app is bad, it isn't a tooling problem it's because we fail to execute.
> It is significantly more prevalent with web because web has never been and never will be an app platform.
Ummm... I sell web apps. Many major vendors have products that are, at heart, web apps. Progressive web apps, web apps, electron, phone gap, Cordova, capacitor, etc. I find this observation a demonstration of your ignorance of this market.
As a user I've seen and used this crap. My understanding of the market is much better than yours, it seems, because I approach it as a user. And yeah, you definitely don't listen to the users.
I've yet to see a single [1] web app that didn't have the shortcomings I partly listed. I've seen this crap in banking apps, ride sharing apps, hotel apps, calendar apps, travel apps, ride and car sharing apps... The list is endless. Every time there's web, there's deficiencies: long loading times, bad scrolling, elements out of bounds, bad touch and tap targets, abysmal animations, layout shifts, you name it.
[1] This is a slight exaggeration. I vaguely remember a couple when I went "hmmm... it's a webview, but nicely implemented"
Declaring that you always know best. When you are asked for evidence your only cited evidence is yourself. That your personal experience is representative of the primary needs of entire markets of users. And that you know better than what transpired between myself and hundreds of users. You seem to be remarkably arrogant.
This isn't productive, I'm done.
Good day.
Software is expensive. People resent high rate subscriptions as it is. Including on here. They resent it a lot more than lack of native toolkit. Ironically, price resistance on mobile is at legendary levels.
But so many can't seem to escape the gravity pull of dev strategies that blow up budgets like multiple code bases, micro service backends, etc etc.
Very very few of my customers actually want a Ferrari with the accompanying price tag. They want stuff that is convenient and works, the car is less important than the destination I can take them to. They don't really care about the last 5% percentile UI flexibility that is a native toolkit.
The big reveal is that React Native is still their future.
TLDR: Their app continues to use React Native, but they've given up on using it to provide a native user experience, and instead just use it to access OS APIs.
Another great option seems to be Flutter web. I was really impressed by the "batteries included" approach to Flutter, and Dart has a pretty comprehensive standard library. This is in contrast to React's "just find a random package on npm and pray it doesn't bite you in the future."
Obviously rewrites are expensive, but I personally think both approaches are worth considering versus abandoning native components completely. WebView isn't without problems (and also, you don't need React Native to use WebView).
The only thing that's really a pain is that react dev tools has a harder time dealing with RNW components, and debugging in general can be a bit of a pain.
Any concise/clear resource or guide you used?
Perf seems totally within reasonable bounds for a react app, no issues so far.
In terms of resources or guides, it's pretty spotty out there. The project has definitely slowed down in terms of dev and i'm not sure where things like react 18 fit into the picture across platform, but we've setup our own config that works just fine for now.
We may need to reappraise in 2-3 years if react does change architecturally too much.
It's completely painless with Expo. With the tradeoff being you are locked into the Expo compatible ecosystem. Incredible devX if you go all in on it though.
I was considering using RN for a cross platform app and for some reason got the impression (earned or not) that Expo was for beginners, and people who have "non trivial" apps will have to "eject" (as it's called in Expo) sooner or later. So I was going to avoid it.
The reason people "eject" is primarily to add 3rd party native modules for functionality not available in expokit, or to optimize build size by removing unused expokit functionality. This isnt neccessary in the vast majority of cases as you can use Expo App Services to do this (locally, or remotely if you dont have mobile sdks installed)
And you still get the other benefits of expo - e.g. "batteries included" api, OTA app updates, not having to install the mobile SDKs, etc.
whats the type of functionality not available?
You then use 3rd party modules (or build your own) to add/extend native functionality that is exposed to react native. For example, webtrc: https://github.com/react-native-webrtc/react-native-webrtc
To be precise, EAS Build does actually eject IIRC, but you never notice this during development. I haven't ejected or seen an android/ or ios/ directory in the past year of developing an Expo app, using many third party libs.
It gets harder if you want to retrofit it to an older app using older third party libraries that have no or limited support. You have to pick through everything to work out what's playing up.
Imitating native components seems both incredibly wasteful and also very fragile considering Google has an attention span comparable to a puppy.
Google what? Chrome org? Flutter org? Android org? Myriad of other orgs?
though I wouldn't describe it as abandoning RN, because I use react-native-web inside that webview.
rn-web provides certain features that are crucial for a native feel on mobile, like better coordination of touches within scrollviews.
too many people don't realize just how non-portable react code can be.
My previous company had probably well over a dozen web engineers and then for our mobile side we had a total of 3, myself included. We also often had to adapt designs ourselves and work with product to fix flows for native. But we still managed to keep up with web.
edit: and not "keep up with web" in the we are working 80 hour weeks type thing, very normal working hours, 9-5. Possibly more normal than the web team.
So in a lot of cases having just 1 engineer per each mobile platform would be enough. And if you spend say 3 years building backend + web frontent, it would take about 6 months for each to replicate user facing experience on mobile. With current average global quality engineering cost of 70k/year, this means it only costs about $70k total to ship both mobile apps.
There are many ways to do it less efficiently, but this is my personal experience (as a CEO, EM and also iOS engineer in different setups) and it's really achievable.
Sure, there are a couple of annoyances mostly related to notifications and how it works when switching between apps, but these are quite minor parts of the app - sure, they're annoying and need to be fixed but it's also important to acknowledge that the other 99% of the app was running correctly and with decent performance on my mid range phone. I think that the remaining issues, including perform, are fixable and will be fixed over the next few years.
You might not write one fully unified code base but you'll at least be able to use 99.9% of the same code with just a little bit of glue on top to make user accounts and notifications work on other platforms.
It's all about trade-offs; you decided to trade better performance and native look&feel for faster/easier development. Perfectly reasonable, but for others that are making different trade-offs React Native totally is the future.
I think RN is a great middle-ground where you get native looking&feeling UX, but still get to share 95%+ of the code across platforms.
[0]: https://standardnotes.com/demo
If you care about UX, you should make native apps.
They're trying to make a useful app for humans, not trying to win the HackerNews Award for Excellence in UX. If accepting a little unfixable edge case jank makes their goal way easier to attain, they're going to end up with a much better app overall
This problem has been solved many times over the last decade or so. So claiming that _this_ is the future and not the more established (and smooth!) solution has to be supported by at least some evidence.
We should however be clear about our trade offs and not pretend that web apps can replace native apps.
We don’t need to pretend. Web apps must and already did replace a whole class of apps that never should’ve been native to start with.
For example: why would you even need native app for HN?
I could imagine a nice native app for Hacker News, too
Don't get me wrong, wikipedia website is also brilliant: fast and reaponsive. The app is simply adjusted to the platform it's on, including all the mobile interactions you've come to expect. For example, there's no hover on mobile. In the app I can tap-hold a link and see the preview that you see on hover on Wikipedia's site.
I’d hate to use a web app for maps, notes, document writing, IDE, messaging, etc. I always prefer a good native app to a good website.
Nothing says “I don’t give a crap about our users or the user experience” like building a web app or using a cross-platform toolkit. It telegraphs you mainly care about doing it as cheap as you can instead of just building a good app.
The only way to build a decent mobile UX is by making an actual native app.
My experience with XP tools is that if you build anything but the most trivial of apps you keep running into issues where you have to do platform specific workarounds. Eventually it becomes an unmaintainable mess of exceptions and workarounds.
In the long run it’s faster and easier to just build a native app for each platform. That way you can provide the native UX a user of each platform expects without compromise.
What a better world we'd have if Apple and Google agreed upon a common UI toolkit baseline.
I'd rather a small, scrappy company spend their limited resources on solving their core competency and value prop than fitting to these two stupid and needlessly different platforms.
Web should have won. It still has a good chance. We should have a "native web" in the future: WASM, hardware renderer access, device control, and more. That'll be the target to develop for.
Building for Apple and Android is a total waste of annual human cognitive resources. I hope every company starts doing cross-platform.
the web has won for a lot, but the companies that want to own their ecosystem, and have learnt from their past mistakes. Mobile is a fresh start, and they specifically made it so that web is a 2nd class citizen.
The fact that platform owners such as apple (or indeed any of them, not just singling out apple) did not make it first class is evidence that they prefer to own the platform rather than operate an open platform.
Microsoft, with windows, did not understand this at the time when they had huge advantage with win32, and thus did not lock down the windows platform. You see them trying now, with windows app stores (which i'm glad is not succeeding).
apple has more foresight, and decided to lockdown their app ecosystem. They deliberately removed flash as a form of application delivery, because they know that it can be good (if only adobe could pull their shit together).
The fact that the web still can remain, and that people still use it, is testament that even for a system being hindered, it provides enough value. Unfortunately, it just cannot complete against platform owners who would preferentially make their own native platforms better than web.
I remember this well, as I was already developing with Cocoa on Mac OS X and was pretty disappointed in the beginning when there was no SDK for iOS.
https://en.wikipedia.org/wiki/IOS_SDK#History
https://9to5mac.com/2011/10/21/jobs-original-vision-for-the-...
> The App Store came later and apparently as a reaction to jailbreakers and developer backlash.
Which doesn’t have any source.
> because web apps sucked so much
Where did you get this?
However I think while web apps can be „good enough“ [1] for many business applications (i.e. basically data entry and reporting), they weren’t good enough for what consumers wanted.
[1] I mean people still accept suffering from stuff like SAP
That is definitely not why they removed it. All the reasons Jobs listed against Flash were 100% true and a year later Android followed suit.
At the same time, Palm decided to redo their own OS and they went all-in on the web stack. They even called it WebOS. Palm were a well known name with momentum and talented staff, but WebOS was a failure partly due to poor performance.
You’re talking about UI part, which hasn’t been a problem on mobile for a good 10 years.
And what is the core competency?
- yet another syncing backend in 2023?
- figuring out another encryption?
- writing yet another web app in the guise of a mobile app?
- writing a notes app that locks the content and doesn’t even let you have raw files on your computer in easily readable format?
This is just absurd reasoning.
But React Native is an actual native app. It is entirely compiled down to native code for your respective platform. I agree that the "hybrid" approaches of days gone by (Ionic, Cordova, Phonegap, et. al) were a terrible mess. But there is fundamentally no reason why RN cannot be equally performant to Swift/Kotlin based apps.
Has this changed recently? It’s been my understanding that react native has corresponding native components for many UI elements and uses them. But your react logic is still executing as JavaScript.
Yes, but this is no different than how native works. On iOS, The JS Bridge compiles to bytecode and talks to the Obj-C runtime for native needs like Cocoa, just as Swift does.
Sure you could get better performance by writing your apps directly in Obj-C, but I don't think many people want to go back to those days.
Some definitions:
- The Obj-C runtime is just a shared library that Swift links to on compilation (/usr/lib/libobjc.A.dylib). The performance to call into it is identical for Swift and Obj-C.
- "Sure you could get better performance by writing your apps directly in Obj-C..." Swift code is native code. Cost to access the runtime is identical.
- There is one "hop" to go from Swift to the Obj-C runtime.
- There are >2 "hops" to go through the JS Bridge. https://hackernoon.com/understanding-react-native-bridge-con...
HN is better without personal attacks and insults.
It could be extended to pretty much anything: "I'm insulting your clothes, not you".
Calling something that a person says, or writes "asinine" is inflammatory. If I were to call your defense of it "naive, brain dead and utterly absurd" are you sure you wouldn't interpret that as a personal attack?
Yes, inflammatory. But personal, no.
> If I were to call your defense of it "naive, brain dead and utterly absurd" are you sure you wouldn't interpret that as a personal attack?
Correct, because it's not personal. That would be attacking the quality of the argument, not me, although it would certainly be inflammatory. I certainly wouldn't take it well — but for a totally different reason than you originally specified.
"Personal" and "inflammatory" are two different things.
Web won’t beat native on mobile phones, I’m sorry this argument has been had every single year it’s just absurd we keep arguing about it.
RN is implemented due to developer productivity at the cost of user experience. Which is fine more power to you, but understand that it doesn’t imply better UX.
The barriers to creating apps is also getting smaller (SwiftUI & Jetpack Compose).
Source: Multiple years working on Core Apple systems at Apple and also multiple years at Google
Honestly, it won't beat anything anywhere, but people do keep on trying to make it work.
RN doesn't "compile" the Javascript to bytecode or machine code. Instead, the closest competition you could get from RN is a JIT. But AFAIK iOS doesn't allow a Javascript JIT to run, so the JavaScript running is not being JITed to Bytecode.
Even if you assume that iOS allows a JS JIT now, you still have a JavaScript->Native bridge to cross. This adds a performance hit that Objective-C does not have.
> just
?
> The only way to build a decent mobile UX is by making an actual native app.
And that’s the problem.
In our case, our users had little say in their respective organizations’ decisions to buy our product, and “good enough” was still better than what our competitors were offering anyway.
We spent a lot of time of time debugging native layer issues, and WebGL bugs that would crash the webview (vector maps using the ArcGIS JS SDK) so it’s not a magic bullet in those respects either.
There are certainly use cases for it but also many downsides, it's mainly just hard to get the UI right.
> Our new mobile app still uses React Native, but is literally just 1 component: a function that renders a webview.
The thing is that its easy to get 90% there with these things. But getting that last 10% is often a huge hurdle, erasing most of the efficiency gains you just made.
Then, when a new hot framework comes along, the old hottness you bet your project on quickly becomes deprecated, and you have to rewrite your whole project under duress.
I tried the new hotness recently - Kotlin Multiplatform. Sharing code was great, debugging sort of worked but not really, and it wasn't long before I was pen pals with an overseas developer - no documentation on the bleeding edge! Ive been developing iOS for 10 years and my all-native workflow never relied on the mercy of a kind Bulgarian...
How long before people give up on that and move on to the next thing?
Hiring is really tough as well. With cross platform, at the end of the day, when you get that crazy memory issue or app crash, you need native expertise. So to be an effective cross platform engineer, you have to be an expert in iOS, Android, and whatever hot framework you bet on.
If you need to get to market very quickly and are OK with throwing it all away in a few years, cross platform is a great choice. But if you want your app to stand the test of time, the best thing you can do is to write it in the only framework which is officially supported by the platform - all native.
On desktop nobody does it any more, not even big companies. Everyone just uses Electron or something similar. It's a worse experience for the user but it's not bad enough to be a major barrier to adoption in most cases.
On mobile I guess only two platforms is not quite as bad so more people cope with it?
One thing I don't quite get is why giant companies with zillions of dollars of recurring revenue just keep using Electron (other than the obvious reason that it's there and it works already), when they could massively improve the user experience & make themselves significantly less vulnerable to competition by building native applications.
I mean, I get that making native applications is really hard, and trying to keep feature parity between version is a huge challenge (indeed, the the point of TFA). But it's obviously possible & some large organisations do it despite the difficulty (indeed, even some open source projects run by volunteers have it figured out).
I think about this every time I use Slack & feel the janky horribleness every time I click around the interface and have to deal with all the latency of waiting for it to update. I get that average users might not notice this but anyone who grew up with native applications surely can "feel" it and despair.
Couple that with the fact that web devs are much easier to recruit than devs for any native platform and it's easy to see why they don't bother with native.
The real choice is (1) be single-platform (Mac only, Windows only, etc) or (2) use a cross-platform UI with Electron being the easiest to adopt.
Beyond the regrettable (but hard to avoid) baseline memory usage, startup time, and bundle size, at the end of the day it’s just a browser. Native code might be faster than JS on benchmarks but at the level of clicking a button to perform an action, there’s no technical reason that the latency should be any different, certainly not at the level of 100s of milliseconds. It’s just slow UI code at that point. I daresay the bigger problem is the huge prevalence of slow UI code.
It reminds me of this article on why NetNewsWire (a native Mac RSS reader) is fast - turns out it takes a lot of work beyond just being native! (and a bunch of these strategies have analogs in the JS world too) https://inessential.com/2020/05/18/why_netnewswire_is_fast
Web apps get a bad rap, and justifiably so.
But the blame frequently lies with the bloated frameworks developers choose to use. Developers choose these frameworks because web development is pretty complex.
When done properly, light-weight responsive web apps can be smooth as butter and an amazing user experience.
I do think that it requires a higher degree of technical expertise and more development effort to achieve this on the web vs native, though.
In some cases, depending on the business model and audience, it's worth it.
Tack onto that experience however many NPM packages the average React app imports, maybe some hastily written synchronous calls that play fast and loose with your main thread, and it's not difficult to see why Electron and web apps in general get a bad wrap. It's not unavoidable, it's just lazy practices.
React, for instance, is famously the opposite of bloated ("it's just the V in MVC") and leaves it up to the user to shape it how they like. I think the trouble is that it's not really fast by default. You end up needing to be pretty careful to avoid excessive rendering, which in practice means thinking about referential equality a lot, and trying to make sure renders only happen when you mean them to. React can be plenty fast though, with care.
I think Svelte does a better job of being fast by default, and part of that is because it's more truly "reactive". Change a variable, and that specific part of the page is updated; if other variables depend on that one, then those parts are re-rendered too. It needs a lot less babysitting to avoid extra CPU cycles.
I've thought about this a bunch because I'm building a video editor with Svelte and Tauri. (Tauri is a Rust-based alternative to Electron that uses the system webview instead of Chromium). Of the things I'd expect to be hampered by being web-based, "video editor" is pretty high on that list! But I've yet to run into a performance problem that came down to the browser being just too slow. It has so far been something under my control, whether that's needing to optimize some canvas drawing, or finding the most efficient way to get video frames on the screen, or minimizing the messages I'm sending between Rust and the UI.
There are certainly inefficiencies that wouldn't be a problem with a native app, but it's been possible to work around them so far. And as the sole developer on the project, it's nice to be able to serve a larger market without having to keep 2 code bases in sync.
Super lightweight, blazing fast, and straightforward to develop with. Class property setters that call render() are the reactivity.
In some cases it does take more time to reason about lifecycle and rendering than the equivalent react component, though.
The promise around much of these frameworks is that any dev with web experience can handle these and become a cross-platform generalist. Faster and less expensive to find more/backfill developers and, most of the time, it won't cost anything in lost sales.
// tangential rant follows
The experience suffers but when you look at the tech landscape as a whole, there is little to no native application niche that is presenting an opportunity. Quite the other way, the prevailing trend is that everything is bring brought down to the limits of the OS's webview components. You even see this in, what used to be, pure native applications like office. One of the latest changes they're doing is replacing the room finder with one backed by a webview2 control. It sucks and is a lot less capable from the native version, but it is following the same path being charted by our industry.
Xamarin (MAUI now) is pretty decent and there are good apps out there (Bitwarden for example).
I honestly can't count the number of times I've been down this road - Alfresco, Hazelcast, Sencha Touch, a bunch of others I can't remember right now. People skills become very important.
I don't know about the wrapper, but the entire app being a webview is how Peapod (grocery delivery) has been for years.
For example, part of the post here is "When web-land wants to access the device keychain, it sends a message to native-land, and native-land responds with a primitive value. Neither native-land or web-land ever have to think about "messages" though. They're just function calls. Web-land has no idea that its function calls are being converted to postMessage calls behind the scenes."
That is very similar to Microsoft COM, DCOM and COM+, which all appeared at the points when Microsoft had to cope with levels of complexity similar to those in the browser and mobile platform diversity observe todday.
ref: https://en.wikipedia.org/wiki/Distributed_Component_Object_M...
If you want to deliver the best applications, there is one answer - native.
If you want to deliver the best application given a small team or other constraints like time, then you have a plethora of hybrid options at your disposal (react native, flutter, etc.)
But at the end of the day the fact remains that almost every app written in a hybrid framework, would be better, smoother, and less of a frustration at scale, than hybrid.
Resources depend on the context and business model and that might not be under the control of the developer.
Resources may also be variable over time, e.g when the funny money runs out. In the post and comments you see the anxiety about having to support diverse codebases.
Thinking longer term you also need to address how platforms and stacks and the application requirements might evolve over a few years. You dont want to compromise your future options. This is even more critical for open source projects.
Further, it is not even a binary choice as there are multiple types of "native" and "hybrid" per platform. E.g. on android you could have pure java, or some variable amount of kotlin (or even qt/c++, depending on your definition of native) and desktop is much worse.
The bottom line is that its much more of a gamble than might have been in the past.
From what sparse commentary I could find online, looks like this is a middle ground between web dev and native dev. It allows reusing server logic to emit html markup for mobile UI, but requires platform developers to put in the necessary native pieces piecemeal (sensible choice considering the leaky abstractions in react native).
https://play.google.com/store/apps/details?id=com.basecamp.h...
What we noticed is that we’d incur substantial performance bottleneck for anything that needs to move data to/from native because of the number of encode/decode steps and “bridge hops”. For example to read a row from SQLite, count the bridge hops:
Webview JS -> Java: postMessage to read a row from SQLite
Java -> React Native JS: hey, a postMessage happened, what to do?
React Native JS -> Java: please select * from … where …
Java -> C: ok really run this SQL
Then the stack of conversions repeats on the way back to the webview:
SQL C -> Java -> RN JavaScript -> Java -> Webview JavaScript
The other thing that plagued us performance wise was boot-up speed. At the time (before Hermes JS VM for React Native), we’d have to wait for RN’s JS to boot, figure out our cache status, then boot the webview JS. And then the webview JS would do the bridge dance above to pull data from SQLite to render. Slow - 40 seconds on low end Android slow.
Today we are still mostly a web app, but our wrapper is pure native code. We cold start to a native view and boot the web app in the background. Our throughout & latency to native APIs is substantially faster without the extra bridge hops into and out of the RN JavaScript VM. We managed the original architecture swap from RN -> true native wrapper with a team of three - myself, our first iOS engineer, and our first Android engineer. We do have a large mobile team now though.
There’s some more FAQs and answers about this on Twitter here: https://twitter.com/jitl/status/1530326516013342723?s=46&t=x...
One thing I’d add is that deciding to use a webview wrapper is quite common for multiplatform rich text content editors. Google Docs, Dropbox Paper, Quip, Coda, Notion all use this architecture on iOS and Android because implementing an editor is extremely complex. It’s much more expensive to implement an editor 3x than say implementing a few list views and a form 3x.
Does this mean you boot the web app in a native WebView in the background (not visible), while showing a [splash?] screen until the web-app sends a signal from the web-view to java (or swift?) that it's ready?
Or have you started to build out native-views too? eg. Splash screen, some other super top level screens, etc?
Yeah, that's what the RN codebase did, and for our initial switch over to native, we did the same thing there too.
These days we launch into a native "Home tab" view that lists all the pages in the workspace, as well as recently edited pages. Our philosophy is to progressively convert views to native, working from the outside in towards the editor. Soon we'll be launching a beta for native-ifying another of our top-level tabs.
My experience wasn't good before the introduction of the native home tab - I experienced high loading times right on opening the app and degraded usability - which made me quit from that page most of the time. Opening a page from the home tab now still has delay associated and the transition is not yet seamless (for me - I get a blank screen and then the page starts to load). But the home tab helps significantly improve the overall experience as the initial wait time is no longer present. Like mentioned the experience is improving - and I'm looking forward to the beta with more native interfaces!
A while back I was working on a notes app, tying to go the single codebase route with Capacitor. The biggest problem I found was with the text selection cursor on iOS. It sits on a layer above all other elements and even appears outside of scrolling overflow, so it would appear over toolbars, really nasty UX. Did you come up against that? As far as I could tell the only solutions were to have a native UI and only use with webview for the editor (that immediately meant writing the UI twice), or create a custom carrot and selection indicator (nasty!).
I'm interested in WASM+SQLite+OPFS. We currently use native SQLite on iOS, Android, as well as in our Electron app for macOS and Windows. WASM+SQLite+OPFS means we can use the same SQLite schema + caching code in the browser that we use on those other platforms, which would align web more with our native apps. We won't go the other way, and try to replace native SQLite with WASM+SQLite+OPFS on iOS or Android, because we have native code on those platforms that also talks to the same DB; on those platforms we've also moved some sync logic from webview into native land so we can sync in the background when the webview may be paused or destroyed. We want to be more native, not more web.
We might consider replacing the native SQLite in Electron with WASM+SQLite+OPFS if the performance looks good, since we don't have any Electron-side code that interacts with the DB.
> The biggest problem I found was with the text selection cursor on iOS. It sits on a layer above all other elements and even appears outside of scrolling overflow, so it would appear over toolbars, really nasty UX. Did you come up against that?
This only occurs inside an `overflow: scroll` container; it doesn't happen if the body itself scrolls. Here's a possibly-related Webkit bug (opened in 2014): https://bugs.webkit.org/show_bug.cgi?id=138201
That means you can overcome with some clever structuring/styling of the DOM, which is how Dropbox Paper for mobile works IIRC. We also found a different work-around in 2018 but it costs too much performance. So, we still have this issue in Notion because our DOM is too tricky to rework to solve this mostly-unimportant issue.
> create a custom carrot and selection indicator (nasty!).
Google Docs does this and it sucks and feels super janky. None of the nice editing gestures work nicely in Docs. Instead of smoothly moving the cursor around via the long-touch -> trackpad gesture, the cursor jumps around in Docs. I'd rather have some weird render issue with the caret drawing over a toolbar at very specific scroll positions, than force my users to use a jank re-implementation of the native selection UX.
Yes, I found the "overflow: auto" issue with WebKit, unfortunately even scrolling the whole page doesn't solve the cursor above a "position: fixed" toolbar... hopefully one day Safari on iOS will catch up!
I think your way of doing things would provide a better experience for users and I'm not sure what value RN is adding here.
That said I am not a JS or mobile dev so I might be missing something obvious.
An issue we had trying to do that was that we still ended up writing a bunch of platform-specific native code, but instead of doing so in a straight-forward way, we had to fork or vendor abandoned/broken libraries and write React Native flavored native code, then integrate that library into the RN app. If it had an issue, you have a lot more to mentally untangle to debug problems.
Edit: Plus macOS' WKWebView has a different implementation on its own.
Where did you get that impression? Do you have a source?
A WebView may or may not be great for text editing, but it'd definitely be overkill for simple text input. The first iPhone was severely resource constrained, I can't imagine it had the luxury of using a WebView for each and every text input.
Of course, it was not the current multiprocess WKWebView, which requires more resources, and not the legacy UIWebView directly, more likely some of its internals.
That's truly surprising! I stand corrected.
To quote two of the tweets:
> Web browsing on the iPhone was always on the feature list, so WebKit would be there, and the editing code came along with it. We needed to decide how other styled text would work, like in Notes. Should we bring over the AppKit text system?
> Eventually, we decided not to. We were so pressed for memory that fitting two styled text systems was judged too much, so I used WebKit to back UITextField and UITextView. I’m pretty sure it stayed that way until iOS 7.