When we set out to build Şarj Asistanı, one decision came first: build iOS and Android separately, or go cross-platform? For a two-person team it wasn't much of a debate. We couldn't maintain two codebases and stay sane. We went with React Native because we already knew JavaScript and React, and picking up a whole new language would have cost us months we didn't have. The plan was to ship as fast as possible, and we did: both stores in six weeks.
It wasn't all smooth. Şarj Asistanı is a map app, so map performance mattered more than anything else. Drop a few hundred pins on the screen and everything grinds to a crawl. Maps that scrolled fine on iOS stuttered on Android. We fixed it with clustering and by skipping any pin outside the visible area. That took weeks, but both platforms are smooth now. Push notifications and background location were another matter, since both meant dropping into native code. This is where "write once, run everywhere" quietly falls apart. In practice it's closer to write once, debug twice. Even so, the native-specific work stayed under 15% of the codebase.
So what did it buy us? Roughly 40% time savings from the single codebase, around 85% of the code shared across both platforms, and, so far, zero performance complaints from users. One bug fix lands on both platforms at once. One feature ships to both the same day. Is it as fast as fully native? Probably not, if you're measuring closely. Slow enough for anyone to notice? No.
Our take: skip the React Native versus Flutter argument entirely. Use whatever your team already knows well. The framework is a means to an end, and the end is a shipped app. You can always optimize after launch. If you never launch, there's nothing to optimize.