Claude Skills Guide

Claude Code Capacitor Hybrid App Development Guide

Building hybrid mobile applications has evolved significantly with modern tooling. Capacitor, the spiritual successor to Cordova, enables developers to create cross-platform apps using web technologies while maintaining access to native device features. When combined with Claude Code, you gain an AI-powered development partner that understands the nuances of hybrid app development across iOS, Android, and web platforms.

This comprehensive guide walks you through building production-ready Capacitor applications with Claude Code, covering project initialization, native feature integration, state management, and deployment strategies.

Why Capacitor for Hybrid App Development

Capacitor represents a modern approach to hybrid development. Unlike its predecessor Cordova, Capacitor treats native code as a first-class citizen and provides a more streamlined integration with native platforms. The framework abstracts platform-specific implementations while giving you direct access to native APIs when needed.

When you use Claude Code alongside Capacitor, you benefit from an AI assistant that comprehends both the web-side JavaScript/TypeScript code and the native configuration files. This holistic understanding enables Claude Code to help you debug cross-platform issues, generate platform-specific code, and optimize your app’s performance across devices.

Consider these compelling reasons to adopt Capacitor for your next mobile project:

Setting Up Your Capacitor Project

Initial Project Creation

Start by creating a new Capacitor project. You can initialize from scratch or add Capacitor to an existing web project. For a fresh start, create a simple React or Vue application first, then add Capacitor:

# Create a new React app
npx create-react-app my-capacitor-app
cd my-capacitor-app

# Install Capacitor CLI
npm install @capacitor/cli @capacitor/core @capacitor/ios @capacitor/android

# Initialize Capacitor
npx cap init "My App" --web-dir build

Claude Code can guide you through this process and help troubleshoot any initialization issues. Simply share your terminal output and ask for assistance:

My Capacitor initialization failed with permission errors on iOS. Help me resolve this and get the project set up correctly.

Configuring Platform Settings

After initialization, you’ll need to configure platform-specific settings. Capacitor uses capacitor.config.ts (or .json) to manage these settings. Claude Code can help you set up proper configurations for different deployment scenarios:

// capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'My Capacitor App',
  webDir: 'build',
  server: {
    androidScheme: 'https',
    // Configure for live reload during development
    url: 'http://192.168.1.100:3000'
  },
  cordova: {
    preferences: {
      ScrollEnabled: 'false',
      Orientation: 'portrait',
      'android-minSdkVersion': '22',
      'android-targetSdkVersion': '33'
    }
  },
  plugins: {
    // Configure plugins here
    SplashScreen: {
      launchShowDuration: 3000,
      backgroundColor: '#ffffff'
    }
  }
};

export default config;

When working with platform configurations, ask Claude Code to explain specific settings:

Explain the capacitor.config.ts settings for optimizing app startup time and explain the differences between iOS and Android configurations.

Integrating Native Features

Using Capacitor Plugins

One of Capacitor’s strongest features is its plugin ecosystem. Plugins provide JavaScript interfaces to native device capabilities. The official plugins cover most common use cases, and community plugins extend functionality further.

Here’s how to integrate the Camera plugin as a practical example:

// services/CameraService.ts
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Directory, Filesystem } from '@capacitor/filesystem';

export interface CapturedPhoto {
  filepath: string;
  webPath: string;
}

export class CameraService {
  async takePicture(): Promise<CapturedPhoto> {
    try {
      const image = await Camera.getPhoto({
        resultType: CameraResultType.Uri,
        source: CameraSource.Camera,
        quality: 90,
        width: 1200,
        height: 1200,
        allowEditing: true
      });

      // Save to app's documents directory
      const filename = `photo_${Date.now()}.${image.format}`;
      await Filesystem.writeFile({
        path: filename,
        data: image.base64String || '',
        directory: Directory.Documents
      });

      return {
        filepath: filename,
        webPath: image.webPath || ''
      };
    } catch (error) {
      console.error('Camera error:', error);
      throw new Error('Failed to capture photo');
    }
  }

  async checkPermissions(): Promise<boolean> => {
    const permission = await Camera.checkPermissions();
    return permission.camera === 'granted';
  }

  async requestPermissions(): Promise<boolean> => {
    const permission = await Camera.requestPermissions();
    return permission.camera === 'granted';
  }
}

Claude Code excels at helping you integrate plugins correctly. When adding new plugins, ask for verification:

Review my CameraService implementation and check if I'm properly handling permissions for both iOS and Android, including the Info.plist and AndroidManifest.xml requirements.

Creating Custom Native Bridges

