Mobile Expert
The Mobile Expert agent specializes in mobile application development for iOS, Android, and cross-platform solutions.
Expertise Areas#
- React Native - Components, navigation, native modules
- Expo - Managed workflow, EAS Build, OTA updates
- Flutter - Widgets, state management, platform channels
- Native Development - Swift/SwiftUI, Kotlin/Jetpack Compose
- Mobile Patterns - Offline-first, push notifications, deep linking
- App Store - Submission, guidelines, optimization
Usage Examples#
React Native App#
Use the mobile-expert agent to create a React Native app structure for a food delivery app.
Response includes:
- Project structure
- Navigation setup
- State management
- API integration patterns
Expo Setup#
Use the mobile-expert agent to set up Expo with EAS Build for our team.
Response includes:
- Expo configuration
- EAS Build setup
- Environment management
- OTA update strategy
Mobile UI#
Use the mobile-expert agent to build a swipeable card component like Tinder.
Response includes:
- Gesture handling
- Animation implementation
- Performance optimization
- Platform-specific code
React Native Patterns#
Project Structure#
src/
├── app/ # App entry, providers
├── components/ # Reusable components
│ ├── ui/ # Base UI components
│ └── features/ # Feature-specific components
├── screens/ # Screen components
├── navigation/ # Navigation configuration
├── hooks/ # Custom hooks
├── services/ # API, storage, etc.
├── store/ # State management
├── utils/ # Utilities
├── types/ # TypeScript types
└── constants/ # App constants
Navigation Setup#
1// navigation/RootNavigator.tsx
2import { NavigationContainer } from '@react-navigation/native';
3import { createNativeStackNavigator } from '@react-navigation/native-stack';
4import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
5
6const Stack = createNativeStackNavigator<RootStackParamList>();
7const Tab = createBottomTabNavigator<MainTabParamList>();
8
9function MainTabs() {
10 return (
11 <Tab.Navigator
12 screenOptions={({ route }) => ({
13 tabBarIcon: ({ focused, color, size }) => {
14 const icons = {
15 Home: focused ? 'home' : 'home-outline',
16 Search: focused ? 'search' : 'search-outline',
17 Profile: focused ? 'person' : 'person-outline',
18 };
19 return <Ionicons name={icons[route.name]} size={size} color={color} />;
20 },
21 })}
22 >
23 <Tab.Screen name="Home" component={HomeScreen} />
24 <Tab.Screen name="Search" component={SearchScreen} />
25 <Tab.Screen name="Profile" component={ProfileScreen} />
26 </Tab.Navigator>
27 );
28}
29
30export function RootNavigator() {
31 const { isAuthenticated } = useAuth();
32
33 return (
34 <NavigationContainer>
35 <Stack.Navigator screenOptions={{ headerShown: false }}>
36 {!isAuthenticated ? (
37 <Stack.Screen name="Auth" component={AuthNavigator} />
38 ) : (
39 <>
40 <Stack.Screen name="Main" component={MainTabs} />
41 <Stack.Screen name="Details" component={DetailsScreen} />
42 </>
43 )}
44 </Stack.Navigator>
45 </NavigationContainer>
46 );
47}Custom Hooks#
1// hooks/useApi.ts
2export function useApi<T>(
3 fetcher: () => Promise<T>,
4 deps: any[] = []
5) {
6 const [data, setData] = useState<T | null>(null);
7 const [loading, setLoading] = useState(true);
8 const [error, setError] = useState<Error | null>(null);
9
10 useEffect(() => {
11 let cancelled = false;
12
13 setLoading(true);
14 fetcher()
15 .then((result) => {
16 if (!cancelled) {
17 setData(result);
18 setError(null);
19 }
20 })
21 .catch((err) => {
22 if (!cancelled) {
23 setError(err);
24 }
25 })
26 .finally(() => {
27 if (!cancelled) {
28 setLoading(false);
29 }
30 });
31
32 return () => {
33 cancelled = true;
34 };
35 }, deps);
36
37 return { data, loading, error, refetch: () => fetcher() };
38}
39
40// hooks/useKeyboard.ts
41export function useKeyboard() {
42 const [keyboardHeight, setKeyboardHeight] = useState(0);
43 const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
44
45 useEffect(() => {
46 const showListener = Keyboard.addListener('keyboardDidShow', (e) => {
47 setKeyboardHeight(e.endCoordinates.height);
48 setIsKeyboardVisible(true);
49 });
50
51 const hideListener = Keyboard.addListener('keyboardDidHide', () => {
52 setKeyboardHeight(0);
53 setIsKeyboardVisible(false);
54 });
55
56 return () => {
57 showListener.remove();
58 hideListener.remove();
59 };
60 }, []);
61
62 return { keyboardHeight, isKeyboardVisible };
63}Expo Configuration#
app.json / app.config.js#
1// app.config.js
2export default {
3 expo: {
4 name: 'MyApp',
5 slug: 'my-app',
6 version: '1.0.0',
7 orientation: 'portrait',
8 icon: './assets/icon.png',
9 splash: {
10 image: './assets/splash.png',
11 resizeMode: 'contain',
12 backgroundColor: '#ffffff',
13 },
14 ios: {
15 bundleIdentifier: 'com.mycompany.myapp',
16 supportsTablet: true,
17 config: {
18 usesNonExemptEncryption: false,
19 },
20 },
21 android: {
22 package: 'com.mycompany.myapp',
23 adaptiveIcon: {
24 foregroundImage: './assets/adaptive-icon.png',
25 backgroundColor: '#ffffff',
26 },
27 },
28 plugins: [
29 'expo-router',
30 [
31 'expo-notifications',
32 {
33 icon: './assets/notification-icon.png',
34 color: '#ffffff',
35 },
36 ],
37 ],
38 extra: {
39 apiUrl: process.env.API_URL,
40 eas: {
41 projectId: 'your-project-id',
42 },
43 },
44 },
45};EAS Build Configuration#
1// eas.json
2{
3 "cli": {
4 "version": ">= 5.0.0"
5 },
6 "build": {
7 "development": {
8 "developmentClient": true,
9 "distribution": "internal",
10 "ios": {
11 "simulator": true
12 }
13 },
14 "preview": {
15 "distribution": "internal",
16 "channel": "preview"
17 },
18 "production": {
19 "channel": "production"
20 }
21 },
22 "submit": {
23 "production": {
24 "ios": {
25 "appleId": "your@email.com",
26 "ascAppId": "123456789"
27 },
28 "android": {
29 "serviceAccountKeyPath": "./google-service-account.json"
30 }
31 }
32 }
33}Mobile-Specific Patterns#
Offline-First#
1// services/offline.ts
2import NetInfo from '@react-native-community/netinfo';
3import AsyncStorage from '@react-native-async-storage/async-storage';
4
5class OfflineQueue {
6 private queue: Array<{ action: string; data: any }> = [];
7
8 async addToQueue(action: string, data: any) {
9 this.queue.push({ action, data });
10 await AsyncStorage.setItem('offline_queue', JSON.stringify(this.queue));
11 }
12
13 async processQueue() {
14 const state = await NetInfo.fetch();
15 if (!state.isConnected) return;
16
17 const stored = await AsyncStorage.getItem('offline_queue');
18 if (!stored) return;
19
20 const queue = JSON.parse(stored);
21 for (const item of queue) {
22 try {
23 await this.processItem(item);
24 } catch (error) {
25 console.error('Failed to process queue item:', error);
26 }
27 }
28
29 await AsyncStorage.removeItem('offline_queue');
30 }
31
32 private async processItem(item: { action: string; data: any }) {
33 // Process based on action type
34 }
35}Push Notifications#
1// services/notifications.ts
2import * as Notifications from 'expo-notifications';
3
4Notifications.setNotificationHandler({
5 handleNotification: async () => ({
6 shouldShowAlert: true,
7 shouldPlaySound: true,
8 shouldSetBadge: true,
9 }),
10});
11
12export async function registerForPushNotifications() {
13 const { status: existingStatus } = await Notifications.getPermissionsAsync();
14 let finalStatus = existingStatus;
15
16 if (existingStatus !== 'granted') {
17 const { status } = await Notifications.requestPermissionsAsync();
18 finalStatus = status;
19 }
20
21 if (finalStatus !== 'granted') {
22 throw new Error('Permission not granted');
23 }
24
25 const token = await Notifications.getExpoPushTokenAsync();
26 return token.data;
27}Sample Prompts#
| Task | Prompt |
|---|---|
| Setup | "Set up a React Native app with Expo and TypeScript" |
| Navigation | "Create a stack + tab navigator with auth flow" |
| Gestures | "Build a pull-to-refresh list with smooth animations" |
| Notifications | "Implement push notifications with deep linking" |
| Performance | "Optimize FlatList for 1000+ items" |
Configuration#
1// bootspring.config.js
2module.exports = {
3 agents: {
4 customInstructions: {
5 'mobile-expert': `
6 - Use Expo managed workflow when possible
7 - Follow platform-specific guidelines
8 - Optimize for performance and battery
9 - Handle offline scenarios
10 - Test on both iOS and Android
11 `,
12 },
13 },
14};Related Agents#
- Frontend Expert - React patterns
- UI/UX Expert - Mobile UI design
- Performance Expert - Mobile optimization