Claude
Skills
Sign in
Back

capacitor-expert

Included with Lifetime
$97 forever

A comprehensive starting point for AI agents to work with Capacitor. Covers core concepts, CLI, app creation, plugins, framework integration, best practices, storage, security, testing, troubleshooting, upgrading, and Capawesome Cloud (live updates, native builds, app store publishing). Pair with the other Capacitor skills in this collection for deeper topic-specific guidance.

Cloud & DevOps

What this skill does


# Capacitor Expert

Comprehensive reference for building cross-platform apps with Capacitor. Covers architecture, CLI, plugins, framework integration, best practices, and Capawesome Cloud.

## Core Concepts

Capacitor is a cross-platform native runtime for building web apps that run natively on iOS, Android, and the web. The web app runs in a native WebView, and Capacitor provides a bridge to native APIs via plugins.

### Architecture

A Capacitor app has three layers:

1. **Web layer** -- HTML/CSS/JS app running inside a native WebView (WKWebView on iOS, Android System WebView on Android).
2. **Native bridge** -- Serializes JS plugin calls, routes them to native code, and returns results as Promises.
3. **Native layer** -- Swift/ObjC (iOS) and Kotlin/Java (Android) code implementing native functionality.

Data passed across the bridge must be JSON-serializable. Pass files as paths, not base64.

### Project Structure

```
my-app/
  android/                  # Native Android project (committed to VCS)
  ios/                      # Native iOS project (committed to VCS)
    App/
      App/                  # iOS app source files
      App.xcodeproj/
  src/                      # Web app source code
  dist/ or www/ or build/   # Built web assets
  capacitor.config.ts       # Capacitor configuration
  package.json
```

The `android/` and `ios/` directories are full native projects -- they are committed to version control and can be modified directly.

### Capacitor Config

`capacitor.config.ts` (preferred) or `capacitor.config.json` controls app behavior:

```typescript
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'My App',
  webDir: 'dist',
  server: {
    // androidScheme: 'https', // default in Cap 6+
  },
};

export default config;
```

For details, see [App Configuration](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-app-development/references/app-configuration.md).

## Creating a New App

### Quick Start

```bash
# 1. Create a web app (React example with Vite)
npm create vite@latest my-app -- --template react-ts
cd my-app && npm install

# 2. Install Capacitor
npm install @capacitor/core
npm install -D @capacitor/cli

# 3. Initialize Capacitor
npx cap init "My App" com.example.myapp --web-dir dist

# 4. Build web assets
npm run build

# 5. Add platforms
npm install @capacitor/android @capacitor/ios
npx cap add android
npx cap add ios

# 6. Sync and run
npx cap sync
npx cap run android
npx cap run ios
```

**Web asset directories by framework:**
- Angular: `dist/<project-name>/browser` (Angular 17+ with application builder)
- React (Vite): `dist`
- Vue (Vite): `dist`
- Vanilla: `www`

For the full guided creation flow, see [capacitor-app-creation](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-app-creation/SKILL.md).

## Capacitor CLI

All commands: `npx cap <command>`. Most important commands:

| Command | Purpose |
| ------- | ------- |
| `npx cap init <name> <id>` | Initialize Capacitor in a project |
| `npx cap add <platform>` | Add Android or iOS platform |
| `npx cap sync` | Copy web assets + update native dependencies (run after every plugin install, config change, or web build) |
| `npx cap copy` | Copy web assets only (faster, no native dependency update) |
| `npx cap run <platform>` | Build, sync, and deploy to device/emulator |
| `npx cap run <platform> -l --external` | Run with live reload |
| `npx cap open <platform>` | Open native project in IDE |
| `npx cap build <platform>` | Build native project |
| `npx cap doctor` | Diagnose configuration issues |
| `npx cap ls` | List installed plugins |
| `npx cap migrate` | Automated upgrade to newer Capacitor version |

For the full CLI reference, see [CLI Reference](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-app-development/references/cli.md).

## Framework Integration

Capacitor works with any web framework. Framework-specific patterns:

### Angular

