In diesem Tutorial starten wir mit einer neuen React App und wechseln zur nativen mobilen Entwicklung mit Capacitor. Du kannst auch Capgo Native Navigation und Transitions für ein natives Feeling hinzufügen und tailwind-capacitor für Safe Areas nutzen.
Capacitor ermöglicht es dir, deine React Web-App einfach in eine native mobile App zu verwandeln, ohne große Änderungen vorzunehmen oder neue Skills wie React Native lernen zu müssen.
Mit nur wenigen einfachen Schritten lassen sich die meisten React-Anwendungen in mobile Apps verwandeln.
Dieses Tutorial führt dich durch den gesamten Prozess: Wir starten mit einer neuen React-App und integrieren dann Capacitor, um den Schritt zu nativen mobilen Apps zu machen. Du kannst außerdem Capgo Native Navigation, Transitions und tailwind-capacitor für Safe Areas nutzen.
Über Capacitor
CapacitorJS ist ein echter Game-Changer! Du kannst es mühelos in jedes Web-Projekt integrieren; es verpackt deine Anwendung in eine native WebView und erstellt die nativen Xcode- und Android Studio-Projekte für dich. Außerdem bieten die Plugins über eine JS-Bridge Zugriff auf native Gerätefunktionen wie die Kamera.
Mit Capacitor erhältst du eine fantastische native mobile App, ganz ohne kompliziertes Setup oder steile Lernkurve. Die schlanke API und die optimierte Funktionalität machen die Integration in dein Projekt zum Kinderspiel. Glaub mir, du wirst staunen, wie einfach es ist, mit Capacitor eine voll funktionsfähige native App zu bauen!
Deine React-App vorbereiten
Es gibt verschiedene Wege, React-Anwendungen zu starten. In diesem Tutorial nutzen wir die einfachste Methode, um eine leere React-App zu erstellen:
npx create-react-app my-app
Um eine native mobile App zu erstellen, benötigen wir eine Export unseres Projekts. Also fügen wir ein einfaches Script in unsere package.json , die zum Build und Export des React-Projekts verwendet werden kann:
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}
Du kannst jetzt npm run build ohne Bedenken ausführen, und du solltest einen neuen out-Ordner im Projektstamm finden.
Dieser Ordner wird später von Capacitor verwendet, aber fürs Erste müssen wir ihn korrekt einrichten.
Capacitor zu deiner React-App hinzufügen
Um eine Web-App in einen nativen Mobile-Container zu verpacken, sind ein paar erste Schritte nötig, danach reicht ein einziger sync Befehl.
Zuerst können wir das Capacitor CLI als Dev-Dependency installieren und dann in unserem Projekt einrichten. Während des Setups kannst du „Enter“ drücken, um die Standardwerte für Name und Bundle ID zu übernehmen.
Als Nächstes müssen wir das Core-Package und die relevanten Packages für iOS und Android installieren.
Schließlich können wir die Plattformen hinzufügen, und Capacitor erstellt für jede Plattform einen Ordner im Wurzelverzeichnis unseres Projekts:
# Install the Capacitor CLI locally
npm install -D @capacitor/cli
# Initialize Capacitor in your React project
npx cap init
# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android
# Add the native platforms
npx cap add ios
npx cap add android
An diesem Punkt solltest du in der Lage sein, neue iOS und Android Ordner in deinem React-Projekt.
Das sind echte native Projekte!
Um später auf das Android-Projekt zuzugreifen, musst du Android Studioinstallieren. Für iOS brauchst du einen Mac und solltest Xcode.
installieren. Außerdem solltest du einen capacitor.config.ts Datei in deinem Projekt, die einige grundlegende Capacitor-Einstellungen enthält, die während des Syncs verwendet werden. Das Einzige, worauf du achten musst, ist die webDir, das auf das Ergebnis deines Build-Befehls zeigen muss. Aktuell ist es nicht korrekt.
Um das zu korrigieren, öffne die capacitor.config.json -Datei und aktualisiere das webDir:
{
"appId": "com.example.app",
"appName": "my-app",
"webDir": "out",
"bundledWebRuntime": false
}
Du kannst es ausprobieren, indem du die folgenden Befehle ausführst:
npm run build
npx cap sync
Der erste Befehl npm run build erstellt einfach dein React-Projekt und exportiert den statischen Build.
Während der zweite Befehl npx cap sync alle Web-code an die richtigen Stellen der nativen Plattformen synchronisiert, damit sie in einer App angezeigt werden können.
Zudem kann der sync-Befehl die nativen Plattformen aktualisieren und Plugins installieren, wenn du ein neues Capacitor Plugins Es ist Zeit zu starten npx cap sync erneut aus.
Ohne es zu merken, bist du nun fertig – schauen wir uns die App also mal auf einem Gerät an!
Native Apps bauen und deployen
Um iOS-Apps zu entwickeln, musst du Xcode installiert haben, und für Android-Apps benötigst du Android Studio installiert haben. Wenn du deine App außerdem im App Store veröffentlichen willst, musst du dich für das Apple Developer Program (iOS) und die Google Play Console (Android) anmelden.
Wenn du neu in der nativen Mobile-Entwicklung bist, kannst du das Capacitor CLI nutzen, um beide nativen Projekte ganz einfach zu öffnen:
npx cap open ios
npx cap open android
Sobald deine nativen Projekte eingerichtet sind, ist das Deployment auf ein verbundenes Gerät kinderleicht. In Android Studio musst du nur warten, bis alles bereit ist, und kannst deine App ohne weitere Einstellungen auf ein verbundenes Gerät deployen. Hier ein Beispiel:

