Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Mobile app development guide — React Native, Flutter, Expo for cross-platform. Triggers: mobile app, React Native, Flutter, Expo, iOS, Android, 모바일 앱.
.claude/skills/popup-studio-ai-mobile-app/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 76% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 138% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 120% | 0% |
A guide for developing mobile apps based on web development experience. Develop for iOS and Android simultaneously using cross-platform frameworks.
| Framework | Tier | Recommendation | Use Case | |-----------|------|----------------|----------| | React Native (Expo) | Tier 1 | ⭐ Primary | TypeScript ecosystem, AI tools | | React Native CLI | Tier 1 | Recommended | Native module needs | | Flutter | Tier 2 | Supported | Multi-platform (6 OS), performance |
> AI-Native Recommendation: React Native with TypeScript > - Full Copilot/Claude support > - Extensive npm ecosystem > - 20:1 developer availability vs Dart
> Performance Recommendation: Flutter > - Impeller rendering engine > - Single codebase for 6 platforms > - Smaller bundles
Starter → Expo (React Native) [Tier 1]
- Simple setup, can leverage web knowledge
- Full AI tool support
Dynamic → Expo + EAS Build [Tier 1] or Flutter [Tier 2]
- Includes server integration, production build support
- Choose Flutter for multi-platform needs
Enterprise → React Native CLI [Tier 1] or Flutter [Tier 2]
- Complex native features, performance optimization needed
- Flutter for consistent cross-platform UIbash# Install Expo CLI npm install -g expo-cli # Create new project npx create-expo-app my-app cd my-app # Start development server npx expo start
my-app/
├── app/ # Expo Router pages
│ ├── (tabs)/ # Tab navigation
│ │ ├── index.tsx # Home tab
│ │ ├── explore.tsx # Explore tab
│ │ └── _layout.tsx # Tab layout
│ ├── _layout.tsx # Root layout
│ └── +not-found.tsx # 404 page
├── components/ # Reusable components
├── hooks/ # Custom hooks
├── constants/ # Constants
├── assets/ # Images, fonts, etc.
├── app.json # Expo configuration
└── package.jsontypescript// app/_layout.tsx - Stack navigation import { Stack } from 'expo-router'; export default function RootLayout() { return ( <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <Stack.Screen name="modal" options={{ presentation: 'modal' }} /> </Stack> ); }
typescript// app/(tabs)/_layout.tsx - Tab navigation import { Tabs } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; export default function TabLayout() { return ( <Tabs> <Tabs.Screen name="index" options={{ title: 'Home', tabBarIcon: ({ color }) => <Ionicons name="home" color={color} size={24} />, }} /> <Tabs.Screen name="profile" options={{ title: 'Profile', tabBarIcon: ({ color }) => <Ionicons name="person" color={color} size={24} />, }} /> </Tabs> ); }
typescript// Basic StyleSheet import { StyleSheet, View, Text } from 'react-native'; export function MyComponent() { return ( <View style={styles.container}> <Text style={styles.title}>Hello</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff', }, title: { fontSize: 24, fontWeight: 'bold', }, });
typescript// NativeWind (Tailwind for RN) - Recommended import { View, Text } from 'react-native'; export function MyComponent() { return ( <View className="flex-1 p-4 bg-white"> <Text className="text-2xl font-bold">Hello</Text> </View> ); }
typescript// hooks/useApi.ts import { useState, useEffect } from 'react'; export function useApi<T>(endpoint: string) { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}${endpoint}`); if (!response.ok) throw new Error('API Error'); const json = await response.json(); setData(json); } catch (e) { setError(e as Error); } finally { setLoading(false); } }; fetchData(); }, [endpoint]); return { data, loading, error }; }
typescript// context/AuthContext.tsx import { createContext, useContext, useState, useEffect } from 'react'; import * as SecureStore from 'expo-secure-store'; interface AuthContextType { user: User | null; signIn: (email: string, password: string) => Promise<void>; signOut: () => Promise<void>; } const AuthContext = createContext<AuthContextType | null>(null); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState<User | null>(null); useEffect(() => { // Check for stored token on app start const loadToken = async () => { const token = await SecureStore.getItemAsync('authToken'); if (token) { // Load user info with token } }; loadToken(); }, []); const signIn = async (email: string, password: string) => { const response = await fetch('/api/auth/login', { method: 'POST', body: JSON.stringify({ email, password }), }); const { token, user } = await response.json(); await SecureStore.setItemAsync('authToken', token); setUser(user); }; const signOut = async () => { await SecureStore.deleteItemAsync('authToken'); setUser(null); }; return ( <AuthContext.Provider value={{ user, signIn, signOut }}> {children} </AuthContext.Provider> ); } export const useAuth = () => useContext(AuthContext)!;
bash# After installing Flutter SDK flutter create my_app cd my_app # Start development server flutter run
my_app/
├── lib/
│ ├── main.dart # App entry point
│ ├── app/
│ │ ├── app.dart # MaterialApp setup
│ │ └── routes.dart # Route definitions
│ ├── features/ # Feature-based folders
│ │ ├── auth/
│ │ │ ├── screens/
│ │ │ ├── widgets/
│ │ │ └── providers/
│ │ └── home/
│ ├── shared/
│ │ ├── widgets/ # Common widgets
│ │ ├── services/ # API services
│ │ └── models/ # Data models
│ └── core/
│ ├── theme/ # Theme settings
│ └── constants/ # Constants
├── assets/ # Images, fonts
├── pubspec.yaml # Dependency management
└── android/ & ios/ # Native codedart// lib/features/home/screens/home_screen.dart import 'package:flutter/material.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: const Center( child: Text('Hello, Flutter!'), ), floatingActionButton: FloatingActionButton( onPressed: () {}, child: const Icon(Icons.add), ), ); } }
dart// lib/providers/counter_provider.dart import 'package:flutter_riverpod/flutter_riverpod.dart'; final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) { return CounterNotifier(); }); class CounterNotifier extends StateNotifier<int> { CounterNotifier() : super(0); void increment() => state++; void decrement() => state--; }
dart// Usage class CounterScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(counterProvider); return Text('Count: $count'); } }
| Element | Web | Mobile | |---------|-----|--------| | Click | onClick | onPress | | Scroll | overflow: scroll | ScrollView / FlatList | | Input | input | TextInput | | Links | a href | Link / navigation | | Layout | div + CSS | View + StyleSheet |
Web: URL-based (browser back button)
Mobile: Stack-based (screen stacking)
Web: /users/123
Mobile: navigation.navigate('User', { id: 123 })Web: localStorage, sessionStorage, Cookie
Mobile: AsyncStorage, SecureStore, SQLite
⚠️ SecureStore is required for sensitive info on mobile!bash# Install EAS CLI npm install -g eas-cli # Login eas login # Configure build eas build:configure # iOS build eas build --platform ios # Android build eas build --platform android # Submit to stores eas submit --platform ios eas submit --platform android
json// app.json { "expo": { "extra": { "apiUrl": "https://api.example.com" } } }
typescript// Usage import Constants from 'expo-constants'; const apiUrl = Constants.expoConfig?.extra?.apiUrl;
□ Identify data that needs offline caching
□ Define sync conflict resolution strategy□ Follow iOS/Android native UX guidelines
□ Consider gestures (swipe, pinch, etc.)
□ Layout for different screen sizes (phone, tablet)□ Keyboard handling (screen adjustment during input)
□ Safe Area handling (notch, home button area)
□ Handle platform-specific UI differences□ Store sensitive info with SecureStore
□ Certificate Pinning (if needed)
□ App obfuscation settings□ Follow App Store review guidelines
□ Prepare Privacy Policy URL
□ Prepare screenshots, app descriptionA: Recommend separate project over full conversion
- APIs can be shared
- UI needs to be rewritten (for native UX)
- Business logic can be sharedA: Start with Expo!
- 90%+ of apps are sufficient with Expo
- Can eject later if needed
- Use CLI only when native modules are absolutely requiredA:
- iOS: 1-7 days (average 2-3 days)
- Android: Few hours ~ 3 days
⚠️ First submission has high rejection possibility → Follow guidelines carefully!"Set up a [app description] app project with React Native + Expo.
Configure with 3 tab navigation (Home, Search, Profile).""Implement [screen name] screen.
- Display [content] at the top
- Display [list/form/etc.] in the middle
- [Button/navigation] at the bottom""Implement screen integrating with [API endpoint].
- Show loading state
- Handle errors
- Support pull-to-refresh"Other measured skills in the registry, with their headline benchmark lift.