Lessons learned from migrating a native iOS app to Flutter
betterprogramming.pub
betterprogramming.pub
The first thought is on maintenance and support from Google/Facebook compared to someone like Ionic. One of the things people don't think about before it's too late is support, and Ionic is unique in mobile in that we actually make money from supporting our technology directly for customers. We have direct support available for our auth/security/data storage plugins, cloud services, and open source projects. We literally will respond to customer support tickets and make fixes/patches on a weekend if we have to.
Is there any other company out there doing what Ionic is in mobile? You mention having issues with the Web View component, is Google or Facebook ever going to prioritize your issues? It's not likely, they don't have that kind of business model around their technology like Ionic does. Facebook builds RN for itself, and who knows what Google's end-goal is with Flutter (drive GCP adoption? push its ad network?) but it's certainly not to monetize it through dedicated support for the most significant users of it. I'm proud that the Ionic stack is the most user-aligned offering out there because we're literally in the business of supporting and extending users of our OSS stack.
On the Web View side, we've recently shipped one of the first mobile micro-frontend projects in the ecosystem called Ionic Portals which is basically an awesome Web View component powered by our tech and expertise building web view experiences on mobile. Right now it doesn't have RN or Flutter bindings but we are working on them this year. This has been a pretty interesting shift for us and we're now working with traditional native teams not using the traditional Ionic stack:
It would be great if Ionic offered consulting for things like Cordova -> Capacitor migrations. However, the last time I talked to sales it seemed like the best we could get was a report on what plugins we could or couldn't use with Capacitor.
> we're literally in the business of supporting and extending users of our OSS stack
Can you define that a little bit better? Because I've contacted Ionic sales before about seemingly well-used but under-maintained plugins and was basically told we were on our own.
AppFlow isn't a horrible product—but the recent price increases gave me a sour taste. What am I getting for my money? OK. I'm getting a build system which is nice, but I can't stomach paying the new (nearly 10x) price just to be able to do things like kick off builds from CI or the CLI.
What I _would_ pay for is help with other OSS plugin issues, consulting to migrate to Capacitor, training and help with maintaining custom projects, or better yet general development support when things go south (like the dreaded white-screen of death).
Anyway, we've been happy with Ionic and are always excited to see things improve. I don't mean to be downer—rather I'd love to give you guys money so long as it makes sense!
When you get stuck on a strange bug or find something in the docs doesn't work as expected your only options are Discord and GH issues. Neither feels appropriate as GH issues are slow and you get lost in the noise and Discord is a sea of noise that you're never sure if anyone with serious answers may be able to help you.
We've built amazing things with Expo (now that you can run almost any native code you want in an Expo app) but support would be an easy purchase.
Also do Dart/Flutter development along side it and.... they (D/F) just feel so damn verbose and messy by comparison.
edit: I can also mirror what the author of the article mentions. Any update in OS versions or the Flutter framework can seriously cripple some of the packages that you'll need to use in order to make a functioning application. Massive time will be spent hunting down the weirdest issues.
But to be fair, that can also happen on the native side. They are usually just much easier to find and fix.
The same has been said for Electron on desktop for years, but look at how VS Code is probably the top editor in use on desktop platforms, and even more demanding audience, like developers, don't really care that it's non-native.
It’s easier to do it via their website.
It is perfectly possible to build a poor app in any language.
Non-standard UI elements is something I don't personally care about. Some people do, but I think this is an issue that is often overstated (or perhaps rather overestimated as a factor) by platform enthusiasts.
What does matter a great deal to me though is launch speed and battery usage. Mobile apps are often used for short periods of time. They must launch instantly. And battery is the scarcest resource in mobile computing.
Nobody will voluntarily use an app that is slow to launch and shows up at the top of the battery usage table in spite of only having been in use for a few minutes.
As a developer, these are the issues I would like to learn more about in respect of any new cross-platform technologies.
100% this. Cross platform frameworks will always fall into a weird uncanny valley where there are just things that are subtly off about apps made with them. Most of the user base may not be able to pinpoint exactly what's wrong with such apps, but I believe they still notice on some level.
Users will of course notice and care. It's just they are not versed in shitty tech to properly articulate what they notice.
So every time a user says "the app is broken/slow/hard to use/loses data/can't update data etc." quite often it's because it's some shitty wrapper on top of a shitty "web app".
The path to sucess is a very tortuous one full of victims.
also everything around navigation is trouble - ios has those large headers that shrink down once you start scrolling. For a long time this was not possible in RN, not sure it finally is.
iOS 15 also uses modals quite a lot more than previous versions. Including modals on top of modals. Also impossible in RN up until recently, don't know current status.
While the navigation-related differences might not be consciously picked up by normal users, it may be subconsciously felt - the app doesn't feel right and user doesn't know why.
So Clubhouse 'succeeded' on native this then before every single competitor copied them to the point where everyone has abandoned it? At what cost?
It didn't stop Discord from copying them (which that is in React Native). It also seems that Discord is the prime example that proved how slow Clubhouse was to catch up in the first place without an Android app available at the time for their entire product.
As soon as the Clubhouse Android app released, it was already too late.
The expectation with apps these days is to release on both platforms from day 1 and Clubhouse was still too busy writing their Android app a year after releasing their iOS app, meaning they were too slow to compete against everyone else.
As soon as that was finished with the invite system removed, everyone already left for Twitter Spaces or Discord Stages.
After some exploration phase, it seems the main use case settled to just semi-interactive podcasting. Which is something that Twitter did take over. But my guess is this is just some 5% of the initial traffic and even Twitter could live without that probably.
Flutter is when one do not want to use Webview in the first place.
The Flutter webview is basically a wrapper for the native iOS and Android implementations. A native Android app using a webview and a Flutter app running on Android using a webview is using the same native webview.
It is like that for a lot of the Flutter libraries. They basically implement native versions of the functionality and make it available to Flutter. The Dart language has FFI so if you want to get "even more native" you can do Android and iOS system calls in your Flutter app using languages like C, C++, Rust or even Assembly.
https://old.reddit.com/r/dartlang/comments/rvqivf/what_is_th...
I wrote a fairly complicated web app in 2013 in Dart. I just updated it to Dart 2.0 and nullability and it still works, which impressed me. Someday people will catch on to Dart, probably if and when Fuchsia gets popular
For me the strong point of Flutter is not to use the webview in the first place delegating the latter to the original cases of showing help pages etc.
In particular the OP writes:
> Fortunately, I could find the bug in the library with my Swift skills, fix it within a day and even submit a patch to the owner of the repository. But I could find and fix it only because the library and my app were written in the same language, and this was a language that I was familiar with.
We adopted RN because we had a lot of web developers(hundreds) and wanted to enable them in contributing to our app. We explicitly didn't make it a goal to achieve code sharing, yet we did, to the tune of 90% of the code. Overall RN was successful for us.
However, one thing became apparent immediately: the RN developers needed support from native teams. As soon as the RN developers hit a problem that required bridging native APIs or a bug that required platform knowledge, they end up blocked with no way to unblock themselves. Luckily we could create a team of platform experts dedicated to supporting these developers.
This highlights the unfortunate paradox with cross platform tech. It's a great choice for solo developers or small startups looking to find product market fit and iterate quickly. They might be fooled into thinking that they can get by without learning the platform native methods and languages, only to find that they end up stuck when the leaky abstraction eventually leaks.
On the other hand, a well resourced company that can dedicate a team of platform experts as support for the cross platform developers will not suffer this problem, but is cross platform the right choice for a well resourced company? Such a company has probably already found product market fit and is better of paying the higher cost of native development to build a higher quality app.
A big takeaway from my RN experience is: One might expect that an RN developer can get away with knowing less about mobile than a native developer. Counter-intuitively, the opposite is true. A solo RN developer will, of course, need to know JS and React, but when the abstraction leaks they'll also need to be comfortable with Java, Kotlin, Swift, Objective-C, the respective build systems(CocoaPods & Gradle), and even C++.
If one considers RN's origin, being an internal Facebook framework. It all makes sense. RN was built to allow more developers at Facebook to contribute to their apps, without requiring them to learn native technologies or languages. Of course, Facebook has the best imaginable team to support these developer, the RN team itself.
If you need extensive native code for custom modules (we haven't yet needed this at my work) then it would make sense to have native developers on each platform take a lead of that. But there should absolutely be people on your RN team who can do integration work and bug fixing independently of that team.
I think the key is: if you're working with cross-platform tech then you ought to have cross platform developers.
Being proficient in all of Web(JS, React), Android(Kotlin, Java, Gradle), and iOS(Swift, Objective-C, CocoaPods) is a pretty significant ask for a single person too. Personally, I check two of those boxes(iOS and Web), adding Android as well would be a bit much.
As someone who came to a react-native project (as the lead) with a web and cordova background and no prior react-native or native platform experience, I've found that just knowing about the ios and android build systems and being able to add basic code to the AppDelegate (ios) and MainActivity (android) has been entirely sufficient for our needs. It would be different if we needed custom native modules (although I'm confident I could learn - I think learning something specific like that would be easier than trying to work out how to structure a whole native app), but then the react-native ecosystem is pretty broad these days. A lot of things are covered.
The react native ecosystem is huge so you really have to have some domain knowledge to be good at it in my opinion. I’ve read articles where the author was in Native Module hell and I just thought “oh well they could have just used this great package”. I know that illustrates a major problem with RN, but its exactly the type of domain knowledge that will make of break your RN experience.
For example myself: I was the co-lead for 2 React-Native projects at my company along with a dev who is very familiar with Swift/Obj-C. I'm still much more familiar with JS/TS-land but I was one of the few on the team fairly comfortable dropping into native Kotlin/Java for when we needed to.
This worked out well for us. The native iOS dev who worked along with me was less experienced at React/JS/TS itself so I took most of the shot calling for that but having him there for native-iOS help definitely pushed us through points where we would have hit a roadblock for a fairly large project. In the end we had 200k LOC on the React-Native side, and a fairly large amount for both in native due to a large feature that required us to drop into native.
> AEXML was needed to parse some XHTML files as the native iOS SDK does not provide a DOM parser.
I have used Foundation XML parsers[0] for many years, but they are general-purpose; not specifically modeled on DOM or HTML, which probably limits usefulness on some Web content.
That said, if he has control of the content (don’t know the app, so I am not sure), then there should be no reason that they couldn’t render it in XHTML, so the Foundation parser could be used reliably. In the article, he mentions that the content is XHTML. I have to assume that AEXML[1] is easier to use than the built-in parser. It uses Foundation parsing (it actually seems to be a lightweight wrapper for the built-in parser), under the hood (and seems to be a very well-written dependency).
So, it could be posited that he would only need one dependency for his native version, if he wanted to handle the XHTML parsing, himself.
Personally, I am a huge believer in native platform development, having many, many scars from the compromises required for cross-platform solutions.
That said, I totally understand why folks prefer cross-platform development, and can’t, in good conscience, recommend a native approach for all apps.
[0] https://developer.apple.com/documentation/foundation/archive...
Anyone have some success stories of using flutter web? I read you can output HTML/CSS/JS instead of canvas and a lot of these issues go away, is that true?
1. Users expect this stuff for free
2. For the most part it is, but only because the tools are being developed by big-tech and serve their interests more than yours
What hasn't changed:
1. compile-time. I just don't get it. Computers are like 5000x faster
2. cross-platform is hard and involves lots of compromises
3. it's hard to make money selling tools
I learned Flutter for my own needs, I make about 25k€ / year after taxes, I couldn't afford to pay this kind of money for hobby stuff. Even Embarcadero stuff at 5k a seat is way too much (I can get a good used car for this price).
Even at work I have to fight to get better hardware than Raspberry Pis (they regularly have black screens that only a few hard reboots solve).
The problem is that we don't live in the same world: there are companies where money flows and other companies where every cent has to be justified because money doesn't grow magically under unicorns hooves ...
Ultimately I went with Ionic/Capacitor and it was a great experience. Very easy to get up and running. I also experimented with combining Capacitor with NativeScript (they launched a way to use the two together) and it seemed like a brilliant way of exposing native functionality to Capacitor without having to drop all the way down to Swift/Kotlin.
The only significant complaint I have about Capacitor is on iOS and a WebKit bug (Ionic can’t fix it). With WebKit on iOS if you have an overflow:scroll with a text input of any kind (basically any app you build) the text cursor or selection highlight will remain visible outside the overflow area when you scroll. So for example if you select text in an input and scroll the view so the input is under a fixed toolbar, the selection highlight or cursor is visible infront of the toolbar. It looks very messy, I wish Apple would fix it.
I would, however, definitely use Ionic/Capacitor again, particularly if a webview was a major part of the app or as a small team targeting web and multiple mobile apps.
The Ionic app isn't as rich as the native ones, but it doesn't need to be.
I'd recommend Ionic for a lot of server-based solutions.
On the Web View side, one other thing we’ve been working on is a mobile micro-frontend product called Portals that is focused on enabling teams to bring in web experiences into their native apps. We’ve seen some really interesting adoption of it from traditional native teams. We will be supporting Flutter and RN this year. It’s probably the best web view experience out there at the moment: https://ionic.io/portals
I'd say both are on about the equal footing these days.
I mean, we usually don't require other developers to actively work in 3 different stacks because there are theoretically better languages around the corner. In fact we even make fun of premature fanboyism such as RIIR.
Today, the web works for most purposes, but when it doesn't, you may need native apps. It then makes perfect sense that people can reuse skills, ecosystems and tooling. From a UI perspective, any modern web rendering engine can do pretty much anything GUI fast and consistently.
Dart is a tiny language in comparison, and last I checked Flutter's web target backend used an opaque canvas element for all rendering, which wasn't just terrible for accessibility but also super laggy. I am still excited about Flutter but they have a lot to prove before I'll frown at the web folks.
I bet only 1% of developers these days have written a native or desktop app. If they had, there would be a gravitational pull moving away from defaulting to the web. I can hit any API from a Swing or WPF app and look damn good doing it with blistering performance.
It shows whenever project owners start asking developers to work around or prevent the use of browser based navigation like the back button.
The browser is like a hand grenade being rolled under a software project. The ultimate shitty dependency.
They move some stuff around like null safety and it’s a bit of a pain but it’s fairly easily to update. It’s still a developing framework and language (Dart).
The difference for us, and the reason we chose it over React, is that Dart/Flutter look a lot more like C/C++. React seems fine if you are using/know JS, which we do not.
It sounds superficial but it’s been great and we’re quite happy with it.
People and especially managers think that cross platform apps will save them money/time. However, they don't realisize that cross platform solves one problem and creates ten.
The developer experience is worse, the user experience is worse and you end up with a pile of mess after 1-2 years.
Ironically, I have an older native iOS app and it briefly stopped working on iOS 14.5 for no reason with the message "developer needs to update this app", like when apps had to switch to 64 bit. A few months later, the very same app started to work again in a later iOS version.
I follow a few native iOS devs on twitter and it looks like they have to deal with quite a lot of shit in Xcode and Swift all the time. I don’t. My app has been running pretty stable.
And yes, dev saves time. One code base for 3 platforms, dev experience is pretty great (hot code reloading, same IDE for all platforms 98% of the time).
I've basically made a living from re-writting cross platforms apps back to native.
Company creates cross platform app. They get some traction. They try to scale but it becomes harder every day. They hire me to go native.
Anything else, might look enticing, however as the author points out brings lots of attrition and failures can happen at any level of the stack, thus requiring native programing knowledge to sort them out anyway.
So instead of being experts in two stacks, the team now needs to be expert in three stacks.
Even if native views are required, the business logic can be driven from Web APIs, or DSL like JSON files.
For the projects I worked on, the bridges were automatically generated, so no hassle for the developer. Admittedly we built our own code gen system which of course was not free.
https://dropbox.tech/mobile/the-not-so-hidden-cost-of-sharin...
You see that often, when instead of rewriting the parts that may have performance issues into a library and keep everything else working as usual, we get those rewrote X in Y posts.
ios devs all have stockholm syndrome and will tell you 'it's not that bad' as they upgrade their dependencies for the 60th time to keep up with some unnecessary framework change aapl is forcing them to do because nice app store ranking, shame if something happened to it
I don’t enjoy Javascript for many reasons in addition to it’s lack of standard library.
Swift is a fine language if only the compiler could keep up with a large project.
Dart is both fast to compile and has a usable suite of standard libraries.
To my memory of working with Swift, I wasn’t left wanting much when I moved to Dart.
Dart isn’t as interested in value-semantics as Swift, so there are all kinds of Dart packages for immutable classes and collections, so that’s a notable miss.
I believe they’re planning to add something more like Swift’s struct to Dart. (dataclass proposal)
The community is small, and there is not a lot of actually multiplatform Kotlin libraries, although I saw some libraries making progress towards it. I found myself having to write bindings to C libraries a lot.
The language is very promising though, it's great with the JVM or JS as target.
It's promising though, although it doesn't really solve the same kind of issues as Flutter - Flutter is a UI library first and formost. While Kotlin Multiplatform will most likely replace cases where we use C++ for porability now - internal, shared libraries.
I am curious as to why the tech community feels so strongly against html content wrapped as an app. There is a lot of valuable reference content which would benefit from being freed from the rigid structure of an ebook, and so suit an app very well, but doesn’t need ‘native’ functionality per se. Putting that content into PWA makes it harder to monetise. App distribution model works well.
I'm a full stack/data engineer and use third party components all the time. In fact, I'd choose a popular and maintained component for the job, instead of writing it myself. I have no issues using as many components as I need. This seems like a bad practice in mobile.
If I encounter a bug in my dependencies, I find it, fix and send the fix to the maintainer. The same as I would do with my own code.
In general, using third party components with native mobile apps is pretty straightforward.
- Many libraries have zero guarantees as to how long they’ll be maintained or if their maintainer(s) will keep pace with new system releases, build tool changes, etc
- It’s less unfamiliar code that I’ll need to wade through at some point
- Fewer libraries reduces lock-in that can encumber refactors and other major changes
- I don’t have to waste as much time and energy “translating” things between different libraries with related functions
I used to not be as avoidant of a long dependency list, but over the years I learned that for both iOS and Android, each library represents a liability across multiple dimensions that WILL become a problem at some point, probably sooner than later. Mobile platforms aren’t like their desktop/server counterparts where the various APIs have barely changed in decades, and they aren’t like the web where everything continues to be supported for practically forever. Things change, and it’s important to be able to keep up with that.
This is a lot easier to manage under iOS than under Android, incidentally. Cocoa Touch still sees tweaks but it’s quite mature, and very deep and capable. You can build a world class app with just Cocoa Touch alone without too much trouble. With Android Framework on the other hand, much of what’s built in is incapable, with bits and pieces constantly shifting in and out of being supported, making it the norm to bring in a laundry list of libraries for super basic stuff (e.g. everybody uses Square’s OkHTTP for networking on Android while on iOS, not using the built in URLSession and associated APIs is very strange).
But otherwise I agree, sharing code and making it better for everyone as well as delegating complicated parts of the application to others are well practices.
"Any piece of code that is not your own and that your app depends on adds to the technical debt of your app."
We need to start pulling in dependencies as code instead of binaries. It should become part of our project and we should remove that which we do not need and maintain or patch those parts that need it manually...one our own.
The number of dependencies in projects cause a great deal of bloat, cross-cutting nightmares, and unending security vulnerabilities that make us desperately seek support in the form of new binaries from unpaid contributors. It is not professional, dignified, or safe.
If you need StringUtils.isEmpty you should not be pulling in the apache commons jar. Just clip the code you need and squirrel it away in your project.
In relation to the particular problems of technical debt related to third party modules mentioned in this article, QML rides on top of Qt which is a 26 year old C++ cross-platform toolkit with a lot of mature technology in it. I.e. there is a lot more "batteries included".
There are still plenty of times you have to "go native" to integrate something Qt doesn't cover but it apparently isn't as often as with Flutter.
https://apps.apple.com/us/app/listeners-on-call/id1498666617...
It has a very good UX designer and I've developed multiple commercial Qt/QML mobile applications previously.
I think the economics make sense with the following assumptions:
* The startup doesn't have the resources to build for two platforms natively (yet).
* The developer(s) can get their hands dirty and "go native" on either platform when needed.
Users know. That's why most of these apps die within 1-2 years.
Have you used any airline app? Have you used any "cross platform" bank app?
I've actually switched banks because i preferred the one with the better mobile app. A bad app just shows how outdated they are.
Not saying there's no demand for building such apps, businesses clearly don't care (yet). When they start losing business they'll have to care.
I think cross-platform apps are commonly misapplied and really only make economic sense with the appropriate assumptions. Once a company has the necessary resources they should go native and go all in on platform conformity.
But for many folks, that's not a feasible place to start from.
I really appreciate the constructive critique in the article: both the good (getting an app up and running quickly), and the more painful to read ("Flutter's ability to execute leads a lot to be desired, particularly on iOS"). While Google is the primary sponsor for Flutter, it's an open source project, and so as ever having reproducible bug reports and ideally pull requests is how we make it better.
The raison d'être for Flutter is simple: we don't think you should have to write the same code six times for your app to reach each major desktop, mobile and web platform. This abstraction is not free, but we think it's worth the bet, and there are some cool apps being built with Flutter, plenty of which have been awarded accolades like Apple Editor's Choice. We're not the solution for every app out there, but there are startups who don't have the developer team size to build multiple apps but can benefit from Flutter, as well as larger companies for whom Flutter lets them unify their app development team behind a single codebase.
A few quick comments I wanted to make:
- Yes, we have a large number of open issues -- over 9,000 at the last count, but not all issues are bugs. We're somewhat unique in bringing together tools, packages, framework and engine issues into a single database, also merging feature requests, bugs and even API doc requests together. Our general philosophy is that it's better to have it out in the open rather than (for example) to prematurely close issues that we don't plan to work on ourselves. We're also not unique as a large open source project in having lots of open issues (also see projects like PyTorch, Rust and VSCode). Lastly, it's important to count the number of issues _closed_, which is over 50,000, representing bugs fixed, new features implemented, and so on. We document the triage process here: https://github.com/flutter/flutter/wiki/Triage
- I'm surprised that the author considers packages an inevitable weakness. We've deliberately kept the core of Flutter relatively small, because it enables us to iterate on packages at their own pace. We could have taken the approach of building things like XML parsing, HTTP servers, geolocation and so on into the core of Flutter, but it wouldn't automatically make them more robust. With a package model, we can fix a specific issue without requiring a whole release cycle for every part of Flutter. Over the last year since the author wrote this article, our package maturity has greatly improved, and I'd be interested to know whether this is noticeable.
- Lastly, the underlying fear expressed in the article seems to be that Google will at some point just give up with Flutter. I understand this, since we don't have an immaculate reputation in terms of long-term support. I will say that this question doesn't come up internally with our stakeholders, though. There are over 400,000 apps in the Play Store that use Flutter; about 1,000 Google engineers building highly-strategic products using Flutter; and a healthy ads revenue from apps that use Flutter. The project more than pays for itself, and I can't honestly envisage any scenario in the next decade where Google would choose to squander all that.
Keep the feedback coming: we're listening.
i would love to see dot notation access to keys like how javascript handles json, it turns it automatically into an object after using .json()
but overall i enjoy working with it and it is always good to see posts popping up on HN about it
Hmm.. From my experience, every time I pick a new language / framework, always always always do proof-of-concept for ALL features you might need: camera, GPS, webview, deeplinking, etc. Don't want surprises.
Esp. if you already have an existing app, you should have a clear visibility of what's needed.
I expect that that most HN users probably have a flagship mobile phone with lots of CPU, RAM and reliable mobile data options. The other 90% of the world can not say that and a lot more sensitive to apps that require advanced phones and operating environments to function.
It's natural to see students using easier stuff as well. Most of student projects you come across is using react, flutter, firebase, MongoDB, as opposed to Angular/Vue, Android native/Jetpack, postgresql etc.. which have much higher barrier to entry.
But this may have to do with developing countries having more recent developers, and less established developers.
I find this ^ strange. There is a difference between using a library and technical debt. We use libraries so that we do not have to solve a problem that someone already has. Tech debt is a "shortcut" that you took when implementing a system because $deadlines/$budget/etc. An example might be calling a binary to do something for a PoC because interacting with a library will be more effort.
Using libraries is a good thing, it would be sad* if all of us keep solving the same problems over and over again. Tech debt, on the other hand, is debt, something you want to avoid as much as you can.
* personally I find having to re-solve solved problems one of the most frustrating things when programming, it takes away all the joy
> Flutter's HttpServer that crashed on iOS if the user briefly switched to another app and then back to mine.
The author is seemingly capable of writing a solution to the concrete problem, and even debugging and fixing issues in simple libraries, but fixing this issue in Flutter itself (which is much more complex than a concrete solution) is too complicated, leaving him at the mercy of the Flutter maintainers.
He may be saved from solving an old problem again, but it seems that he now has a new, much harder problem to solve. In this context, I think it makes sense to describe using the Flutter library as a technial debt in your definition above.
You say that libraries are a Good Thing (tm), but how would you handle such an issue?
On the other hand, if you don’t use libraries you’ll end up with an enormous pile of technical work to do, likely outside your core-knowledge, just to get your project off the ground. Nobody can afford that, and you need to borrow from existing libraries to get your app off the ground. In that way it could be analogous to debt, but in the way that debt can be good.
No. It's still a liability, even if the "payments" haven't come due.
Characterising all "debt" as negative is rather strange, I will agree.
1. Native iOS followed by Native Android
2. Flutter
3. React Native
4. Capacitor
5. Microsoft toolkit of the day
I may soon embark on such a task with such a small team. I am leaning towards #1.
Something to think about is all mobile apps come with the typical boilerplate. Think about a screen that displays the results from a REST call. You will need to create the screen for the Android app using either XML or Jetpack Compose frameworks. The iOS will need to create a screen using storyboards or SwiftUI frameworks. That is a lot to maintain. With Flutter you create the screens just once in Flutter and the only framework choice is Flutter. Now at some point in the future when the REST call adds a new field you have twice the work to do with native solutions then you do with Flutter to add it to your screen.
I would also like to correct misconception about Flutter. Flutter doesn't eliminate the need to do cross platform development. You still need to know the native tooling, native build cycles and native programming languages if you want to get a Flutter app out the door.
If you are a small teams looking to get something out the door, all of these are points in favour of Flutter. It works better for teams will constraints such as team size, budget and time.
BUT! If you are working on a complex application which requires a lot of resources and clever ways to keep a low footprint, you might be better off with the native solutions(even though dart has a very mature ffi). I guess a similar comparison would be something like tinygo and micro python for embedded development - good enough for simple things, but anything beyond that, sack them and stick to C/C++.