Was ist Capacitor? — Cordova, React Native und der Web-Standard-Ansatz
Capacitor ist eine Open-Source-Laufzeit von Ionic, die Web-Apps in native iOS- und Android-Apps verwandelt — ohne dass du dein Frontend anfassen musst. Im Gegensatz zu älteren Bridging-Lösungen setzt Capacitor konsequent auf Web-Standards.
VergleichCapacitor vs. Cordova vs. React Native
| Kriterium | Capacitor 6 | Cordova | React Native |
| Web-Framework-Agnostisch | ✓ Ja | ✓ Ja | ✗ Nein (React only) |
| Native UI-Komponenten | ✗ WebView | ✗ WebView | ✓ Native |
| TypeScript Support | ✓ First-class | ~ Eingeschränkt | ✓ First-class |
| Plugin-Ökosystem | ✓ Modern, aktiv | ~ Veraltet | ✓ Groß |
| Vorhandene Web-App nutzen | ✓ Direkt | ~ Anpassungen nötig | ✗ Neuschreiben |
| Live Updates (OTA) | ✓ Appflow/Capawesome | ~ CodePush | ✓ CodePush |
| Performance Overhead | ~ WebView | ✗ Hoch | ✓ Gering |
Entscheidungshilfe: Bestehende Vite/Next.js/Angular-App → Capacitor. Neue App mit nativem UI benötigt → React Native/Flutter. Cordova: nicht mehr empfehlenswert für neue Projekte (2026).
ArchitekturWeb-Standard-first — wie Capacitor funktioniert
# Capacitor Architektur 2026
# ┌─────────────────────────────────────────────┐
# │ Deine Web-App (React/Vue/Svelte/Vanilla) │
# │ läuft in einem nativen WebView │
# │ ┌──────────────────────────────────────┐ │
# │ │ Capacitor Bridge (JS ↔ Native) │ │
# │ │ @capacitor/core │ │
# │ └──────────────────────────────────────┘ │
# │ Native Plugins: Camera, Geo, FS, Push... │
# └─────────────────────────────────────────────┘
# ↕ ↕
# iOS (Swift/ObjC) Android (Kotlin/Java)
# Kein Kompilieren des JS-Codes zu nativem Code!
# Web-App bleibt Web-App — läuft im WKWebView (iOS)
# und Android WebView (Chromium-basiert)
# Ionic ist OPTIONAL — Capacitor läuft mit jedem Framework:
npm create vite@latest my-app -- --template react-ts
# → dann Capacitor hinzufügen, ohne Ionic!
Setup und Migration — npx cap init, iOS & Android, Vite/Next.js Integration
Eine bestehende Web-App auf Capacitor zu migrieren dauert mit Claude Code meist unter 30 Minuten. Der Build-Output deiner Web-App wird einfach als WebView-Inhalt verpackt.
SetupNeue App mit Capacitor — Schritt für Schritt
# Prompt für Claude Code:
# "Richte Capacitor für meine Vite/React-App ein,
# füge iOS und Android hinzu, konfiguriere capacitor.config.ts"
# 1. Capacitor installieren
npm install @capacitor/core @capacitor/cli
npm install @capacitor/ios @capacitor/android
# 2. Capacitor initialisieren
npx cap init "MyApp" "com.mycompany.myapp" --web-dir dist
# 3. Web-App bauen (Vite)
npm run build
# 4. Plattformen hinzufügen
npx cap add ios
npx cap add android
# 5. Nativen Code synchronisieren
npx cap sync
# 6. In Xcode / Android Studio öffnen
npx cap open ios
npx cap open android
Configcapacitor.config.ts — alle wichtigen Optionen
// capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.mycompany.myapp',
appName: 'My App',
webDir: 'dist', // Vite → 'dist', Next.js → 'out'
server: {
// Entwicklung: lokalen Dev-Server nutzen (Hot Reload!)
url: 'http://192.168.1.100:5173',
cleartext: true,
allowNavigation: ['*.mybackend.com'],
},
ios: {
scheme: 'myapp',
backgroundColor: '#ffffff',
contentInset: 'automatic',
preferredContentMode: 'mobile',
},
android: {
backgroundColor: '#ffffff',
allowMixedContent: false,
captureInput: true,
webContentsDebuggingEnabled: true, // Nur dev!
},
plugins: {
SplashScreen: {
launchShowDuration: 2000,
backgroundColor: '#ffffff',
androidSplashResourceName: 'splash',
showSpinner: false,
},
PushNotifications: {
presentationOptions: ['badge', 'sound', 'alert'],
},
},
}
export default config
Next.jsNext.js mit Capacitor — Static Export
// next.config.ts — Static Export für Capacitor
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
output: 'export', // Statischen Build erzeugen
distDir: 'out', // capacitor.config: webDir: 'out'
images: {
unoptimized: true, // Kein next/image Optimierungsserver
},
trailingSlash: true, // Für WebView-Navigation wichtig
}
export default nextConfig
// Dann: npm run build && npx cap sync && npx cap open ios
// ⚠ ACHTUNG: next/image, API-Routes, Middleware
// laufen NICHT im Static Export!
// API-Calls → externes Backend nötig (Supabase, eigener Server)
Next.js Einschränkung: Server Components und API-Routes funktionieren nicht im Static-Export-Modus. Für Datenbankzugriff Supabase oder ein externes API-Backend verwenden. Claude Code kennt alle Alternativen und empfiehlt je nach Usecase.
Native Plugins — Camera, Filesystem, Geolocation, Haptics, Share
Capacitor bringt alle wichtigen nativen APIs als offiziell gewartete Plugins mit. Kein Community-Roulette — alle Plugins sind TypeScript-typisiert und werden von Ionic gepflegt.
CameraKamera und Foto-Galerie
# Installation
npm install @capacitor/camera
npx cap sync
// camera.ts — Foto aufnehmen oder aus Galerie wählen
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'
export async function takePhoto() {
const image = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri, // Base64 | DataUrl | Uri
source: CameraSource.Camera, // Camera | Photos | Prompt
width: 1200,
correctOrientation: true,
})
// image.webPath = lokaler URL zum Bild
// image.base64String = Base64-codiertes Bild
return image.webPath
}
export async function pickFromGallery() {
const images = await Camera.pickImages({
quality: 85,
limit: 5,
})
return images.photos.map(p => p.webPath)
}
// iOS: Info.plist — Berechtigungen eintragen (Claude Code macht das automatisch)
// NSCameraUsageDescription = "Wir nutzen die Kamera für Profilfotos"
// NSPhotoLibraryUsageDescription = "Wähle ein Bild aus deiner Galerie"
GeoGeolocation — GPS-Koordinaten und Echtzeit-Tracking
# Installation
npm install @capacitor/geolocation
npx cap sync
// geolocation.ts
import { Geolocation } from '@capacitor/geolocation'
export async function getCurrentPosition() {
// Einmalige Position abfragen
const coords = await Geolocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 10000,
})
return {
lat: coords.coords.latitude,
lng: coords.coords.longitude,
acc: coords.coords.accuracy,
}
}
export function watchPosition(callback: (lat: number, lng: number) => void) {
// Echtzeit-Tracking — gibt watchId zurück
return Geolocation.watchPosition(
{ enableHighAccuracy: true },
(position, err) => {
if (err) { console.error(err); return; }
callback(position!.coords.latitude, position!.coords.longitude)
}
)
}
export async function stopWatching(watchId: string) {
await Geolocation.clearWatch({ id: watchId })
}
Android Manifest: Claude Code fügt automatisch ACCESS_FINE_LOCATION und ACCESS_COARSE_LOCATION ins AndroidManifest.xml ein. iOS benötigt NSLocationWhenInUseUsageDescription in der Info.plist.
FSFilesystem & Haptics & Share — drei weitere Core-Plugins
# Alle auf einmal installieren
npm install @capacitor/filesystem @capacitor/haptics @capacitor/share
npx cap sync
// --- FILESYSTEM: Dateien lokal speichern ---
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'
await Filesystem.writeFile({
path: 'data/user-prefs.json',
data: JSON.stringify({ theme: 'dark', lang: 'de' }),
directory: Directory.Documents,
encoding: Encoding.UTF8,
})
const { data } = await Filesystem.readFile({
path: 'data/user-prefs.json',
directory: Directory.Documents,
encoding: Encoding.UTF8,
})
const prefs = JSON.parse(data as string)
// --- HAPTICS: Vibrationsrückmeldung ---
import { Haptics, ImpactStyle, NotificationType } from '@capacitor/haptics'
await Haptics.impact({ style: ImpactStyle.Medium }) // Light | Medium | Heavy
await Haptics.notification({ type: NotificationType.Success })
await Haptics.vibrate() // Standard-Vibration
// --- SHARE: Nativer Share-Dialog ---
import { Share } from '@capacitor/share'
await Share.share({
title: 'Schau dir das an!',
text: 'Entdecke diese App!',
url: 'https://agentic-movers.com',
dialogTitle: 'Teilen via', // Android only
})
Push Notifications — FCM für Android, APNs für iOS
Push Notifications sind technisch der aufwändigste Teil einer nativen App — sie erfordern Backend-Setup (Firebase/APNs), Zertifikate und Permissions-Handling. Claude Code generiert den vollständigen Setup-Code für beide Plattformen.
Push@capacitor/push-notifications — vollständiger Setup
# Installation
npm install @capacitor/push-notifications
npx cap sync
// push.service.ts — Push Notification Service
import {
PushNotifications,
Token,
ActionPerformed,
PushNotificationSchema
} from '@capacitor/push-notifications'
import { Capacitor } from '@capacitor/core'
export class PushService {
async initialize() {
// Nur auf nativen Plattformen initialisieren
if (!Capacitor.isNativePlatform()) return
// 1. Permission anfragen
const { receive } = await PushNotifications.requestPermissions()
if (receive !== 'granted') {
console.warn('Push-Permissions verweigert')
return
}
// 2. Registrieren bei FCM/APNs
await PushNotifications.register()
// 3. Token erhalten → ans Backend senden
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push Token:', token.value)
// Token an Backend senden:
fetch('/api/push-tokens', {
method: 'POST',
body: JSON.stringify({ token: token.value, platform: Capacitor.getPlatform() }),
headers: { 'Content-Type': 'application/json' },
})
})
// 4. Fehler behandeln
PushNotifications.addListener('registrationError', (err) => {
console.error('Push-Registrierung fehlgeschlagen:', err)
})
// 5. Eingehende Notification (App im Vordergrund)
PushNotifications.addListener(
'pushNotificationReceived',
(notification: PushNotificationSchema) => {
console.log('Push erhalten:', notification.title, notification.body)
// Eigene In-App-Banner anzeigen
}
)
// 6. Tap auf Notification → App-Navigation
PushNotifications.addListener(
'pushNotificationActionPerformed',
(action: ActionPerformed) => {
const data = action.notification.data
if (data?.route) {
// Zur entsprechenden Route navigieren
window.location.href = data.route
}
}
)
}
}
FCMFirebase Cloud Messaging Setup — Android & iOS
# Android: google-services.json in android/app/ legen
# iOS: GoogleService-Info.plist in ios/App/App/ legen
// android/app/build.gradle — FCM Dependency
dependencies {
implementation 'com.google.firebase:firebase-messaging'
}
// ios/App/Podfile — APNs via Firebase
pod 'Firebase/Messaging'
# Backend: Push-Notification senden (Node.js)
// push-sender.ts
import admin from 'firebase-admin'
admin.initializeApp({
credential: admin.credential.applicationDefault(),
})
async function sendPush(token: string, title: string, body: string, route?: string) {
await admin.messaging().send({
token,
notification: { title, body },
data: route ? { route } : {},
apns: {
payload: { aps: { badge: 1, sound: 'default' } }
},
android: {
priority: 'high',
notification: { sound: 'default', channelId: 'default' },
},
})
}
APNs für iOS: Du benötigst ein Apple Developer-Konto (99€/Jahr), ein APNs-Zertifikat und ein Provisioning Profile mit Push Notification Capability. Claude Code generiert alle notwendigen Konfigurationsdateien und erklärt den Zertifikat-Upload zu Firebase.
Deployment: App Store & Play Store — Xcode, Gradle, Signing, App Store Connect
Das Deployment in die offiziellen App-Stores ist der Schritt, der die meisten Entwickler zunächst einschüchtert. Claude Code kennt den vollständigen Prozess für beide Plattformen und generiert Signing-Scripts, Fastlane-Konfigurationen und CI/CD-Pipelines.
iOSiOS Deployment — Xcode, Signing & App Store Connect
# 1. Web-App bauen + Capacitor synchronisieren
npm run build && npx cap sync ios
# 2. Xcode öffnen
npx cap open ios
## In Xcode:
## → Signing & Capabilities → Team auswählen (Apple Developer Account)
## → Bundle Identifier muss mit App Store Connect übereinstimmen
## → Capability: Push Notifications hinzufügen (falls benötigt)
# 3. Fastlane für automatisches iOS-Deployment
# Fastfile
lane :beta do
build_app(
scheme: "App",
workspace: "ios/App/App.xcworkspace",
export_method: "app-store",
export_options: {
provisioningProfiles: {
"com.mycompany.myapp" => "MyApp AppStore Profile"
}
}
)
upload_to_testflight(
api_key_path: "fastlane/api_key.json"
)
end
## App Store Connect API Key (Automatisches Signing)
## → App Store Connect → Users → Keys → New Key erstellen
## → JSON mit key_id, issuer_id, key_content speichern
AndroidAndroid Deployment — Gradle, Keystore & Play Console
# 1. Web-App bauen + Capacitor synchronisieren
npm run build && npx cap sync android
# 2. Keystore erstellen (einmalig — sicher aufbewahren!)
keytool -genkey -v \
-keystore my-release-key.jks \
-alias myapp \
-keyalg RSA \
-keysize 2048 \
-validity 10000
// android/app/build.gradle — Signing Config
android {
signingConfigs {
release {
storeFile file('../../my-release-key.jks')
storePassword System.getenv('KEYSTORE_PASSWORD')
keyAlias System.getenv('KEY_ALIAS')
keyPassword System.getenv('KEY_PASSWORD')
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
shrinkResources false
}
}
}
# 3. Release APK / AAB bauen
cd android && ./gradlew bundleRelease
# Output: android/app/build/outputs/bundle/release/app-release.aab
# → In Google Play Console hochladen (AAB bevorzugt gegenüber APK)
Keystore-Sicherheit: Den Keystore NIEMALS verlieren oder ins öffentliche Git committen! Ohne den originalen Keystore kann kein Update der App veröffentlicht werden. Sichere Aufbewahrung: verschlüsselter Cloud-Speicher + lokales Backup.
CI/CDGitHub Actions — automatisierter Build & Deploy
# .github/workflows/mobile-release.yml
name: Mobile Release
on:
push:
tags: ['v*']
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci && npm run build
- run: npx cap sync android
- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/my-key.jks
- name: Build AAB
run: cd android && ./gradlew bundleRelease
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
packageName: com.mycompany.myapp
releaseFiles: android/app/build/outputs/bundle/release/*.aab
track: internal
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci && npm run build
- run: npx cap sync ios
- run: pod install --project-directory=ios/App
- uses: maierj/fastlane-action@v3
with:
lane: beta
env:
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }}
Live Updates — OTA-Updates ohne Store-Review
Der größte Vorteil von Capacitor gegenüber rein nativen Apps: Du kannst den Web-Teil deiner App jederzeit aktualisieren, ohne einen neuen Store-Release zu benötigen. Dafür gibt es zwei etablierte Lösungen: Ionic Appflow (kommerziell) und Capawesome Updater (open-source).
OTACapawesome Updater — kostenloses OTA-Update
# Installation — Open-Source Alternative zu Appflow
npm install @capawesome/capacitor-app-update
npx cap sync
// updater.service.ts
import { AppUpdate, AppUpdateAvailability } from '@capawesome/capacitor-app-update'
import { Capacitor } from '@capacitor/core'
export async function checkForUpdate() {
if (!Capacitor.isNativePlatform()) return
const result = await AppUpdate.getAppUpdateInfo()
if (result.updateAvailability === AppUpdateAvailability.UPDATE_AVAILABLE) {
const confirmed = await showUpdateDialog(
result.availableVersionName ?? 'Neue Version'
)
if (confirmed) {
// Direkt zum Store weiterleiten
await AppUpdate.openAppStore()
}
}
}
// Für echte OTA (JS-Bundle-Update ohne Store):
// → @capawesome/capacitor-live-update
npm install @capawesome/capacitor-live-update
import { LiveUpdate } from '@capawesome/capacitor-live-update'
export async function applyLiveUpdate() {
await LiveUpdate.sync() // Prüft auf neue Bundle-Version
await LiveUpdate.reload() // App neu laden mit neuem Bundle
}
AppflowIonic Appflow — Enterprise Live Updates
# Ionic Appflow: Kommerziell, aber einfachste Option
# Preise 2026: Starter kostenlos (1000 Live-Updates/Mo)
npm install @ionic/portals # Für Micro-Frontend-Architektur
npm install @capacitor/app # App-State-Listener
// appflow-update.ts — Automatisches Update beim App-Start
import { App } from '@capacitor/app'
import { Deploy } from 'cordova-plugin-ionic'
export async function setupLiveUpdates() {
// Bei App-Resume prüfen (Nutzer kommt aus dem Hintergrund)
App.addListener('resume', async () => {
try {
const update = await Deploy.checkForUpdate()
if (update.available) {
await Deploy.downloadUpdate((progress) => {
console.log(`Download: ${progress}%`)
})
await Deploy.extractUpdate()
await Deploy.reloadApp()
}
} catch (e) {
console.error('Live-Update fehlgeschlagen:', e)
}
})
}
// Appflow-Dashboard: app.ionic.io
// → Channel: "Production" oder "Staging"
// → Deploy-Trigger: Manuell oder via CI/CD
// → Rollback: Single-Click auf jede frühere Version
Apple Store Richtlinien und OTA: Live-Updates dürfen laut Apple-Richtlinien nur den Web-Code (JS/CSS/HTML) aktualisieren — keine neuen nativen Plugins, keine grundlegenden Verhaltensänderungen. Capacitor und Appflow halten sich an diese Grenze. Bei Missachtung riskierst du das App-Store-Listing.
Claude CodePrompts für Capacitor-Entwicklung — Best Practices
# Effektive Claude Code Prompts für Capacitor-Projekte:
# Setup
"Richte Capacitor 6 für meine Vite/React-TypeScript-App ein.
Füge iOS und Android hinzu, konfiguriere capacitor.config.ts
mit SplashScreen und StatusBar Plugin."
# Kamera + Upload
"Erstelle eine CameraService-Klasse mit takePhoto(), pickFromGallery()
und uploadToSupabase(). Nutze @capacitor/camera und @supabase/supabase-js.
Fehlerbehandlung inklusive."
# Push Notifications
"Implementiere Push Notifications mit @capacitor/push-notifications
und Firebase. Erstelle: PushService-Klasse, Backend-Endpoint zum
Token-Speichern (Express/Supabase), und Notification-Sender-Funktion."
# Fastlane CI/CD
"Erstelle GitHub Actions Workflows für iOS (Fastlane + TestFlight)
und Android (Gradle + Play Store Internal Track). Signing via Secrets."
# Live Updates
"Integriere Capawesome Live Update in meine App. Prüfe beim
App-Start auf neue Versionen, zeige einen Update-Dialog an
und lade die App neu. Fehlerbehandlung mit Fallback."
Mit Claude Code zur nativen App — in Stunden statt Wochen
Claude Code kennt alle Capacitor-Patterns, generiert nativen Plattform-Code und erklärt jeden Schritt. Starte deinen 14-Tage-Trial und deploye deine erste mobile App noch heute.
14 Tage kostenlos testen →
Fazit: Wann Capacitor die richtige Wahl ist
Capacitor ist 2026 die erste Wahl, wenn du eine bestehende Web-App ohne Framework-Wechsel als native iOS- und Android-App veröffentlichen möchtest. Die Stärken: Web-Standard-first, TypeScript first-class, aktives Plugin-Ökosystem, OTA-Update-Fähigkeit und volle Unabhängigkeit von Ionic als Framework.
EntscheidungCapacitor vs. Alternativen — wann welche Lösung
| Usecase | Empfehlung |
| Bestehende React/Vue/Svelte-App → native App | Capacitor |
| Neue App, native UI-Performance kritisch | React Native / Flutter |
| PWA reicht aus (kein App Store benötigt) | PWA direkt |
| Ionic-basierte App erneuern | Capacitor |
| Cordova-App migrieren | Capacitor (Drop-in) |
| App mit vielen nativen Animationen | React Native (Reanimated) |
| Cross-Platform Desktop + Mobile | Flutter |
Claude Code übernimmt das Setup, die Plugin-Integration, das Signing und die CI/CD-Pipeline — du fokussierst dich auf das Produkt. Die Kombination aus Capacitor und Claude Code ist 2026 einer der schnellsten Wege, eine Web-App in beiden App-Stores zu veröffentlichen.