Zum Hauptinhalt springen

How to Patch a Capacitor Plugin (Bun, npm, pnpm)

How to patch a Capacitor plugin with bun patch, patch-package or pnpm patch, apply native iOS and Android fixes, and decide when to fork or upstream.

Martin Donadieu

Martin Donadieu

Writer

Valeria

Reviewer

Jordan

Editor

How to Patch a Capacitor Plugin (Bun, npm, pnpm)

Um ein Capacitor-Plugin zu patchen, bearbeiten Sie die Dateien des Plugins node_modules, speichern Sie die Änderung als Diff mit bun patch --commit (oder patch-package auf npm und Yarn, pnpm patch-commit auf pnpm), committen Sie das generierte File in patches/, führen Sie dann bunx cap sync Damit nehmen die native Projekte es auf. Der Paketmanager wiederholt die Patches bei jeder Installation, für Ihre Team und in CI.

Patching ist die richtige Entscheidung, wenn ein Plugin einen kleinen Fehler hat, eine Versionsbeschränkung, die Ihren Build blockiert, oder eine aufwärts gerichtete Fixierung, die eingereicht wurde, aber noch nicht veröffentlicht wurde. Diese Anleitung deckt das Workflow für jeden Paket-Manager ab, wie native Patches auf Xcode und Gradle gelangen und wann ein Fork oder ein aufwärts gerichteter PR die bessere Wahl ist.

Warum funktioniert das Patchen für native Plugins code

Ein Capacitor-Plugin ist ein npm-Paket mit drei Teilen: JavaScript in dist/, Android code in android/, und iOS code in ios/ zusammen mit einer podspec und/oder Package.swift.Capacitor kompiliert die nativen Teile direkt von node_modules:

  • Android: android/capacitor.settings.gradle beinhaltet jedes Plugins android Fachordner von node_modules.
  • iOS mit CocoaPods: Die Podfile verweist auf jedes Plugin mit :path => '../../node_modules/...'.
  • iOS mit SPM: CapApp-SPM/Package.swift verweist auf jeden Plugin über lokalen Pfad in node_modules.

Also ändert sich ein Plugin node_modules/@scope/plugin/ios/Sources/... endet in deinem App-Binary nach cap sync und einem Neubuild. Es muss nichts veröffentlicht werden.

Bevor Sie ein Plugin patchen

  1. Überprüfen Sie, ob ein Release verfügbar ist. Betrachte die Änderungsliste des Plugins und öffne die PRs. Eine Aktualisierung ist besser als ein Patch.
  2. Lesen Sie die Lizenz. MIT und Apache-2.0 erlauben private Änderungen. Copyleft-Lizenzen wie GPL oder MPL-2.0 können Sie dazu verpflichten, veränderte Quellcode zu veröffentlichen, wenn Sie die App verteilen. Überprüfen Sie dies, bevor Sie die App freigeben.
  3. Schreiben Sie, warum. Fügen Sie die URL des Issues oder eine Zeilenbegründung in Ihrem Commit-Botschaft ein. Sechs Monate später weiß niemand mehr, warum. patches/ hat ein Datei in sich.

Patchen mit Bun

Bun hat Patching in sich. Kein extra Paket, kein postinstall Skript.

# 1. Prepare the package for editing
bun patch @capacitor/haptics

# 2. Edit files under node_modules/@capacitor/haptics

# 3. Save the patch
bun patch --commit node_modules/@capacitor/haptics

Schritt 1 gibt Bun Ihnen eine private Kopie des Pakets in node_modules, damit Änderungen den globalen Cache von Bun nicht berühren. Schritt 3 erstellt einen Diff und speichert ihn in package.json:

{
  "patchedDependencies": {
    "@capacitor/haptics@8.0.2": "patches/@capacitor%2Fhaptics@8.0.2.patch"
  }
}

Commit beide package.json Beide patches/ Ordner. Jeder bun installVerzeichnis. Jeder bun install --frozen-lockfile wird in CI angewendet.

The key contains the exact version. If you bump the plugin, Bun no longer matches the patch, so recreate it for the new version or delete it if the fix shipped.

Patchen mit npm oder Yarn: patch-package

npm install --save-dev patch-package

Fügen Sie ein postinstall Skript, damit Patches nach jedem Installieren angewendet werden.

{
  "scripts": {
    "postinstall": "patch-package"
  }
}

