Zum Hauptinhalt springen

Wie man Fotos in einer Capacitor-App aufnimmt und bearbeitet

Nehmen und bearbeiten Sie Fotos in einer Capacitor-App mit der Kamera 8 API: Aufnahme, Galerieauswahl, In-App-Crop, Live-Vorschau, Komprimierung, EXIF und Uploads.

Artikelcredits

Martin Donadieu

Schreiber

Valeria

Rezensent

Jordan

Redakteur

Wie man Fotos in einer Capacitor-App aufnimmt und bearbeitet

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 oder editURIPhoto.
  • 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. includeMetadata ist wahr.
  • saved: ob saveToGallery erfolgreich 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.

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.

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:

  1. Entfernen Sie den Standort vor dem Hochladen von Fotos, die öffentlich werden (Profilbilder, Marktangebote). @capgo/capacitor-file-compressor entfernt EXIF auf allen Plattformen als Teil der Komprimierung.
  2. 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.

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

  1. Zeige eine Aktionstaste mit „Bild aufnehmen“ und „Aus Bibliothek wählen“.
  2. Call takePhoto oder chooseFromGallery mit editable: 'in-app', targetWidth: 1024, targetHeight: 1024.
  3. Crop to a square in a canvas if you need a guaranteed 1:1 ratio.
  4. Komprimieren Sie mit quality: 0.8 und EXIF entfernt.
  5. 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.

Live-Updates für Capacitor-Apps

Wenn ein Web-Schicht-Bug live ist, verschicken Sie die Reparatur über Capgo anstatt Tage für die Genehmigung des App-Stores zu warten. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Verfahren bleiben.

Neuestes aus unserem Blog

Capgo gibt Ihnen die besten Einblicke, die Sie benötigen, um eine wirklich professionelle mobile App zu erstellen.