- Wrap Capacitor plugins in Angular services for DI and testability.
- Plugin event listeners run outside NgZone -- always wrap callbacks in `NgZone.run()`.
- Register listeners in `ngOnInit`, remove in `ngOnDestroy`.

For details, see [capacitor-angular](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-angular/SKILL.md).

### React

- Create custom hooks (`useCamera`, `useNetwork`) that wrap Capacitor plugins.
- Use `useEffect` for listener registration with cleanup to prevent memory leaks.
- React 18 strict mode double-mounts -- ensure cleanup functions work correctly.

For details, see [capacitor-react](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-react/SKILL.md).

### Vue

- Create composables (`useCamera`, `useNetwork`) using Vue 3 Composition API.
- Register listeners in `onMounted`, remove in `onUnmounted`.
- Vue reactivity picks up `ref` changes automatically (no NgZone equivalent needed).

For details, see [capacitor-vue](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-vue/SKILL.md).

## Plugins

Plugins are Capacitor's extension mechanism. Each plugin exposes a JS API backed by native implementations.

### Plugin Sources

- **Official** (`@capacitor/*`) -- Camera, Filesystem, Geolocation, Preferences, etc.
- **Capawesome** (`@capawesome/*`, `@capawesome-team/*`) -- SQLite, NFC, Biometrics, Live Update, etc.
- **Community** (`@capacitor-community/*`) -- AdMob, BLE, SQLite, Stripe, etc.
- **Firebase** (`@capacitor-firebase/*`) -- Analytics, Auth, Messaging, Firestore, etc.
- **MLKit** (`@capacitor-mlkit/*`) -- Barcode scanning, face detection, translation.
- **RevenueCat** (`@revenuecat/purchases-capacitor`) -- In-app purchases.

### Installing a Plugin

```bash
npm install @capacitor/camera
npx cap sync
```

After installation, apply any required platform configuration (permissions in `AndroidManifest.xml`, `Info.plist` entries, etc.) as documented by the plugin.

### Using a Plugin

```typescript
import { Camera, CameraResultType } from '@capacitor/camera';

const photo = await Camera.getPhoto({
  quality: 90,
  resultType: CameraResultType.Uri,
});
```

For the full plugin index (160+ plugins) and setup guides, see [capacitor-plugins](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-plugins/SKILL.md).

## Plugin Development

Create custom Capacitor plugins with native iOS (Swift) and Android (Java/Kotlin) implementations:

1. Scaffold with `npm init @capacitor/plugin@latest`.
2. Define the TypeScript API in `src/definitions.ts`.
3. Implement the web layer in `src/web.ts`.
4. Implement iOS plugin in `ios/Sources/`.
5. Implement Android plugin in `android/src/main/java/`.
6. Verify with `npm run verify`.

Key rules:
- The `registerPlugin()` name in `src/index.ts` must match `jsName` on iOS and `@CapacitorPlugin(name = "...")` on Android.
- iOS methods need `@objc` and must be listed in `pluginMethods` (CAPBridgedPlugin).
- Android methods need `@PluginMethod()` annotation and must be `public`.

For full details, see [capacitor-plugin-development](https://github.com/capawesome-team/skills/blob/main/skills/capacitor-plugin-development/SKILL.md).

## Cross-Platform Best Practices

### Platform Detection

```typescript
import { Capacitor } from '@capacitor/core';

const platform = Capacitor.getPlatform(); // 'android' | 'ios' | 'web'
if (Capacitor.isNativePlatform()) { /* native-only code */ }
if (Capacitor.isPluginAvailable('Camera')) { /* plugin available */ }
```

### Permissions

Follow the check-then-request pattern:

```typescript
const status = await Camera.checkPermissions();
if (status.camera !== 'granted') {
  const requested = await Camera.requestPermissions();
  if (requested.camera === 'denied') {
    // Guide user to app settings -- cannot re-request on iOS
    return;
  }
}
const photo = await Camera.getPhoto({ ... });
```

### Performance

- **Minimize bridge calls** -- batch operations 

Related in Cloud & DevOps