Dann bearbeiten Sie die Dateien in node_modules und generieren Sie den Patch:

npx patch-package @capacitor/haptics

Dies schreibt patches/@capacitor+haptics+8.0.2.patchin. Commit es. Wenn der Patch nach einem Upgrade nicht mehr angewendet wird, patch-package versagt die Installation mit einer klaren Meldung.

Yarn Berry hat seinen eigenen yarn patch <pkg> / yarn patch-commit -s <path> Ablauf, der den Patch im resolutions field.

Patching mit pnpm

pnpm patch @capacitor/haptics
# edit the temporary folder pnpm prints
pnpm patch-commit <path-printed-above>

pnpm registriert die Patches unter patchedDependencies und wendet sie bei der Installation an.

Beispiel: Behebung eines Fehler im nativen Build eines Plugins

Ein häufiges Szenario: Ihre App verwendet AGP 9, und ein älteres Plugin android/build.gradle verweist noch immer auf proguard-android.txt, die AGP 9 ablehnt. Sie können nicht auf eine Veröffentlichung warten.

bun patch some-capacitor-plugin

Editieren node_modules/some-capacitor-plugin/android/build.gradle:

 buildTypes {
     release {
         minifyEnabled false
-        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
     }
 }

Speichern und synchronisieren:

bun patch --commit node_modules/some-capacitor-plugin
bunx cap sync android
cd android && ./gradlew assembleDebug

The full background on this error is in fixen Sie Capacitor-Fehler im Plugin-Builder mit AGP 9.

Beispiel: Lockern Sie eine iOS-Abhängigkeit

Zwei Plugins setzen unterschiedliche Versionen des gleichen SDK fest und CocoaPods kann sie nicht lösen. Wenn Sie die Funktionsfähigkeit des Plugins mit der neueren SDK bestätigt haben, lockern Sie die podspec:

-  s.dependency 'FirebaseMessaging', '11.15.0'
+  s.dependency 'FirebaseMessaging', '>= 11.15.0', '< 13.0'

Für SPM-Anwendungen lebt dieselbe Einschränkung im Plugin’s Package.swift:

-  .package(url: "https://github.com/firebase/firebase-ios-sdk.git", exact: "11.15.0")
+  .package(url: "https://github.com/firebase/firebase-ios-sdk.git", "11.15.0"..<"13.0.0")

Dann:

bunx cap sync ios

Mit CocoaPods benötigen Sie möglicherweise cd ios/App && pod update FirebaseMessaging einmal, weil Podfile.lock immer noch die alte Version. Mit SPM verwenden Sie Datei > Packages > Packageversionen auflösen in Xcode.

Patching Capacitor Kern selbst

Manchmal liegt der Fehler in @capacitor/android, @capacitor/ios oder im CLI, und die Reparatur befindet sich in einem upstream-Pull-Request. Sie können diese Pakete auf die gleiche Weise patchen, aber jede Mannschaft endet mit der gleichen Diffs.

Capgo veröffentlicht @capgo/capacitor-patch für dies. Es ist ein hook-only-Paket mit einem Katalog kleiner, version-gesteuerter Patches, die auf ihre upstream-PRs verweisen. Es tut nichts, bis Sie sich entscheiden:

bun add @capgo/capacitor-patch
bunx capgo-capacitor-patch list --all
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'Example',
  webDir: 'dist',
  plugins: {
    CapacitorPatch: {
      patches: ['upstream-pr-8418-android'],
      strict: true,
    },
  },
};

export default config;

Paket-Patches laufen vorher cap sync und cap update, und native Projekt-Patches laufen nachher. bunx capgo-capacitor-patch doctor führt ein Trockentest durch. Mit strict: true, wird ein Synchronisierungsversuch fehlschlagen, wenn ein ausgewählter Patch nicht mehr anwendbar ist, was Ihnen sagt, wenn ein Upgrade ihn veraltet hat. Siehe die plugin docs für die vollständige Liste der Optionen.

Patch, fork oder upstream?

Situation Beste Option
Ein paar Zeilen, bereits in der upstream-Merge Patch, nach dem nächsten Release entfernen
Versionseinschränkung zu streng Patch, ein Issue upstream öffnen
Bug ohne noch keine Fix von upstream Patch und ein PR mit demselben Diff senden
Neue Funktion oder große Refaktorisierung Fork, unter Ihrem Scope veröffentlichen
Plugin aufgegeben Fork, oder auf ein gepflegtes Plugin umsteigen

