Loading...
Loading...
Expert in cross-platform mobile development (React Native/Flutter), bridging native performance with shared business logic.
npx skill4agent add 404kidwiz/claude-supercode-skills mobile-app-developerWhich framework fits the project?
│
├─ **React Native (0.76+)**
│ ├─ Team knows React? → **Yes** (Fastest ramp-up)
│ ├─ Need OTA Updates? → **Yes** (Expo Updates / CodePush)
│ ├─ Heavy Native UI? → **Maybe** (New Architecture makes this easier, but complex)
│ └─ Ecosystem? → **Massive** (npm, vast library support)
│
├─ **Flutter (3.24+)**
│ ├─ Pixel Perfection needed? → **Yes** (Skia/Impeller rendering guarantees consistency)
│ ├─ Heavy Animation? → **Yes** (60/120fps default)
│ ├─ Desktop support needed? → **Yes** (First-class Windows/macOS/Linux)
│ └─ Dart knowledge? → **Required** (Learning curve for JS devs)
│
└─ **Expo (Managed RN)**
├─ Rapid MVP? → **Yes** (Zero config, EAS Build)
├─ Custom Native Code? → **Yes** (Config Plugins handle 99% of cases)
└─ Ejecting? → **No** (Prebuild allows native code without ejecting)| Architecture | React Native | Flutter | Best For |
|---|---|---|---|
| MVVM | MobX / Legend-State | Provider / Riverpod | Reactive UI, clean separation |
| Redux-style | Redux Toolkit / Zustand | BLoC / Cubit | Complex enterprise apps, strict flow |
| Atomic | Recoil / Jotai | Riverpod | Fine-grained updates, high performance |
| Offline-First | WatermelonDB / Realm | Hive / Isar / Drift | Apps needing robust sync |
| Metric | Target | Optimization Strategy |
|---|---|---|
| Cold Start | < 1.5s | Hermes (RN), Lazy Loading, Deferred initialization |
| Frame Rate | 60fps (min) / 120fps (target) | Memoization, release thread (JS) vs UI thread, Impeller (Flutter) |
| Bundle Size | < 30MB (Universal) | ProGuard/R8, Split APKs, Asset Optimization |
| Memory | < 200MB (Avg) | Image caching, List recycling (FlashList) |
mobile-developernpx create-expo-app@latest my-app -t default
cd my-app
npx expo install expo-router react-native-reanimated{
"expo": {
"newArchEnabled": true,
"plugins": [
"expo-router",
"expo-font",
["expo-build-properties", {
"ios": { "newArchEnabled": true },
"android": { "newArchEnabled": true }
}]
]
}
}/app
/_layout.tsx # Root layout (Provider setup)
/index.tsx # Home screen
/(tabs)/ # Tab navigation group
/_layout.tsx # Tab configuration
/home.tsx
/settings.tsx
/product/[id].tsx # Dynamic route
/components # UI Components
/services # API & Logic
/store # State Management// app/_layout.tsx
import { Stack } from 'expo-router';
import { QueryClientProvider } from '@tanstack/react-query';
export default function RootLayout() {
return (
<QueryClientProvider client={queryClient}>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(tabs)" />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</QueryClientProvider>
);
}import { FlashList } from "@shopify/flash-list";
const MyList = ({ data }) => {
return (
<FlashList
data={data}
renderItem={({ item }) => <ListItem item={item} />}
estimatedItemSize={100} // Critical for performance
keyExtractor={item => item.id}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
);
};const ListItem = React.memo(({ item }) => {
return (
<View style={styles.item}>
<Text>{item.title}</Text>
</View>
);
}, (prev, next) => prev.item.id === next.item.id);expo-imagecachePolicy="memory-disk"transition={200}// plugins/withCustomNative.js
const { withAndroidManifest } = require('@expo/config-plugins');
const withCustomNative = (config) => {
return withAndroidManifest(config, async (config) => {
const androidManifest = config.modResults;
// Add permission
androidManifest.manifest['uses-permission'].push({
$: { 'android:name': 'android.permission.BLUETOOTH' }
});
return config;
});
};
module.exports = withCustomNative;import * as LocalAuthentication from 'expo-local-authentication';
export function useBiometrics() {
const authenticate = async () => {
const hasHardware = await LocalAuthentication.hasHardwareAsync();
if (!hasHardware) return false;
const isEnrolled = await LocalAuthentication.isEnrolledAsync();
if (!isEnrolled) return false;
const result = await LocalAuthentication.authenticateAsync({
promptMessage: 'Login with FaceID',
fallbackLabel: 'Use Passcode',
});
return result.success;
};
return { authenticate };
}import axios from 'axios';
import * as SecureStore from 'expo-secure-store';
const api = axios.create({ baseURL: 'https://api.example.com' });
api.interceptors.request.use(async (config) => {
const token = await SecureStore.getItemAsync('auth_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
api.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Trigger token refresh logic
// If refresh fails, redirect to login
}
return Promise.reject(error);
}
);openapi-generatorflexDirectionjustifyContenttestID="login_btn"