Claude wrote one UI for both platforms, exactly as React Native promises. Android still collected its tax in small, maddening bugs that may never show on the device on your desk, which is why someone has to go looking.
The pitch for React Native is that you write your interface once and it runs on both platforms. Claude did exactly that, and the pitch is mostly true, which is why I build this way. What it leaves out is that Android collects a tax, and it collects it in papercuts. None of these bugs are catastrophic. Every one is the kind of thing a user notices and the person who wrote the screen does not, because they all share one cruel property: they look perfect on your device and wrong on someone else’s.
Here are four worth knowing before they cost you real time.
The case of the disappearing last letter(s)
A user on a Samsung phone reported that a button said “Don” instead of “Done.” Elsewhere, “AM” rendered as “A,” and a version number lost its final digit. The box clearly had room. Regular text was fine. Only bold and heavier text lost characters, and only on certain devices, mostly Samsung’s One UI.
It turned out to be one underlying problem with four independent causes, which is why it resists a quick fix. The glyphs were rendering wider than React Native had measured the text box, so the trailing edge got clipped. You can arrive there by not bundling a real font (so Android fakes bold by smearing the regular weight wider), by bundling the font but skipping the heaviest weights, by putting an inline style prop on a Text (which silently drops your global font rule for that one element), or by the user turning on the system “Bold text” accessibility setting, which makes Android render everything heavier than React Native measured.
Fixing one cause still leaves the others, and they surface one device at a time. The full fix is to bundle every weight you actually use, tag any weighted text that also has an inline style so it keeps your font, and ship a small native plugin that opts out of the system bold-weight adjustment (ideally proxying it to an app setting you can use for dynamically adjusting your font tokens internally to still provide accessibility support). It also helps if you add “Enabling the bold text system settings” to your testing and incorporate simulators to get device variety. A single clean dev phone with default accessibility settings proves nothing.
Icons that get their corners shaved off
I switched the branding to a tight, edge-to-edge glyph and watched Android crop it, first on the launcher icon and then on the splash screen. Android masks the adaptive launcher icon to a circle or squircle and masks the Android 12+ splash icon to a circle, and only the centered two-thirds is guaranteed to survive. A glyph cropped tight to its own edges fills the whole image, so the mask eats the corners.
The fix is undramatic once you know it: the app icon wants a tight, full-bleed image, but the splash and adaptive-foreground slots want the same glyph with transparent padding baked in, sitting in the middle two-thirds. Same artwork, different framing per slot.
A button you could only tap in the middle
A full-width button responded to taps only near its horizontal center. The colored background filled the whole width, but the edges were dead. The same button component worked fine on other screens, which sent the debugging off chasing the wrong theories for a while.
On the New Architecture, a touchable that is stretched full width but whose content does not fill the cross axis hit-tests only over its content. A short, centered label leaves dead zones on either side, while a long label fills enough width to hide the problem. That is why it felt random. The fix is to give the content something that fills the width, like making the label itself flex to fill and center its text, and then to bake that into your shared button component so nobody has to rediscover it. A useful diagnostic habit came out of this one: when a tap bug looks screen-specific, put a temporary border on the frame first. If the frame is full width but the taps are not, it is a hit-testing problem, not a layout problem.
Keyboards that lift but will not sit back down
Keyboard avoidance has its own Android footnotes. The short version is to use padding rather than height for keyboard avoidance, because height behaves unreliably with edge-to-edge layouts. The longer footnote is that inside an Android modal, the avoiding view lifts correctly but does not fully reset when the keyboard dismisses while the modal stays open, leaving a transparent gap at the bottom. A modal is a separate native window, and the reset across that boundary is unreliable. The workaround is to drive the sheet’s own bottom padding from the keyboard show and hide events on Android, applied to an element that has a solid background so there is never a see-through strip.
What I actually took away
I am not warning anyone off React Native, and I am certainly not warning anyone off building this way with an assistant. The shared codebase still pays for itself many times over. The takeaway is narrower and more useful than “Android is hard.” It is that the device on your desk is the single least representative test device you own. Every one of these bugs was invisible on my test device and obvious on a user’s, and none of them were going to surface from unit tests or the coding assistant that wrote the screen. Someone has to borrow an OEM phone, turn on the accessibility settings real people use, and look at the interface, element by element. That is where the tax comes due.