I agree, this is the way. To be clear: I'm not a mobile developer, and have only dabbled with it over the years, but I'm generally familiar with the stacks.
If you want to simplify development of a cross-platform app, your work should start by architecting the software in a way that the core business logic is agnostic to the user interfaces. Then your web, mobile, and desktop GUIs, CLI, TUI, API, and any other way a user interacts with your program are simply thin abstractions that call your core components.
The complexity of each UI will inevitably vary, and it might not be possible to offer a consistent experience across platforms or to leverage unique features of each platform without making your core a tangled mess, so this is certainly not "easy" to do in practice, but this approach should avoid the bulk of the work of targetting individual platforms than if you had done it any other way. It should also avoid depending on a 3rd-party framework that may or may not exist a few years down the line.
One extra clarification: If the quality of your app is business critical you should really use the native UI toolkit to offer the best platform integration and user experience.
If your app is not business critical (you just have to offer it - example: dishwasher app, ..) you might get away with using a cross platform toolkit like flutter or react native. But even then this adds a 3rd party dependency as you mentioned which adds risk.
Writing an App in Swift on iOS is boring. The same thing is true for writing an Android app using Kotlin/Java. This is a good thing. Now your developers can concentrate on shipping great features.
I hear this and it makes sense but when I actually go about implementing it, it quickly falls apart.
Most apps are UI, remote requests and maybe some storage. What do you put in the common core? Android does HTTP requests one way. iOS does them another way. You go for the lowest common denominator an implement a third way, using libcurl or something?
Or do you just put business logic in the common core? Is there really that much business logic that doesn't issue requests or access a database?
Excellent Points, this is where the answer is "it depends".
> What do you put in the common core? Android does HTTP requests one way. iOS does them another way. You go for the lowest common denominator an implement a third way, using libcurl or something?
If it's really functionality that cannot reasonable be shared don't share it.
It's probably more work to maintain bindings to a single API client in the core and fiddle with all the details of not using the native HTTP client implementations that it is to implement the API client twice.
Writing the API client twice is boring, but that's a good thing.
> Or do you just put business logic in the common core? Is there really that much business logic that doesn't issue requests or access a database?
The shared core is optional. You might have the need for it, then it's a good solution.
For an app like snapchat you'd probably share the video effects and have that in your core library.
That's perfectly reasonable but, at that point, the argument becomes: build 95% natively and maybe there's a 5% "core" that warrants extracting into a common lib. Technically? That's excellent architecture. In terms of saving development time — which is where stuff like React Native comes in? Not so much.
This is the direction we are going, but at the moment we are doing iOS only, but with the plan of learning the users UX needs in iOS before investing in Android, which is a bit strange because most of our team are on Android, but our users are on iOS.
Every time I see a new project like Valdi, I am hoping for something that is truly magical and cross platform, but I'm always steered away by comments like yours and people saying "you have to do native".
For context, I am a dev, and I've done RN apps in the past.
How hard could it be?