| name | mobile-app |
| classification | capability |
| classification-reason | Specialized domain knowledge with limited model overlap |
| deprecation-risk | low |
| effort | low |
| description | Mobile app development guide โ React Native, Flutter, Expo for cross-platform.
Triggers: mobile app, React Native, Flutter, Expo, iOS, Android, ๋ชจ๋ฐ์ผ ์ฑ.
|
| agent | bkit:pipeline-guide |
| allowed-tools | ["Read","Write","Edit","Glob","Grep","Bash","WebSearch"] |
| user-invocable | true |
Mobile App Development Expertise
Overview
A guide for developing mobile apps based on web development experience.
Develop for iOS and Android simultaneously using cross-platform frameworks.
Framework Selection Guide
Framework Selection by Tier (v1.3.0)
| 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
Level-wise Recommendations
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 UI
Expo (React Native) Guide
Project Creation
npm install -g expo-cli
npx create-expo-app my-app
cd my-app
npx expo start
Folder Structure
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.json
Navigation Patterns
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>
);
}
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>
);
}
Styling Patterns
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',
},
});
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>
);
}
API Integration
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 };
}
Authentication Pattern
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(() => {
const loadToken = async () => {
const token = await SecureStore.getItemAsync('authToken');
if (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)!;
Flutter Guide
Project Creation
flutter create my_app
cd my_app
flutter run
Folder Structure
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 code
Basic Widget Patterns
// 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),
),
);
}
}
State Management (Riverpod)
// 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--;
}
// Usage
class CounterScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
}
}
Web vs Mobile Differences
UI/UX Differences
| Element | Web | Mobile |
|---|
| Click | onClick | onPress |
| Scroll | overflow: scroll | ScrollView / FlatList |
| Input | input | TextInput |
| Links | a href | Link / navigation |
| Layout | div + CSS | View + StyleSheet |
Navigation Differences
Web: URL-based (browser back button)
Mobile: Stack-based (screen stacking)
Web: /users/123
Mobile: navigation.navigate('User', { id: 123 })
Storage Differences
Web: localStorage, sessionStorage, Cookie
Mobile: AsyncStorage, SecureStore, SQLite
โ ๏ธ SecureStore is required for sensitive info on mobile!
Build & Deployment
Expo EAS Build
npm install -g eas-cli
eas login
eas build:configure
eas build --platform ios
eas build --platform android
eas submit --platform ios
eas submit --platform android
Environment Variables
{
"expo": {
"extra": {
"apiUrl": "https://api.example.com"
}
}
}
import Constants from 'expo-constants';
const apiUrl = Constants.expoConfig?.extra?.apiUrl;
Mobile PDCA Checklist
Phase 1: Schema
โก Identify data that needs offline caching
โก Define sync conflict resolution strategy
Phase 3: Mockup
โก Follow iOS/Android native UX guidelines
โก Consider gestures (swipe, pinch, etc.)
โก Layout for different screen sizes (phone, tablet)
Phase 6: UI
โก Keyboard handling (screen adjustment during input)
โก Safe Area handling (notch, home button area)
โก Handle platform-specific UI differences
Phase 7: Security
โก Store sensitive info with SecureStore
โก Certificate Pinning (if needed)
โก App obfuscation settings
Phase 9: Deployment
โก Follow App Store review guidelines
โก Prepare Privacy Policy URL
โก Prepare screenshots, app description
Frequently Asked Questions
Q: Can I convert a web project to an app?
A: Recommend separate project over full conversion
- APIs can be shared
- UI needs to be rewritten (for native UX)
- Business logic can be shared
Q: Should I use Expo or React Native CLI?
A: Start with Expo!
- 90%+ of apps are sufficient with Expo
- Can eject later if needed
- Use CLI only when native modules are absolutely required
Q: How long does app review take?
A:
- iOS: 1-7 days (average 2-3 days)
- Android: Few hours ~ 3 days
โ ๏ธ First submission has high rejection possibility โ Follow guidelines carefully!
Requesting from Claude
Project Creation
"Set up a [app description] app project with React Native + Expo.
Configure with 3 tab navigation (Home, Search, Profile)."
Screen Implementation
"Implement [screen name] screen.
- Display [content] at the top
- Display [list/form/etc.] in the middle
- [Button/navigation] at the bottom"
API Integration
"Implement screen integrating with [API endpoint].
- Show loading state
- Handle errors
- Support pull-to-refresh"