In einer Capacitor-App Fotos aufnehmen und bearbeiten @capacitor/camera 8.1 oder später: Camera.takePhoto() Öffnet die Kamera, editable: 'in-app' Fügt eine Schneide- und Drehschritt hinzu und chooseFromGallery() Wählt bestehende Fotos über den Systempicker aus. Für eine benutzerdefinierte Kameraanzeige mit Ihren eigenen Steuerelementen verwenden Sie @capgo/camera-preview. Diese Anleitung behandelt Aufnahme, Bearbeitung, Berechtigungen, Komprimierung, Metadaten, Speichern und Hochladen, mit code für Capacitor 8.
Wählen Sie das richtige Werkzeug
| Brauchen Sie | Plugin | Wozu |
|---|---|---|
| Mit der Systemkamera UI ein Foto aufnehmen | @capacitor/camera takePhoto |
Keine benutzerdefinierte UI zum Pflegen, funktioniert überall |
| Lassen Sie den Benutzer schneiden oder drehen | @capacitor/camera editable, editPhoto, editURIPhoto |
Integriertes in-app-Editor auf iOS und Android |
| Wählen Sie ein oder mehrere Fotos oder Videos | @capacitor/camera chooseFromGallery |
Verwendet den Android Photo Picker und PHPicker, kein breites Berechtigung |
| Benutzerdefinierte Kameraansicht (Überlagerungen, ID-Kartenrahmen, Gesichtsführung) | @capgo/camera-preview |
Nativansicht, die Sie aus HTML und JS steuern |
| Durchsuchen Sie die gesamte Bibliothek in Ihrem eigenen Grid | @capgo/capacitor-photo-library |
Seitengenerte Bibliothekszugriff mit Miniaturansichten |
| Verkleinern, anpassen oder HEIC in ein anderes Format umwandeln | @capgo/capacitor-file-compressor |
Nativencoder, EXIF-Informationen entfernt |
| Verwenden Sie zuverlässig große Fotos | @capgo/capacitor-uploader |
Nativhintergrund-Hochladen mit Fortschrittsanzeige |
Installieren und konfigurieren Sie die Kamera-Plugin
bun add @capacitor/camera
bunx cap sync
Stellen Sie sicher, dass Sie Version 8.1 oder neuer haben.takePhoto, chooseFromGallery, editPhoto, editURIPhotowurden in Version 8.1 hinzugefügt CameraErrorCode in 8.2. Die ältere getPhoto und pickImages sind veraltet.
iOS
Fügen Sie diese Schlüssel hinzu ios/App/App/Info.plist. Apple lehnt Builds ab, die vage Zeichenketten enthalten, daher erklären Sie den realen Grund:
<key>NSCameraUsageDescription</key>
<string>Take a photo for your profile or attach it to a report.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choose existing photos to attach.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save photos you take to your library.</string>
Android
Die Aufnahme und das Wählen des Galerie-Bildes benötigen keine Berechtigung. Die Erweiterung startet die System-Kamera-Aktivität und verwendet den Android-Photo-Picker auf Android 11+-Geräten, die ihn unterstützen, fällt zurück auf ACTION_OPEN_DOCUMENT anderswo. Um den zurückportierten Picker auf älteren Geräten mit Google Play-Diensten zu erhalten, fügen Sie diesen innerhalb <application> in AndroidManifest.xmlden Namespace, daher fügen Sie auch tools namespace, also hinzufügen xmlns:tools="http://schemas.android.com/tools" zum Root <manifest> Element, wenn es noch nicht vorhanden ist (ein neuer Capacitor-Projekt deklariert nur xmlns:android):
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
android:enabled="false"
android:exported="false"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>
Nur saveToGallery: true Braucht Speicherberechtigungen und nur auf alten Android-Versionen:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
Vermeide die Hinzufügung READ_MEDIA_IMAGES unless your app’s core purpose is a gallery or editor. Google Play’s photo and video permissions policy requires apps with occasional photo needs to use the picker instead, and builds that declare the permission without justification get rejected.
Bild aufnehmen
import { Camera, CameraDirection, CameraErrorCode, EncodingType } from '@capacitor/camera';
export async function takePicture() {
try {
const photo = await Camera.takePhoto({
quality: 85,
targetWidth: 2048,
targetHeight: 2048,
correctOrientation: true,
encodingType: EncodingType.JPEG,
cameraDirection: CameraDirection.Rear, // iOS and web
includeMetadata: true,
});
// webPath works directly in <img src>
document.querySelector<HTMLImageElement>('#preview')!.src = photo.webPath!;
return photo;
} catch (e: any) {
if (e.code === CameraErrorCode.TakePhotoCancelled) return null;
if (e.code === CameraErrorCode.CameraPermissionDenied) {
// show a screen that explains how to enable the camera in Settings
return null;
}
throw e;
}
}
was Sie wiederbekommen MediaResult:
uriDie native Datei-URI des vollständigen Bildes (nicht im Web). Übergeben Sie es an Filesystem, einen Uploader odereditURIPhoto.webPathEine URL, die der WebView laden kann. Verwenden Sie sie für Vorschauen anstatt Base64.thumbnaileine Base64-Vorschaubild auf native, das vollständige Bild im Web.metadata: ein Base64-Vorschaubild auf nativ, das vollständige Bild im Web.includeMetadataist wahr.saved: obsaveToGalleryerfolgreich war.
targetWidth und targetHeight müssen zusammen eingestellt werden. Sie sind der günstigste Weg, um 12 MP-Fotos hochzuladen, wenn Sie nur eine 2048 Pixel-Bild benötigen.
Bild bearbeiten: Crop und Rotate
Bild bearbeiten, sobald es aufgenommen wurde
Einstellen editable und der Benutzer landet in einem Editor, bevor die Versprechen erfüllt sind:
const photo = await Camera.takePhoto({
quality: 85,
editable: 'in-app', // 'in-app' | 'external' | 'no'
});
'external' übergibt das Bild an einen anderen installierten Editor auf Android (zum Beispiel Google Fotos) und fällt zurück auf den in-app-Editor. iOS hat keinen externen Editor und verwendet immer 'in-app'.
Bild eines bestehenden Fotos bearbeiten
Um eine ausgewählte oder früher gespeicherte Fotodatei zu bearbeiten, übergeben Sie deren URI:
const edited = await Camera.editURIPhoto({
uri: photo.uri!,
saveToGallery: false,
includeMetadata: false,
});
Wenn Sie nur Base64 haben (z.B. von einem Canvas oder einer Serverantwort), verwenden Sie editPhotoDie Eingabe muss Roh-Base64 ohne einen data: Vorlage sein:
const { outputImage } = await Camera.editPhoto({ inputImage: base64 });
img.src = `data:image/jpeg;base64,${outputImage}`;
Keine dieser Methoden ist auf dem Web verfügbar. Wenn Sie Filter, Sticker, Text oder freie Zeichnungen benötigen, reicht der eingebauten Editor nicht aus. Rendern Sie das Bild in einem <canvas> und fügen Sie die Bearbeitungen dort hinzu, oder verwenden Sie einen JavaScript-Cropper wie Cropper.js für fixe Seitenverhältnisse wie Avatare. Ein Canvas-Export (canvas.toBlob(cb, 'image/jpeg', 0.85)gibt Ihnen einen Blob, den Sie direkt hochladen können.
Wählen Sie Fotos aus der Galerie
import { Camera, MediaTypeSelection } from '@capacitor/camera';
const { results } = await Camera.chooseFromGallery({
mediaType: MediaTypeSelection.Photo,
allowMultipleSelection: true,
limit: 5, // Android 13+ and iOS
quality: 85,
targetWidth: 2048,
targetHeight: 2048,
});
const urls = results.map((r) => r.webPath);
Für ein einzelnes Foto allowMultipleSelection: false plus editable: 'in-app' gibt Ihnen Pick-then-Crop in einem Aufruf. Setzen mediaType: MediaTypeSelection.All Auf iOS können Benutzer begrenzten Zugriff gewähren.
Auf iOS können Benutzer eingeschränkten Zugriff gewähren. pickLimitedLibraryPhotos() lasst sie die Auswahl ändern und getLimitedLibraryPhotos() erstellt, was Sie sehen können. Mit dem Systempicker benötigen Sie dies nur selten, da ausgewählte Elemente immer lesbar sind.
Erstellen Sie Ihre eigene Galerie-Grid-Ansicht
Wenn Ihre App die Benutzerbibliothek innerhalb Ihrer eigenen UI anzeigt (z. B. ein Foto-Druck-App, eine Sicherheitskopie-App), verwenden Sie @capgo/capacitor-photo-library:
import { PhotoLibrary } from '@capgo/capacitor-photo-library';
const { state } = await PhotoLibrary.requestAuthorization();
if (state === 'authorized' || state === 'limited') {
const { assets, hasMore } = await PhotoLibrary.getLibrary({
limit: 60,
offset: 0,
thumbnailWidth: 256,
thumbnailHeight: 256,
});
// assets[i].thumbnail?.webPath for the grid, getPhotoUrl({ id }) for full size
}
Das gleiche Plugins pickMedia() Öffnet den Systempicker und kopiert die Auswahl in den Cache, wenn Sie ein Plugin für beide Flüsse verwenden möchten. Vergessen Sie die Google Play-Politik oben, bevor Sie auf Android den Zugriff auf die vollständige Bibliothek anfordern.
Erstellen Sie eine benutzerdefinierte Kamera-Ansicht
Die Systemkamera-UI kann keine ID-Kartenrahmen, Dokumentenübersichten oder Ihre Marke anzeigen. @capgo/camera-preview zeigt die native Kamera-Feed und ermöglicht Ihnen, die UI in HTML zu zeichnen:
bun add @capgo/camera-preview
bunx cap sync
import { CameraPreview } from '@capgo/camera-preview';
await CameraPreview.start({
position: 'rear',
toBack: true, // preview behind the WebView
aspectRatio: '4:3',
storeToFile: true, // capture() returns a file path instead of base64
disableAudio: true,
});
await CameraPreview.setFlashMode({ flashMode: 'auto' });
await CameraPreview.setZoom({ level: 2 });
const { value: filePath, exif } = await CameraPreview.capture({ quality: 85 });
await CameraPreview.stop();
Mit toBack: true, sitzt die Vorschau hinter dem WebView, sodass die Seite und jedes übergeordnete Element während der Kamera-Aktivität einen transparenten Hintergrund haben müssen. Ein häufiges Muster ist eine camera-active Klasse auf body das Setzt background: transparent und versteckt den Rest der App. Fügen Sie NSCameraUsageDescription auf iOS, und auf Android fordert der Plugin die CAMERA Runtime-Erlaubnis durch requestPermissions()Always call the __CAPGO_KEEP_0__ function before taking a photo. stop() Anzeige, Komprimierung und Umwandlung
Anzeigen, komprimieren und umwandeln
(oder webPath context Capacitor.convertFileSrc(path) für Pfade aus anderen Plugins) um Bilder anzuzeigen. Vermeide Base64 in <img> Tags für Vollbilder: Ein 4 MB JPEG wird in einem JS-Memory-String zu 5,3 MB und überschreitet die Grenze.
Bevor Sie das Bild hochladen, verkleinern Sie es:
import { FileCompressor } from '@capgo/capacitor-file-compressor';
const { path } = await FileCompressor.compressImage({
path: photo.uri!,
width: 1600, // keeps aspect ratio
quality: 0.75,
mimeType: 'image/jpeg',
});
Der Kompressor akzeptiert HEIC-Eingaben von iPhones, daher wandelt die gleiche Funktion HEIC in JPEG um, wenn Backend-Systeme HEIC nicht lesen können. Es schreibt das Ergebnis in einen temporären Verzeichnis, daher bewegen Sie es mit @capacitor/filesystem wenn Sie es behalten müssen.
EXIF-Metadaten und Standort-Privatsphäre
Mit includeMetadata: true, metadata.exif enthält den EXIF-Block der Fotografie. Fotos aus der Kamera-Rolle können GPS-Koordinaten enthalten. Zwei Regeln halten Sie aus der Verlegenheit heraus:
- Entfernen Sie den Standort vor dem Hochladen von Fotos, die öffentlich werden (Profilbilder, Marktangebote).
@capgo/capacitor-file-compressorentfernt EXIF auf allen Plattformen als Teil der Komprimierung. - Wenn Sie den Standort benötigen (Feldberichte, Inspektionen), lesen Sie ihn aus EXIF vor der Komprimierung und senden Sie ihn als separates Feld. Dann offenbaren Sie ihn in Ihrer App-Store-Privatsphäre-Bezeichnung und Play-Datensicherheitsform. Siehe unsere Richtlinien für die iOS-Seite. für die iOS-Seite.
Save to the gallery or app storage
saveToGallery: true on takePhoto oder editURIPhoto schreibt das Bild auf die Kamera-Rolle und setzt saved auf das Ergebnis. Um ein Foto für Ihre App privat zu halten, kopieren Sie es in die App-Speicherung:
import { Filesystem, Directory } from '@capacitor/filesystem';
await Filesystem.copy({
from: photo.uri!,
to: `photos/${Date.now()}.jpg`,
toDirectory: Directory.Data,
});
Dateien im Cache-Verzeichnis können vom Betriebssystem jederzeit gelöscht werden, also sollten Sie keine langfristigen Verweise darauf speichern.
Hochladen des Fotos
Für kleine Fotos fetch with FormData ist ausreichend:
const blob = await fetch(photo.webPath!).then((r) => r.blob());
const form = new FormData();
form.append('file', blob, 'photo.jpg');
await fetch('https://api.example.com/photos', { method: 'POST', body: form });
Für große Dateien oder unzuverlässige Netzwerke verwenden Sie einen native Uploader, der weiterläuft, wenn die App im Hintergrund läuft.
import { Uploader } from '@capgo/capacitor-uploader';
const { id } = await Uploader.startUpload({
filePath: path,
serverUrl: 'https://api.example.com/photos',
method: 'POST',
mimeType: 'image/jpeg',
});
await Uploader.addListener('events', (event) => {
console.log(event.name, event.payload);
});
Beispiel: Profilbild-Fluss
- Zeige eine Aktionstaste mit „Bild aufnehmen“ und „Aus Bibliothek wählen“.
- Call
takePhotooderchooseFromGallerymiteditable: 'in-app',targetWidth: 1024,targetHeight: 1024. - Crop to a square in a canvas if you need a guaranteed 1:1 ratio.
- Komprimieren Sie mit
quality: 0.8und EXIF entfernt. - Hochladen, dann zeigen Sie die Server-URL, nicht die lokale Datei, damit das Avatar bei Wiederinstallierung überlebt.
Problembehandlung
: Eine Beschreibung für die Verwendung fehlt inEine Beschreibungsschlüssel für die Verwendung fehlt. Info.plist.
Die Fotografie ist auf Android gedreht.: set correctOrientation: true (Standard) und vermeiden Sie das Lesen von Rohdaten ohne Anwendung der EXIF-Orientierung.
Die App wird nach dem Aufnehmen einer Foto auf Geräten mit geringer Speicherfläche neu gestartet: Android kann Ihre Aktivität während der Kamera-Öffnung beenden. Hören Sie auf appRestoredResult von @capacitor/app um das Ergebnis nach dem Neustart wiederherzustellen.
webPath lädt nicht: Sie haben das webPath und es nach einem Neustart erneut verwenden. Speichere uri oder einen Dateisystempfad und konvertieren Sie es erneut mit Capacitor.convertFileSrc.
Die Kamera-Vorschau zeigt ein schwarzes Bild: Ein Element über der WebView hat noch eine Hintergrundfarbe oder start() wurde vor der Erlaubnis erteilt.
Die Play Console lehnt den Build wegen Foto-Berechtigungen ab: entfernen READ_MEDIA_IMAGES und READ_MEDIA_VIDEO es sei denn Sie haben eine Erklärung eingereicht, dass Ihre App breiten Zugriff benötigt.
Schiffe ohne Store-Veröffentlichung
Bildgrößen, Kompressionsstufen, Schneideverhältnisse und Upload-Endpunkte befinden sich alle in Ihrem Web code. Mit Capgo Live-Updates können Sie sie für jeden Benutzer ändern, ohne auf eine Überprüfung warten zu müssen, während native Änderungen wie neue Plugins durch einen regulären Build gehen. Wenn Sie iOS-Builds ohne Mac benötigen Capgo Build verwaltet das Signieren und das Hochladen mit Xcode 26, das App Store Connect seit April 2026 erfordert.