One of the most frustrating moments in app development is when everything looks perfect on iOS, then you open the Android preview and — the shadows are gone, the font looks different, or the camera won't respond. If you've built with Rork and run into this, you're not alone.
When I shipped my first Rork app, the TestFlight build on iPhone was clean. But the moment I tested on an Android device, half the card shadows had vanished. The reason is straightforward once you know it: Rork generates React Native code, which is cross-platform by nature, but "cross-platform" doesn't mean "pixel-identical on every device." iOS and Android each have their own rendering engines, font systems, permission models, and keyboard behaviors — and some of those require explicit handling in code.
Why iOS/Android Gaps Happen in Rork Apps
Rork uses React Native (Expo) under the hood. React Native lets you write one codebase for both platforms, but the rendering still happens natively on each OS — iOS uses Core Animation, Android uses its own graphics stack. Some CSS-like properties work the same way on both; others don't translate.
Beyond styling, the two platforms handle things like camera permissions, font weight declarations, status bar height, and keyboard avoidance differently. Once you know where the gaps are, most of them are quick to fix — either by editing the generated code directly or by prompting Rork's AI with precise instructions.
Common Difference 1: Shadows Don't Show on Android
This is the single most common visual difference you'll encounter. iOS supports shadowColor, shadowOffset, shadowOpacity, and shadowRadius. Android ignores all of them. On Android, you need the elevation property instead.
If Rork generated iOS-only shadows for your cards or modals, add elevation alongside the existing shadow properties:
// Shadows that work on both iOS and Android
const cardStyle = {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
// iOS shadow
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 4,
// Android shadow — elevation is required
elevation: 4,
};Prompt for Rork: "The card shadows aren't showing on Android. Please add an elevation property alongside the existing iOS shadow styles for all card and modal components."
Common Difference 2: Font Weight Doesn't Work on Android
iOS respects fontWeight: 'bold' or fontWeight: '700' without any extra setup. On Android, bold font weight is often silently ignored unless you explicitly reference a bold font variant in fontFamily.
This means a heading that looks strong on iOS might appear regular-weight on Android. The fix is to use Platform.OS to set the right font family for each OS:
import { Platform } from 'react-native';
const titleStyle = {
fontSize: 18,
color: '#111827',
// fontWeight alone often doesn't work on Android
...Platform.select({
ios: {
fontWeight: '700',
},
android: {
// Reference the bold variant of the font directly
fontFamily: 'Roboto-Bold',
},
}),
};If you're using a custom font loaded via expo-font, make sure you're loading both the regular and bold variants. Missing the bold file is a common cause of this issue.
Common Difference 3: Content Hidden Behind the Status Bar
iPhones have notches or Dynamic Islands; Android phones have punch-hole cameras, notches, or plain status bars — each with different heights. If content is getting clipped at the top of the screen on Android, the status bar height isn't being accounted for.
The most reliable fix is to wrap your screens in SafeAreaView, but if that's already in place and Android still clips, try adding explicit top padding using StatusBar.currentHeight:
import { Platform, StatusBar, SafeAreaView } from 'react-native';
// Option 1: Use SafeAreaView (recommended for most cases)
function MyScreen() {
return (
<SafeAreaView style={{ flex: 1 }}>
{/* screen content */}
</SafeAreaView>
);
}
// Option 2: Manual top padding for Android (when SafeAreaView isn't enough)
const containerStyle = {
flex: 1,
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
};StatusBar.currentHeight is Android-only and returns undefined on iOS, so the ternary guard is important.
Common Difference 4: Camera and Microphone Permissions
On iOS, declaring the usage description in Info.plist is enough — the system shows the permission dialog automatically at runtime. On Android, you also need to declare permissions in AndroidManifest.xml and actively request them in code using PermissionsAndroid.
If your camera feature works on iOS but silently fails on Android, missing the PermissionsAndroid.request() call is the most likely cause:
import { Platform, PermissionsAndroid, Alert } from 'react-native';
async function requestCameraPermission(): Promise<boolean> {
// iOS handles permission UI automatically
if (Platform.OS === 'ios') {
return true;
}
try {
const result = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: 'Camera Access',
message: 'This app needs camera access to take photos.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Deny',
buttonPositive: 'Allow',
}
);
return result === PermissionsAndroid.RESULTS.GRANTED;
} catch (err) {
Alert.alert('Error', 'Something went wrong while requesting camera access.');
return false;
}
}Prompt for Rork: "The camera feature works on iOS but not Android. Please add PermissionsAndroid.request() for camera access and wrap it in a Platform.OS === 'android' check."
Common Difference 5: Keyboard Covers Input Fields on Android
A form that scrolls properly on iOS may have inputs disappear behind the keyboard on Android. KeyboardAvoidingView handles this, but the behavior prop needs to be different for each OS: "padding" for iOS, "height" for Android.
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
function FormScreen() {
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20}
>
<ScrollView keyboardShouldPersistTaps="handled">
{/* input fields here */}
</ScrollView>
</KeyboardAvoidingView>
);
}If Rork didn't generate KeyboardAvoidingView at all, prompt: "Text inputs are being hidden by the keyboard on Android. Please wrap the form in a KeyboardAvoidingView — behavior should be 'padding' on iOS and 'height' on Android."
How to Prompt Rork AI for Cross-Platform Fixes
When asking Rork to fix a platform-specific bug, vague prompts like "it doesn't work on Android" often lead to incomplete fixes. More precise prompts get better results:
- Describe the exact symptom: "On Android (Pixel 8, Android 15), the card shadow is not visible. On iOS it looks correct."
- Name the platform API you expect: "Please use
Platform.select()to handle Android-specific styling." - Ask for one fix at a time — Rork's AI is more reliable when the scope is narrow.
Also, be cautious when the AI modifies styling or layout code: always check a few other screens afterward to make sure related components weren't unexpectedly changed. If you're seeing that problem, this guide on preventing Rork AI from overwriting existing code is worth a read.
Test on Android Early — Not Just Before Launch
The habit of developing primarily in the iOS simulator and only checking Android at the end is a recipe for painful bug-fixing right before release. Rork Companion supports real-device testing on both iOS and Android, so there's no reason to delay.
Styling issues are easy to catch visually, but permission bugs, font rendering, and keyboard behavior often only show up on a physical device. My approach now: once the core features are working, I do one full run-through of every screen on an Android device — before I think about submitting to either store. It's become a habit that saves me from late-stage surprises.