capacitor-expert
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:
- Web layer -- HTML/CSS/JS app running inside a native WebView (WKWebView on iOS, Android System WebView on Android).
- Native bridge -- Serializes JS plugin calls, routes them to native code, and returns results as Promises.
- 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:
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.
Creating a New App
Quick Start
# 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.
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.
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 inngOnDestroy.
For details, see capacitor-angular.
React
- Create custom hooks (
useCamera,useNetwork) that wrap Capacitor plugins. - Use
useEffectfor listener registration with cleanup to prevent memory leaks. - React 18 strict mode double-mounts -- ensure cleanup functions work correctly.
For details, see capacitor-react.
Vue
- Create composables (
useCamera,useNetwork) using Vue 3 Composition API. - Register listeners in
onMounted, remove inonUnmounted. - Vue reactivity picks up
refchanges automatically (no NgZone equivalent needed).
For details, see capacitor-vue.
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
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
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.
Plugin Development
Create custom Capacitor plugins with native iOS (Swift) and Android (Java/Kotlin) implementations:
- Scaffold with
npm init @capacitor/plugin@latest. - Define the TypeScript API in
src/definitions.ts. - Implement the web layer in
src/web.ts. - Implement iOS plugin in
ios/Sources/. - Implement Android plugin in
android/src/main/java/. - Verify with
npm run verify.
Key rules:
- The
registerPlugin()name insrc/index.tsmust matchjsNameon iOS and@CapacitorPlugin(name = "...")on Android. - iOS methods need
@objcand must be listed inpluginMethods(CAPBridgedPlugin). - Android methods need
@PluginMethod()annotation and must bepublic.
For full details, see capacitor-plugin-development.
Cross-Platform Best Practices
Platform Detection
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:
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 instead of many individual calls.
- Use file paths over base64 for binary data.
- Lazy-load plugins with dynamic imports for code splitting.
Error Handling
Always wrap plugin calls in try-catch:
try {
const photo = await Camera.getPhoto({ resultType: CameraResultType.Uri });
} catch (error) {
if (error.message === 'User cancelled photos app') {
// Not an error
} else {
console.error('Camera error:', error);
}
}
For full details, see Cross-Platform Best Practices.
Deep Links
Deep links open specific content in the app from external URLs.
- iOS: Universal Links via
apple-app-site-associationhosted athttps://<domain>/.well-known/. - Android: App Links via
assetlinks.jsonhosted athttps://<domain>/.well-known/.
Listener Setup
import { App } from '@capacitor/app';
App.addListener('appUrlOpen', (event) => {
const path = new URL(event.url).pathname;
// Route to the appropriate page
});
Platform Configuration
- iOS: Add
applinks:<domain>to Associated Domains capability inios/App/App/App.entitlements. - Android: Add
<intent-filter android:autoVerify="true">toandroid/app/src/main/AndroidManifest.xml.
For full setup, see Deep Links.
Storage
| Requirement | Solution |
|---|---|
| App settings, preferences | @capacitor/preferences (native key-value, persists reliably) |
| Sensitive data (tokens, credentials) | @capawesome-team/capacitor-secure-preferences (Keychain/Keystore) |
| Relational data, offline-first | SQLite (@capawesome-team/capacitor-sqlite or @capacitor-community/sqlite) |
| Files, images, documents | @capacitor/filesystem |
Do NOT use localStorage, IndexedDB, or cookies for persistent data -- the OS can evict them (especially on iOS).
For details, see Storage.
Security
- Never embed secrets (API keys with write access, OAuth secrets, DB credentials) in client code -- move to a server API.
- Use secure storage (
@capawesome-team/capacitor-secure-preferences) for tokens and credentials, notlocalStorageor@capacitor/preferences. - HTTPS only -- never allow cleartext HTTP in production.
- Content Security Policy -- add a
<meta>CSP tag inindex.html. - Disable WebView debugging in production: set
webContentsDebuggingEnabled: falseincapacitor.config.ts. - Prefer Universal/App Links over custom URL schemes (verified via HTTPS).
- iOS Privacy Manifest (
PrivacyInfo.xcprivacy) -- required for iOS 17+ when using privacy-sensitive APIs.
For details, see Security.
Testing
Unit Testing
Mock Capacitor plugins in Jest/Vitest since tests run in Node.js, not a WebView:
vi.mock('@capacitor/camera', () => ({
Camera: {
getPhoto: vi.fn().mockResolvedValue({
webPath: 'https://example.com/photo.jpg',
}),
},
}));
E2E Testing
- Web E2E: Cypress or Playwright (tests web layer, plugins must be mocked).
- Native E2E: Appium (cross-platform) or Detox (iOS-focused).
Debugging
- Android: Enable
webContentsDebuggingEnabled: true, openchrome://inspectin Chrome. - iOS: Enable
webContentsDebuggingEnabled: true, use Safari > Develop menu > select device.
For details, see Testing.
Troubleshooting
Android
npx cap syncfails: Verify@capacitor/coreand@capacitor/cliversions match. Runcd android && ./gradlew clean.- Build fails after config changes: Clean with
cd android && ./gradlew clean, then rebuild. - Plugin not found at runtime: Run
npx cap syncafter plugin installation. Verify Gradle sync completed. - SDK errors: Verify
ANDROID_HOMEis set. Install missing SDK versions via Android Studio SDK Manager. - White square notification icon: Push notification icons must be white pixels on transparent background.
iOS
- Build fails with "no such module": Run
npx cap sync ios. For CocoaPods:cd ios/App && pod install --repo-update. - Build fails after config changes: Clean build folder (Xcode Product > Clean Build Folder) or delete
ios/App/Podsand re-runpod install. - Simulator cannot receive push notifications: Use a physical device for push notification testing.
- Permission denied permanently: Cannot re-request on iOS. Guide user to Settings > App > Permissions.
- WebView not loading: Verify
webDirincapacitor.config.tsmatches the actual build output directory.
General
- Live reload not connecting: Ensure device and dev machine are on the same network. Use
--externalflag. - Plugin not found: Run
npx cap sync. Verify plugin is inpackage.jsondependencies. Capacitor is not defined: Install@capacitor/core(npm install @capacitor/core).
For full troubleshooting, see Android Troubleshooting and iOS Troubleshooting.
Upgrading
Capacitor supports upgrades across major versions (4 through 8). Apply each major version jump sequentially -- do not skip intermediate versions.
| Current to Target | Node.js | Xcode | Android Studio |
|---|---|---|---|
| to 5 | 16+ | 14.1+ | Flamingo 2022.2.1+ |
| to 6 | 18+ | 15.0+ | Hedgehog 2023.1.1+ |
| to 7 | 20+ | 16.0+ | Ladybug 2024.2.1+ |
| to 8 | 22+ | 26.0+ | Otter 2025.2.1+ |
Quick automated upgrade:
npx cap migrate
npx cap sync
If npx cap migrate fails partially, apply manual steps from the upgrade guides.
For app upgrades, see capacitor-app-upgrades. For plugin upgrades, see capacitor-plugin-upgrades.
Capawesome Cloud
Capawesome Cloud provides cloud infrastructure for Capacitor apps: native builds, live updates, and automated app store publishing.
Website: capawesome.io | Cloud Services: cloud.capawesome.io
Getting Started
# Install and authenticate
npx @capawesome/cli login
# Create an app
npx @capawesome/cli apps:create
Live Updates
Deploy over-the-air (OTA) web updates to Capacitor apps without going through the app stores. Users receive updates immediately on next app launch.
Setup:
# Install the live update plugin
npm install @capawesome/capacitor-live-update
npx cap sync
Configure in capacitor.config.ts:
const config: CapacitorConfig = {
plugins: {
LiveUpdate: {
appId: '<APP_ID>',
autoUpdate: true,
},
},
};
Deploy an update:
npm run build
npx @capawesome/cli apps:liveupdates:upload --app-id <APP_ID>
Native Builds
Build iOS and Android apps in the cloud without local build environments. Supports signing certificates, environments, and build configuration.
# Trigger a build
npx @capawesome/cli apps:builds:create --app-id <APP_ID> --platform android
# Download the artifact
npx @capawesome/cli apps:builds:download --app-id <APP_ID> --build-id <BUILD_ID>
App Store Publishing
Automate submissions to Apple App Store (TestFlight) and Google Play Store.
# Create a deployment destination
npx @capawesome/cli apps:destinations:create --app-id <APP_ID>
# Deploy a build
npx @capawesome/cli apps:deployments:create --app-id <APP_ID> --build-id <BUILD_ID>
CI/CD Integration
Use token-based auth for CI/CD pipelines:
npx @capawesome/cli login --token <TOKEN>
npx @capawesome/cli apps:builds:create --app-id <APP_ID> --platform ios --detached
For full Capawesome Cloud setup, see capawesome-cloud. For the Capawesome CLI reference, see capawesome-cli.
Push Notifications
Set up push notifications using Firebase Cloud Messaging (FCM) via @capacitor-firebase/messaging:
npm install @capacitor-firebase/messaging firebase
npx cap sync
Requires Firebase project setup, platform-specific configuration (APNs for iOS, google-services.json for Android), and permission handling.
For the full setup guide, see capacitor-push-notifications.
In-App Purchases
Set up in-app purchases and subscriptions with either:
- Capawesome Purchases (
@capawesome-team/capacitor-purchases) -- lightweight, no third-party backend, requires Capawesome Insiders license. - RevenueCat (
@revenuecat/purchases-capacitor) -- full managed backend with receipt validation, analytics, and integrations.
Both require App Store Connect (iOS) and/or Google Play Console (Android) product configuration.
For the full setup guide, see capacitor-in-app-purchases.
Related Skills
- capacitor-app-creation -- Create a new Capacitor app from scratch.
- capacitor-app-development -- General Capacitor development topics, configuration, and troubleshooting.
- capacitor-angular -- Angular-specific Capacitor patterns.
- capacitor-react -- React-specific Capacitor patterns.
- capacitor-vue -- Vue-specific Capacitor patterns.
- capacitor-plugins -- Install and configure 160+ Capacitor plugins.
- capacitor-plugin-development -- Create custom Capacitor plugins.
- capacitor-app-upgrades -- Upgrade Capacitor apps across major versions.
- capacitor-plugin-upgrades -- Upgrade Capacitor plugins across major versions.
- capacitor-push-notifications -- Push notifications with FCM.
- capacitor-in-app-purchases -- In-app purchases and subscriptions.
- capawesome-cloud -- Live updates, native builds, app store publishing.
- capawesome-cli -- Capawesome CLI reference.