home / skills / popup-studio-ai / bkit-claude-code / mobile-app

mobile-app skill

/skills/mobile-app

This skill guides cross-platform mobile app development with React Native, Expo, and Flutter, helping you ship iOS and Android apps efficiently.

npx playbooks add skill popup-studio-ai/bkit-claude-code --skill mobile-app

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
12.1 KB
---
name: mobile-app
description: |
  Mobile app development guide for cross-platform apps.
  Covers React Native, Flutter, and Expo frameworks.

  Use proactively when user wants to build mobile apps or convert web apps to mobile.

  Triggers: mobile app, React Native, Flutter, Expo, iOS, Android, 모바일 앱, モバイルアプリ, 移动应用,
  aplicación móvil, app móvil, desarrollo móvil,
  application mobile, développement mobile,
  mobile Anwendung, mobile App, mobile Entwicklung,
  applicazione mobile, app mobile, sviluppo mobile

  Do NOT use for: web-only projects, backend-only development, or desktop apps.
agent: bkit:pipeline-guide
allowed-tools:
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - Bash
  - WebSearch
user-invocable: false
---

# 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

```bash
# 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
```

### 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

```typescript
// 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>
  );
}
```

### Styling Patterns

```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>
  );
}
```

### API Integration

```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 };
}
```

### Authentication Pattern

```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)!;
```

---

## Flutter Guide

### Project Creation

```bash
# After installing Flutter SDK
flutter create my_app
cd my_app

# Start development server
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

```dart
// 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)

```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');
  }
}
```

---

## 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

```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
```

### Environment Variables

```json
// app.json
{
  "expo": {
    "extra": {
      "apiUrl": "https://api.example.com"
    }
  }
}
```

```typescript
// Usage
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"
```

Overview

This skill is a practical guide for building cross-platform mobile apps using React Native (Expo and CLI) and Flutter. It focuses on developer workflows, folder structure, navigation, state management, API integration, and production builds. Use it to plan, start, and ship iOS and Android apps while leveraging web experience and AI tooling.

How this skill works

The skill inspects project goals and recommends an appropriate framework tier: Expo (React Native) for rapid starts, React Native CLI for advanced native needs, and Flutter for high-performance multi-platform targets. It provides concrete patterns: project creation commands, recommended folder layouts, navigation and styling examples, API hooks, auth patterns, and build/deploy steps (EAS and Flutter). It also includes a PDCA checklist for mobile-specific concerns like offline sync, security, and app store readiness.

When to use it

  • Starting a new cross-platform mobile app from web or API-first code
  • Converting a web app to a mobile-native UX while reusing business logic
  • Prototyping quickly with Expo and TypeScript and AI assistance
  • Needing consistent UI/UX across iOS and Android with shared code
  • Building multi-platform targets (desktop/embedded) where Flutter’s advantages matter

Best practices

  • Prefer Expo + TypeScript for fast iteration and strong AI tool support; eject only when native modules are required
  • Structure projects by feature and keep reusable components, hooks, and services separate
  • Use secure storage (SecureStore) for sensitive tokens and follow certificate pinning where needed
  • Implement stack + tab navigation patterns and handle safe area, keyboard, and gesture UX
  • Adopt environment variables and CI/EAS build pipelines for reproducible builds and store submissions
  • Plan offline-first data and sync strategies; define conflict resolution in schema phase

Example use cases

  • Create a new Expo app with 3-tab navigation (Home, Search, Profile) and TypeScript templates
  • Build an API-connected feed screen with pull-to-refresh, loading states, and error handling using a useApi hook
  • Migrate business logic from a web app into a mobile project while rewriting UI for native UX patterns
  • Choose Flutter for a multi-platform product needing consistent, high-performance UI across six OS targets
  • Set up EAS builds and automated store submission for iOS and Android

FAQ

Should I start with Expo or React Native CLI?

Start with Expo for most projects—it covers 90%+ use cases and speeds development. Move to React Native CLI only if you need custom native modules or advanced native integrations.

Can I reuse web code when building a mobile app?

Yes for business logic and API services, but rewrite UI for mobile (Views, TextInput, ScrollView) to follow native UX and performance patterns.