Sometimes you need functionality beyond what existing plugins provide. Capacitor allows you to create custom plugins that bridge JavaScript to native code. Here’s a streamlined approach using a local plugin:

// Create a simple native bridge without full plugin structure
import { Capacitor } from '@capacitor/core';

// Define the native interface
interface NativeDeviceInfo {
  getDeviceId(): Promise<{ identifier: string }>;
  getBatteryLevel(): Promise<{ level: number }>;
}

// Access native implementation
export function getNativeDeviceInfo(): NativeDeviceInfo | null {
  if (Capacitor.isNativePlatform()) {
    // @ts-ignore - accessing native implementation
    return (window as any).Capacitor?.Plugins?.DeviceInfo;
  }
  return null;
}

// Usage in component
async function getDeviceIdentifier() {
  const native = getNativeDeviceInfo();
  if (native) {
    const result = await native.getDeviceId();
    console.log('Device ID:', result.identifier);
  }
}

State Management in Capacitor Apps

Choosing the Right Approach

State management in Capacitor applications requires consideration of both frontend state and persistent storage. For frontend state, React’s built-in hooks work well, while Capacitor’s Storage plugin handles persistent data:

// stores/appStore.ts
import { create } from 'zustand';
import { Storage } from '@capacitor/storage';

interface AppState {
  user: User | null;
  theme: 'light' | 'dark';
  isLoading: boolean;
  setUser: (user: User | null) => void;
  setTheme: (theme: 'light' | 'dark') => void;
  loadPersistedState: () => Promise<void>;
}

export const useAppStore = create<AppState>((set) => ({
  user: null,
  theme: 'light',
  isLoading: true,
  
  setUser: (user) => {
    set({ user });
    // Persist to capacitor storage
    if (user) {
      Storage.set({ key: 'user', value: JSON.stringify(user) });
    } else {
      Storage.remove({ key: 'user' });
    }
  },
  
  setTheme: (theme) => {
    set({ theme });
    Storage.set({ key: 'theme', value: theme });
  },
  
  loadPersistedState: async () => {
    const [userResult, themeResult] = await Promise.all([
      Storage.get({ key: 'user' }),
      Storage.get({ key: 'theme' })
    ]);
    
    set({
      user: userResult.value ? JSON.parse(userResult.value) : null,
      theme: (themeResult.value as 'light' | 'dark') || 'light',
      isLoading: false
    });
  }
}));

Ask Claude Code to help you design state management:

Design a state management approach for a Capacitor app that needs to sync state between the app and a web dashboard in real-time. Consider using IndexedDB for local storage and suggest a synchronization strategy.

Building and Deployment

iOS Build Configuration

Before building for iOS, ensure your Xcode project is properly configured. Capacitor generates native projects that you can open and modify:

# Sync web assets to iOS
npx cap sync ios

# Open in Xcode
npx cap open ios

In Xcode, configure your signing and capabilities. Key settings include:

Android Build Configuration

Similarly for Android:

# Sync to Android
npx cap sync android

# Open in Android Studio
npx cap open android

For production builds, create a release configuration:

# Generate release build
cd android && ./gradlew assembleRelease

The APK will be located at android/app/build/outputs/apk/release/.

Best Practices and Tips

Development Workflow

  1. Use live reload - Configure Capacitor for development server integration to see changes instantly
  2. Test on real devices - Emulators don’t replicate all native behaviors, especially for sensors and plugins
  3. Keep plugins updated - Regularly update Capacitor and plugins for security and performance fixes
  4. Handle offline scenarios - Implement offline-first architecture using local storage

Performance Optimization

Claude Code can help you optimize your Capacitor app:

Analyze my React components and identify performance bottlenecks in my Capacitor app. Suggest optimizations for rendering performance and memory usage on mobile devices.

Key areas to focus on include:

Debugging Native Issues

Debugging platform-specific failures — crashes, plugin errors, permission denials, and log analysis across iOS and Android — is a deep topic beyond the scope of this development guide. For a step-by-step workflow covering JavaScript runtime errors, native plugin configuration, WebView inspection, and structured investigation with Claude Code skills, see the dedicated Claude Code Capacitor Hybrid App Debugging Workflow.

Conclusion

Building hybrid mobile applications with Capacitor and Claude Code combines the best of modern web development with native platform capabilities. This guide covered the essential aspects of Capacitor development, from project setup to deployment.

Remember these key takeaways:

Continue exploring Capacitor’s capabilities by experimenting with additional plugins, implementing complex native features, and optimizing your app’s performance across all target platforms.

Built by theluckystrike — More at zovo.one