In Xcode musst du dein Signing-Account einrichten, um deine App auf einem echten Gerät statt nur im Simulator zu deployen. Falls du das noch nie gemacht hast, führt dich Xcode durch den Prozess (du musst dafür allerdings im Developer Program angemeldet sein). Danach kannst du einfach auf Play drücken, um die App auf deinem verbundenen Gerät zu starten, das du oben auswählen kannst. Hier ein Beispiel:

Glückwunsch! Du hast deine React-Web-App erfolgreich auf einem mobilen Gerät deployed. Hier ein Beispiel:
Aber Moment, es gibt während der Entwicklung auch einen noch schnelleren Weg…
Capacitor Live Reload
Mittlerweile bist du wahrscheinlich an Hot Reload bei allen modernen Frameworks gewöhnt, und die gute Nachricht ist: Du kannst dieselbe Funktionalität auf einem mobilen Gerät mit minimalem Aufwand nutzen!
Aktiviere den Zugriff auf deine lokal gehostete App mit Live Reload in deinem Netzwerk indem die Capacitor App den Inhalt von der spezifischen URL lädt.
Der erste Schritt ist es, deine lokale IP-Adresse herauszufinden. Wenn du einen Mac nutzt, kannst du dies mit folgendem Befehl im Terminal ermitteln:
ipconfig getifaddr en0
Unter Windows führe aus:
ipconfig
Suche dann nach der IPv4-Adresse.
Wir können Capacitor anweisen, die App direkt vom Server zu laden, indem wir einen weiteren Eintrag in unsere capacitor.config.ts Datei:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: 'out',
bundledWebRuntime: false,
server: {
url: 'http://192.168.x.xx:3000',
cleartext: true
}
};
export default config;
Achte darauf, die richtige IP und den Port zu verwenden, ich habe in diesem Beispiel den Standard-React-Port verwendet.
Jetzt können wir diese Änderungen anwenden, indem wir sie in unser natives Projekt kopieren:
npx cap copy
Der copy Der Befehl ähnelt sync, aber es wird nur Kopiere die Änderungen in den Web-Ordner und die Konfiguration kopieren, ohne das native Projekt zu aktualisieren.
Du kannst deine App nun ein letztes Mal über Android Studio oder Xcode deployen. Wenn du danach etwas in deiner React-App änderst, wird die App automatisch neu geladen und zeigt die Änderungen an!
Beachte bitte, dass bei der Installation neuer Plugins wie der Kamera immer ein Rebuild deines nativen Projekts erforderlich ist. Da sich dabei native Dateien ändern, kann dies nicht on the fly geschehen.
Achte darauf, die richtige IP und den richtigen Port in deiner Konfiguration zu verwenden. Der obige code Block zeigt den Standard-React-Port zu Demonstrationszwecken.
Capacitor Plugins verwenden
Schauen wir uns an, wie ein Capacitor Plugin in der Praxis funktioniert, das wir bereits erwähnt haben. Dazu können wir ein recht einfaches Plugin mit folgendem Befehl installieren:
npm i @capacitor/share
Es gibt nichts Besonderes am Share-Plugin, aber es öffnet trotzdem den nativen Share-Dialog! Dafür müssen wir nur noch das Package importieren und die share() Funktion in unserer App aufrufen. Ändern wir nun die src/App.js wie folgt:
import React from 'react';
import { Share } from '@capacitor/share';
function App() {
const share = async () => {
await Share.share({
title: 'Open Youtube',
text: 'Check new video on youtube',
url: 'https://www.youtube.com',
dialogTitle: 'Share with friends'
});
};
return (
<div>
<h1>Welcome to React and Capacitor!</h1>
<p>
<h2>Cool channel</h2>
<button onClick={() => share()}>Share now!</button>
</p>
</div>
);
}
export default App;
Wie bereits erwähnt, müssen wir nach der Installation neuer Plugins einen Sync durchführen und die App anschließend neu auf das Gerät deployen. Nutze dazu diesen Befehl:
npx cap sync
Nach dem Klick auf den Button siehst du den nativen Share-Dialog in Aktion!
Als Nächstes kannst du die App auf iOS und Android mit Capgo Navigation und Transitions nativer wirken lassen und typische iOS-Layoutprobleme beheben, die horizontalen Overflow oder abgeschnittene Safe Areas verursachen.
Native-Feeling-UI mit Capgo Native Navigation und Transitions
Ich arbeite schon seit Jahren mit Ionic um plattformübergreifende Apps zu bauen, ist die Integration mit React jedoch oft umständlich und lohnt sich kaum, wenn man bereits Tailwind CSS.
Für ein natives Mobile-Feeling in einer React + Capacitor App solltest du Capgo Plugins statt reiner Web-UI-Kits wie Konsta UI nutzen:
- @capgo/capacitor-native-navigation — native Navbar, Liquid Glass Tab Bar auf iOS und ein geblurrter Tab-Bar-Stil auf Android. Dein React Router verwaltet den Route-State; das Plugin übernimmt das native Chrome.
- @capgo/capacitor-transitions — Page Transitions im Ionic-Stil und iOS Edge Swipe-Back in der WebView-Ebene, ohne das Ionic UI zu übernehmen.
Beides installieren:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Konfiguriere die native Navigation mit dem CSS Inset Mode, damit Web-Content die nativen Bars berücksichtigt:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Rendere eine Liquid Glass Tab Bar (iOS nutzt systemeigenes Rendering; Android nutzt einen geblurrten WebView-Hintergrund):
await NativeNavigation.setTabbar({
selectedId: 'home',
labelVisibilityMode: 'labeled',
icons: true,
colors: { dynamic: true },
tabs: [
{ id: 'home', title: 'Home', icon: { svg: '...' } },
{ id: 'settings', title: 'Settings', icon: { svg: '...' } },
],
});
await NativeNavigation.addListener('tabSelect', ({ id }) => {
navigate(`/${id}`);
});
Füge native Page Transitions in deine App Shell ein:
import { useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/react';
initTransitions({ platform: 'auto' });
export function AppShell() {
const navigate = useNavigate();
const outletRef = useRef<HTMLElement>(null);
useEffect(() => {
if (outletRef.current) {
setupRouterOutlet(outletRef.current, { platform: 'auto', swipeGesture: 'auto' });
}
}, []);
const openSettings = () => {
setDirection('forward');
navigate('/settings');
};
return <cap-router-outlet ref={outletRef}>{/* routes */}</cap-router-outlet>;
}
Umschließe geroutete Seiten mit cap-router-outlet, cap-page, und cap-content, und rufe setDirection('forward') oder setDirection('back') bevor du navigierst. Dupliziere keine Web-Header oder -Footer, wenn die native Navigation diese Bereiche bereits übernimmt.
Hier findest du die vollständigen Guides: Verwendung von @capgo/capacitor-native-navigation und Verwendung von @capgo/capacitor-transitions.
Safe Areas mit Tailwind
Für Safe Areas von Geräten in Tailwind CSS verwende @capgo/tailwind-capacitor (veröffentlicht als tailwind-capacitor auf npm). Es bietet safe-areas Utilities und andere Capacitor-freundliche Tailwind-Plugins:
bun add -D tailwind-capacitor
Unter src/index.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Nutze Utilities wie pt-safe, pb-safe, und px-safe anstatt alles manuell env(safe-area-inset-*) manuell. Das Projekt wird aktiv entwickelt – falls etwas für dein React-Setup fehlt, eröffne einen PR auf GitHub.
iOS-Layoutprobleme beheben (Viewport, Safe Area und horizontaler Overflow)
Wenn Inhalte auf iOS abgeschnitten, verschoben oder horizontal scrollbar wirken, hilft es meist nicht, mehr overflow-x: hidden hinzuzufügen oder nur das Viewport-Tag zu ändern. Gehe diese Checks der Reihe nach durch.
Stelle sicher, dass das Viewport-Meta-Tag korrekt angewendet wird
Füge das Viewport-Meta-Tag in index.html innerhalb von <head>:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
iOS Safe Area nur von einem Root-Wrapper aus handhaben
Erstelle eine einzige App-Shell und wende dort das Safe-Area-Padding an – nicht in mehreren verschachtelten Komponenten:
html,
body,
#root {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
.app-shell {
min-height: 100dvh;
width: 100%;
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
Umschließe den gesamten Seiteninhalt mit .app-shellDoppeltes Safe-Area-Padding in Headern, Modals und Layout-Wrappern lässt das UI oft abgeschnitten oder zu groß wirken.
Mit @capgo/tailwind-capacitor, kannst du dasselbe Padding mit Utilities wie pt-safe pb-safe px-safe in dieser einen Shell ausdrücken.
Setze Capacitor iOS contentInset zu never zuerst
Unter capacitor.config.ts, deaktiviere lieber native Insets und überlasse CSS (oder der Native Navigation contentInsetMode: 'css') die Safe Area:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'dist',
ios: {
contentInset: 'never',
},
};
Kombination von Capacitor’s automatischen Content Insets mit CSS env(safe-area-inset-*) Padding ist eine häufige Ursache für doppelte Abstände.
Das tatsächlich überlaufende Element finden
Der übliche Übeltäter ist ein Element mit 100vw, Tailwind w-screen, einer festen Pixelbreite oder einem großen min-width.
Im Safari Web Inspector ausführen:
[...document.querySelectorAll('*')]
.filter(el => el.scrollWidth > document.documentElement.clientWidth)
.map(el => ({
el,
tag: el.tagName,
class: el.className,
scrollWidth: el.scrollWidth,
clientWidth: document.documentElement.clientWidth,
}));
Mit Tailwind ersetzen w-screen mit w-full wann immer möglich. Viele Probleme mit horizontalem Overflow entstehen durch 100vw / w-screen, doppeltes Safe-Area-Padding oder einen Container mit fester Breite – nicht durch das Viewport-Meta-Tag selbst.
Fazit
Capacitor ist eine hervorragende Option, um native Apps auf Basis eines bestehenden Webprojekts zu bauen, da es einen einfachen Weg bietet, code zu teilen und ein konsistentes UI zu pflegen.
Und mit der Ergänzung von Capgo, wird es noch einfacher, Live Updates in deine App einzubinden, damit deine Nutzer immer Zugriff auf die neuesten Features und Bugfixes haben.
Wenn du lernen möchtest, wie du Capgo in deine React-App einbindest, schau dir den nächsten Artikel an:
Weiter geht's mit: Mobile Apps mit React und Capacitor bauen
Wenn du es nutzt Mobile Apps mit React und Capacitor bauen um CI/CD-Automatisierung zu planen, verbinde es mit Capgo CI/CD für den Produkt-Workflow in Capgo CI/CD, Capgo Native Builds optimieren für den Produkt-Workflow in Capgo Native Builds, Capgo Integrationen für den Produkt-Workflow in Capgo Integrations, CI/CD-Integration für die Implementierungsdetails in der CI/CD-Integration und GitHub Actions-Integration für die Implementierungsdetails in der GitHub Actions-Integration.