Chrome-Erweiterung für Safari portieren: So funktioniert der Web Extension Converter
Wie Apples Konverter aus einem Erweiterungsordner ein Xcode-Projekt macht, was Sie danach anpassen müssen und wie die Erweiterung als App in den App Store kommt.
Eine Chrome-Erweiterung portieren Sie für Safari mit Apples Werkzeug safari-web-extension-packager, das früher safari-web-extension-converter hieß. Es liest Ihren bestehenden Erweiterungsordner und erzeugt daraus ein Xcode-Projekt mit einer kleinen Container-App und der eigentlichen Erweiterung. Der JavaScript-Code bleibt weitgehend gleich. Anpassungen sind vor allem bei einzelnen APIs, Berechtigungen und der Veröffentlichung nötig.
Warum Safari anders ist
Safari unterstützt das WebExtensions-Modell mit manifest.json, Content Scripts, Popup und Hintergrundskript. Anders als bei Chrome oder Firefox gibt es aber keinen eigenen Erweiterungs-Store. Eine Safari-Erweiterung wird immer als Teil einer App ausgeliefert. Diese App kann fast leer sein und nur erklären, wie man die Erweiterung aktiviert. Daraus folgen drei Konsequenzen:
- Sie brauchen Xcode und damit in der Praxis einen Mac.
- Für die Verteilung im App Store benötigen Sie eine kostenpflichtige Mitgliedschaft im Apple Developer Program.
- Die Prüfung erfolgt nach den Regeln des App Store, nicht nach eigenen Erweiterungsrichtlinien.
Voraussetzungen
| Was | Wofür |
|---|---|
| Mac mit aktueller macOS-Version | Xcode und Safari zum Testen |
| Xcode | enthält den Packager und baut die App |
| Apple-Konto | lokale Builds und Tests |
| Apple Developer Program | Veröffentlichung im App Store und TestFlight |
| funktionierende Erweiterung nach Manifest V3 | Ausgangspunkt der Konvertierung |
Am einfachsten ist die Portierung, wenn Ihre Erweiterung bereits sauber nach Manifest V3 aufgebaut ist, wie in der Anleitung Chrome-Erweiterung programmieren beschrieben.
Vorbereitung: was vor dem Konvertieren geklärt sein sollte
Der Packager übernimmt Ihre Dateien so, wie sie sind. Probleme, die schon in der Chrome-Fassung stecken, landen deshalb unverändert im Xcode-Projekt. Prüfen Sie vorab:
- Sauberer Build-Ordner: Nur die Dateien, die zur Erweiterung gehören, ohne Testdaten, Quellkarten oder
node_modules. - API-Unterstützung: Die Kompatibilitätstabellen auf MDN zeigen für jede WebExtension-API, ob und ab welcher Version Safari sie unterstützt. Funktionen, die es nur in Chromium gibt, brauchen eine Ausweichlösung.
- Bundle-ID festlegen: Wählen Sie eine dauerhafte Kennung in umgekehrter Domain-Schreibweise. Sie verbindet das Projekt mit dem Eintrag in App Store Connect und lässt sich dort später nicht mehr ändern.
- Symbole bereitstellen: Die Container-App braucht ein eigenes App-Symbol zusätzlich zu den Symbolen der Erweiterung.
Schritt für Schritt konvertieren
- Erzeugen Sie den fertigen Erweiterungsordner, also das Ergebnis Ihres Build-Schritts mit
manifest.jsonauf oberster Ebene. - Rufen Sie im Terminal den Packager auf:
xcrun safari-web-extension-packager /pfad/zur/erweiterung. - Beantworten Sie die Rückfragen oder geben Sie Optionen direkt mit, etwa den App-Namen und die Bundle-ID.
- Lesen Sie die Ausgabe genau: Das Werkzeug listet Manifest-Schlüssel und Berechtigungen auf, die Safari nicht unterstützt.
- Xcode öffnet das neue Projekt. Wählen Sie das Ziel für macOS und starten Sie die App mit „Run“.
Einige nützliche Optionen des Packagers:
xcrun safari-web-extension-packager ./dist \
--project-location ./safari \
--app-name "Lesezeit-Schätzer" \
--bundle-identifier org.example.lesezeit \
--copy-resources
--project-locationlegt fest, wo das Xcode-Projekt entsteht.--copy-resourceskopiert die Erweiterungsdateien ins Projekt. Ohne diese Option verweist das Projekt auf Ihren Quellordner, was für die laufende Entwicklung praktisch sein kann.--rebuild-projecterzeugt ein bestehendes Projekt neu, etwa um später iOS als Plattform hinzuzufügen.
Die vollständige Liste zeigt xcrun safari-web-extension-packager --help.
Was im Xcode-Projekt steckt
Das erzeugte Projekt enthält zwei Teile:
- Container-App: eine kleine App für macOS und auf Wunsch iOS. Standardmäßig zeigt sie einen Hinweis, wie die Erweiterung in Safari aktiviert wird.
- Erweiterungsziel: enthält Ihre Web-Extension-Dateien im Ordner
Resourcesund eine Swift-Datei, über die die Erweiterung mit der App kommunizieren kann (Native Messaging).
Wenn Sie keine nativen Funktionen brauchen, müssen Sie an der Swift-Seite nichts ändern. Ihr JavaScript bleibt der Kern.
In Safari testen
Damit Safari eine lokal gebaute, nicht signierte Erweiterung lädt, sind zwei Einstellungen nötig:
- Aktivieren Sie in den Safari-Einstellungen unter „Erweitert“ die Funktionen für Webentwickler.
- Erlauben Sie in den Entwicklereinstellungen unsignierte Erweiterungen. Diese Freigabe gilt nur bis zum Beenden von Safari.
- Starten Sie die Container-App aus Xcode und schalten Sie die Erweiterung in den Safari-Einstellungen unter „Erweiterungen“ ein.
- Gewähren Sie den Websitezugriff, wenn Safari danach fragt.
Fehler im Hintergrundskript und im Popup untersuchen Sie mit dem Web-Inspektor von Safari, der über das Entwicklermenü für die Erweiterung geöffnet wird. Content Scripts erscheinen im Web-Inspektor der jeweiligen Seite.
Typische Anpassungen nach der Konvertierung
| Thema | Was in Safari anders ist | Vorgehen |
|---|---|---|
| Namensraum | browser.* ist der native Namensraum |
browser verwenden oder Polyfill einsetzen |
| Hintergrund | Service Worker oder nicht persistente Seite | keinen Zustand in Variablen halten |
| Websitezugriff | Nutzer erteilen ihn pro Website und können ihn befristen | ohne Zugriff sinnvoll reagieren, Hinweis anzeigen |
| Nicht unterstützte APIs | einzelne Schnittstellen fehlen oder verhalten sich anders | vor dem Aufruf prüfen, ob die API existiert |
| Symbole | Safari nutzt die Symbole aus dem Manifest, zeigt sie aber anders an | Icons in mehreren Größen und gut lesbar gestalten |
| iOS | kein Mauszeiger, kleines Popup, eingeschränkte Fenster | Bedienung für Touch testen |
Ein robuster Stil hilft allen Browsern: Prüfen Sie vor der Nutzung einer API, ob sie vorhanden ist, statt bestimmte Browser abzufragen.
const api = globalThis.browser ?? globalThis.chrome;
if (api.sidePanel) {
// Seitenleiste nur dort nutzen, wo sie existiert
}
Native Messaging: wann die App mitarbeitet
Eine Besonderheit von Safari ist die enge Verbindung zwischen Erweiterung und App. Über browser.runtime.sendNativeMessage kann das Hintergrundskript Nachrichten an den nativen Teil der Erweiterung schicken, der in Swift geschrieben ist. Das erzeugte Projekt enthält dafür bereits eine Klasse, die eingehende Nachrichten entgegennimmt und eine Antwort zurückgibt. Damit die Schnittstelle genutzt werden darf, muss die Berechtigung nativeMessaging im Manifest stehen.
Sinnvoll ist das, wenn die Erweiterung Funktionen braucht, die im Browser nicht verfügbar sind, etwa den Zugriff auf Daten, die die App verwaltet, oder Einstellungen, die App und Erweiterung gemeinsam nutzen. Für den Datenaustausch zwischen App und Erweiterung bieten sich App-Gruppen an, also ein gemeinsamer Speicherbereich, den beide Ziele lesen dürfen.
Für eine reine Portierung brauchen Sie nichts davon. Bleiben Sie zunächst beim JavaScript-Kern und ergänzen Sie native Funktionen erst, wenn es einen konkreten Grund gibt. Jede native Komponente bedeutet zusätzlichen Pflegeaufwand und eine weitere Stelle, an der sich Safari von Chrome und Firefox unterscheidet. Beachten Sie auch, dass nativeMessaging bei der Installation als Berechtigung angezeigt wird und Nutzer misstrauisch machen kann, wenn der Zweck nicht erklärt ist.
Eine Codebasis für alle Browser
Auf Dauer ist es mühsam, Änderungen von Hand in den Safari-Ordner zu übertragen. Bewährt hat sich ein Build-Setup, das aus einem gemeinsamen Quellordner getrennte Ausgabeordner für Chrome, Firefox und Safari erzeugt, jeweils mit passendem Manifest. Das Xcode-Projekt wird einmal angelegt und verweist anschließend auf den Safari-Ausgabeordner, oder ein Skript kopiert die Dateien vor jedem Build hinein. Wie Sie TypeScript und Vite dafür einrichten, zeigt der Beitrag TypeScript und Vite für Erweiterungen einrichten.
Veröffentlichen über App Store Connect
- Legen Sie in App Store Connect eine neue App mit der Bundle-ID aus dem Projekt an.
- Setzen Sie in Xcode Version, Build-Nummer, Kategorie und Ihr Entwicklerteam für die Signierung.
- Erstellen Sie über „Product“ und „Archive“ ein Archiv und laden Sie es zu App Store Connect hoch.
- Verteilen Sie es zunächst über TestFlight an Testpersonen.
- Füllen Sie Beschreibung, Screenshots, Datenschutzangaben und Support-Adresse aus und reichen Sie die App zur Prüfung ein.
Die App-Prüfung achtet darauf, dass die Container-App einen erkennbaren Zweck erfüllt und die Erweiterung tut, was die Beschreibung verspricht. Eine App, die nur aus einem leeren Fenster besteht, ist ein häufiger Grund für Nachfragen. Eine kurze Anleitung zur Aktivierung mit Screenshots reicht meist aus. Weitere Hinweise zu Stores und Pflege finden Sie im Bereich Add-ons veröffentlichen und pflegen.
Updates
Jede neue Version der Erweiterung ist eine neue Version der App und durchläuft erneut die App-Prüfung. Nutzer erhalten Updates über den App Store. Planen Sie dafür etwas mehr Vorlauf ein als bei Chrome oder Firefox, und halten Sie Versionsnummern von Erweiterung und App konsistent, damit Fehlermeldungen eindeutig zugeordnet werden können.
Fragen und Antworten
- Brauche ich einen Mac, um eine Safari-Erweiterung zu bauen?
- Für die übliche Arbeitsweise mit Xcode ja. Apple bietet inzwischen zusätzlich einen webbasierten Packager in App Store Connect, der ein hochgeladenes ZIP-Archiv in ein Testpaket umwandelt. Für Fehlersuche und Feinarbeit bleibt ein Mac mit Safari aber praktisch unverzichtbar.
- Kann ich eine Safari-Erweiterung ohne App Store verteilen?
- Unter macOS lässt sich die App auch außerhalb des App Store verteilen, wenn sie mit einem Entwicklerzertifikat signiert und von Apple notarisiert ist. Unter iOS und iPadOS führt der reguläre Weg über den App Store.
- Läuft dieselbe Erweiterung auf Mac, iPhone und iPad?
- Ja, der Packager kann ein Projekt mit Zielen für macOS und iOS anlegen. Die Erweiterung selbst bleibt gleich, die Bedienung auf kleinen Bildschirmen und einzelne APIs sollten Sie aber gesondert testen.
- Warum taucht meine Erweiterung in Safari nicht auf?
- Meist ist sie nur noch nicht aktiviert. Erweiterungen müssen in den Safari-Einstellungen unter Erweiterungen eingeschaltet werden. Unsignierte Entwicklungsversionen erscheinen zudem erst, wenn in den Entwicklereinstellungen unsignierte Erweiterungen erlaubt sind.
Weiterlesen
- Chrome-Erweiterung programmieren
Von der leeren manifest.json bis zur funktionierenden Erweiterung mit Popup, Service Worker und Kontextmenü: ein vollständiges Beispiel zum Nachbauen.
- TypeScript und Vite einrichten
Ein Build-Setup für Erweiterungen: TypeScript-Konfiguration, Typen für die Browser-APIs, mehrere Einstiegspunkte mit Vite, die Sonderrolle der Content Scripts und Alternativen wie WXT.
- Veröffentlichen
Stores und Prüfprozesse, Versionsnummern und Changelog, Lizenzen und Bezahlmodelle: was nach dem letzten Commit kommt und warum ein Add-on nie ganz fertig ist.