Forking gut

If you fork, publish it so installs stay reproducible:

# in the fork, rename to your scope in package.json: "@acme/capacitor-foo"
bun run build
bun publish --access restricted

Aus einer Git-URL installieren funktioniert auch, aber die Plugin- dist/ Ordner muss in diesem Branch existieren oder durch einen prepare Skript und nicht jeder Paketmanager läuft die Abhängigkeitslebenszyklus-Skripte standardmäßig aus. Ein veröffentlichtes Paket vermeidet das.

Denken Sie daran, dass der npm-Name den Modulnamen des von CLI für SPM generierten Moduls ändert (@acme/capacitor-foo wird AcmeCapacitorFoo), also aktualisieren Sie die Forks Package.swift zum Anpassen. Details finden Sie in migrieren Sie ein Capacitor-Plugin auf SPM.

Bevor Sie ein Plugin für eine fehlende Funktion forken, überprüfen Sie das Capgo-Plugin-Verzeichnis. Es könnte bereits ein gepflegtes Plugin geben, das es abdeckt.

Upstreaming

Das Ziel ist, Ihre Patches zu löschen. Öffnen Sie ein Issue mit einer minimalen Reproduktion, Ihren Capacitor- und Plugin-Versionen und dem Patch-Diff. Dann öffnen Sie einen PR. Wartungsbeauftragte integrieren kleine, getestete Fixes viel schneller als Issue-Berichte allein.

Patches und Live-Updates

Ihr Web-Bundle enthält die JavaScript-Dateien des Plugins dist/daher wird ein Patch auf der JS-Seite mit der nächsten Web-Ausgabe verschickt. Mit Capgo Live-Updates wird das Update den Benutzern ohne eine Store-Ausgabe erreicht.

Nativ-Patches sind anders. Änderungen an Swift, Kotlin, Java, Gradle, podspec oder Package.swift wirken nur in einer neuen nativen Ausgabe, die an die Stores geschickt wird. Drücken Sie nicht ein Web-Bundle aus, das auf einem nativen Patch angewiesen ist, an Benutzer weiter, die noch die alte Binärdatei ausführen. Capgo Kompatibilitätsprüfung vergleicht die nativen Plugin-Versionen zwischen einem Bundle und einem Kanal, um dies zu erkennen.

Fehlerbehebung

Das Update wird nicht in CI angewendet. Make sure patches/ wird eingereicht und nicht ignoriert. Für patch-package, überprüfen Sie, dass CI nicht verwendet --ignore-scripts, das überspringt postinstall. Überprüfen Sie für Bun patchedDependencies ist im committierten package.json.

Meine native Änderung hat keinen Effekt. Sie haben das Datei geändert, aber nicht neu gebaut. Führen Sie bunx cap sync, dann clean: in Xcode Produkt > Ordner für Clean Build löschen, auf Android ./gradlew clean. Mit SPM resetzt man auch die Paket-Caches.

bun patch --commit sagt, es gäbe keine Änderungen. Sie haben eine Datei geändert, die nicht zum Paket gehört (z.B. eine gehobene Kopie in einem anderen Ordner). Bearbeiten Sie den Pfad Bun aus Schritt 1.

Die Patches scheitern nach dem Plugin-Upgrade. Überprüfen Sie, ob der Fix in der neuen Version enthalten ist. Wenn nicht, wiederholen Sie den Patch gegen die neue Version.

Das Plugin baut, aber die App stürzt auf dieser Funktion ab. Patches überspringen die eigenen Test des Plugins. Testen Sie den gepatchten Pfad auf einem realen Gerät auf beiden Plattformen. Der Capacitor iOS-Fehlersuche-Leitfaden und Android-Fehlersuche-Anleitung erklären, wie man native Logs liest.

Live-Updates für Capacitor-Apps

Wenn ein Web-Schicht-Bug live ist, schicken Sie die Reparatur über Capgo anstatt Tage zu warten, bis die App-Store-Zulassung vorliegt. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Menschliche Unterstützung von Martin

Los geht's jetzt

Neueste von unserem Blog

Capgo gibt Ihnen die besten Einblicke, die Sie benötigen, um ein wirklich professionelles Mobil-App zu erstellen.