So verwandeln Sie eine Web-App mit Chromium und PyInstaller in eine Desktop-App

Das Verpacken und Verteilen Ihrer App klingt im Prinzip einfach. Es ist nur Software. Aber in der Praxis ist es ziemlich herausfordernd.

Ich habe an einem Python-Modul namens Sofi gearbeitet, das Benutzeroberflächen generiert. Es kann ein Desktop-Gefühl vermitteln, während Standard-Webtechnologien für einzelne Seiten verwendet werden. Aus Gründen der Flexibilität habe ich zwei Verteilungsmethoden entwickelt: In-Browser und ausführbare Datei.

Es läuft im Browser und funktioniert ähnlich wie eine normale Webseite. Sie können es laden, indem Sie eine Datei öffnen oder von Ihrer Shell aus starten. Ich habe auch eine ausführbare Datei erstellt, die als gepackte App unabhängig und ohne externe Anforderungen ausgeführt wird.

Im Laufe der Zeit, als ich Code in Atom - meinem bevorzugten Editor - hackte, fiel mir ein, dass Atom tatsächlich ein Browser ist. Es verwendet Node.js als Back-End und das Electron-Framework für seine Benutzeroberfläche. Dies hat mich dazu inspiriert, mich mit den Interna von Electron zu beschäftigen, in der Hoffnung, Beispiele und Best Practices für die Lösung von Desktop-Verpackungen zu finden.

Es dauerte nicht lange, bis ich herausfand, dass alles auf kostenlosen und Open-Source-Technologien basiert: dem Chromium-Browser und dem Chromium Embedded Framework. Dies beinhaltete einfach zu integrierende Beispielanpassungen, die meine Anforderungen erfüllen konnten.

Mit all dem in der Hand machte ich mich an die Arbeit.

Das Chromium Embedded Framework

Chromium ist der Basiscode, der den Chrome-Browser von Google speist. Es vereint alle Elemente, die eine Schnittstelle rendern, Benutzereingaben verarbeiten und ihre Funktionen skripten.

Das Chromium Embedded Framework (CEF) ist eine Gruppe von C-Funktionen, die diesen Browser steuern können. Es enthält auch Skripte, die das Erstellen und Kompilieren vereinfachen.

Visual Studio Code, Slack, Mattermost, Curse, Postman und Kitematic sind Beispiele für Desktop-Apps, die Electron verwenden. Diese Systeme gelten alle als Websites, die den darunter liegenden Browser mit CEF ausnutzen.

Wenn Sie der Meinung sind, dass Python an C binden und diese Funktionen auch nutzen kann, haben Sie Recht. Suchen Sie nicht weiter als bis zum pycef-Projekt, um die CEF-Wrapper-Funktionen direkt aufzurufen. Es kommt jedoch mit der Chromium-Binärdatei als zusätzliche Abhängigkeit. Wenn Sie sich also Sorgen um die Verwaltung komplizierter Support-Anweisungen machen, denken Sie nach, bevor Sie loslegen.

In meiner speziellen Situation verwaltet das Sofi-Projekt alle Interaktionen über einen Websocket und bietet eine konsistente Schnittstelle für verschiedene Arten von Plattformen (Web, Desktop, Mobile usw.). Dies bedeutet, dass ich den Browser nicht manuell steuern oder steuern muss. Ich möchte nur mit dem DOM interagieren, das der Browser über Standard-Webtechnologien anzeigt.

Mein Ziel ist es, die UI-Elemente anzupassen, die einen Browser wie einen Browser aussehen lassen. Ich muss die Menüs, Symbolleisten und Statusleisten entfernen. Auf diese Weise werde ich den Eindruck erwecken, dass wir uns im Vollbildmodus befinden - jedoch in einem Anwendungsfenster.

Angesichts meiner einfachen Anforderungen war ich der Meinung, dass Pycef - oder andere Bindungen auf niedrigerer Ebene - zu viel waren. Stattdessen nutzte ich ein vorgefertigtes Beispiel aus dem CEF-Projekt: cefsimple . Dieser Browser verbirgt alle visuellen Elemente, die ich möchte. Wenn ich also seine CLI zum Öffnen einer Webseite verwende, hat der Benutzer keine Ahnung, dass sie sich tatsächlich in einem Browser befinden. Es sieht aus wie ein normales Fenster aus jeder Anwendung.

Das Erstellen von Cefsimple war nicht allzu kompliziert, als ich die Dokumentation durchgesehen hatte. Es dauert jedoch enorm lange, wenn Sie auch Chromium zusammenbauen. Um dies zu vermeiden, bietet das Projekt selbst vorgefertigte Binärdateien, die Sie anpassen und zu cefsimple kompilieren können. Ich fand es am besten, diese auszunutzen.

Die Schritte sind wie folgt:

  1. Sehen Sie sich kurz an, wie Sie mit CEF aus Binärdateien erstellen.
  2. Holen Sie sich eine der Binärdistributionen aus dem Repo. Lesen Sie unbedingt die QuickInfos, bevor Sie eine auswählen, da nicht alle Pakete dieselben Dateien enthalten. Ich habe speziell nach einem gesucht cefsimple.
  3. Durchsuchen Sie die CMakeLists.txtDatei und stellen Sie sicher, dass Sie die erforderlichen Build-Tools installieren. Dies ist plattformspezifisch.
  4. Führen Sie den Build durch. Dies wird in derselben Datei wie im vorherigen Schritt erläutert und ist auch plattformspezifisch. Es folgt jedoch in der Regel dem folgenden Vorgang: make und cd in das Build-Verzeichnis erstellen, cmake für Ihre Kompilierungswerkzeuge und -architektur ausführen und auf das übergeordnete Verzeichnis zeigen. Da ich die OSX Ninja-Tools auf einer 64-Bit-Plattform verwendet habe, sah der Befehl so auscmake -G "Ninja" -DPROJECT_ARCH="x86_64" ..
  5. Das Erstellungsverzeichnis enthält jetzt die Ausgabedateien. Die Struktur kann etwas verwirrend sein, wird aber hauptsächlich beschrieben README. Als Referenz führte der vorherige Schritt zu einem App-Bundle unter build/tests/cefsimple/Release/cefsimple.app.
  6. Vergessen Sie nicht, dass Sie dies tun müssen, um die Binärdateien zu erstellen, die Sie für jede Plattform und Betriebssystemarchitektur benötigen, die Sie unterstützen.

Nachdem Sie eine ausführbare Datei haben, führen Sie sie über die Befehlszeile aus und --urlsetzen Sie sie auf die Webseite, die Sie öffnen möchten. Dies bedeutet, dass die Integration in ein Python-Skript einfach über das subprocessModul erfolgt.

Wenn Sie Chromium selbst kompilieren möchten, lesen Sie die CEF-Dokumentation. Es wird Sie in die richtige Richtung weisen. Aber seien Sie gewarnt, das Herunterladen, Erstellen und Kompilieren nimmt viel Zeit in Anspruch. Gute, altmodische Verarbeitungsleistung wird definitiv dazu beitragen, schnellere Ergebnisse zu erzielen.

Verpackung

Jetzt, da wir ein Desktop-Erlebnis bieten können, müssen wir uns überlegen, wie wir das an unsere Benutzer verteilen können. Die herkömmliche Verteilung von Python-Paketen erfolgt über den Python Package Index (PyPI). Unsere Benutzer müssen jedoch den Python-Interpreter und eine Art Verpackungswerkzeug wie easy_installoder installieren pip.

Dies ist zwar nicht besonders schwierig, Sie sollten jedoch die größere Anzahl von Benutzern berücksichtigen. Das Verwalten eines Installationsprozesses mit separaten manuellen Schritten wird ziemlich kompliziert. Besonders bei nicht-technischen Zielgruppen - einige von ihnen wissen nicht, dass Python etwas anderes als eine große Schlange ist. Während andere zumindest die Luftgeschwindigkeit einer europäischen unbeladenen Schwalbe kennen.

Wenn sie die Sprache kennen, haben die meisten bereits eine eigene Version installiert. Hier kommen Paketabhängigkeiten, verschiedene Betriebssysteme, Browser ins Spiel, von denen Sie noch nie gehört haben (oder von denen Sie dachten, dass sie inzwischen tot sind), sowie die unterschiedlichen Fähigkeiten der Benutzer beim Einrichten virtueller Umgebungen. Dies führt in der Regel zu einem hohen Zeitaufwand für die Unterstützung nicht übereinstimmender Software.

Um ein so großes Durcheinander zu vermeiden, gibt es Tools, mit denen Sie alle Ihre Abhängigkeiten in betriebssystemspezifische ausführbare Dateien einbetten können. Nach sorgfältiger Überlegung habe ich mich für PyInstaller entschieden. Es scheint die größte Flexibilität bei unterstützten Plattformen und Formaten zu bieten.

Ein kurzer Auszug aus ihrem GitHub-Repository fasst die Dinge gut zusammen:

PyInstaller liest ein von Ihnen geschriebenes Python-Skript. Es analysiert Ihren Code, um alle anderen Module und Bibliotheken zu ermitteln, die Ihr Skript zur Ausführung benötigt. Dann sammelt es Kopien all dieser Dateien - einschließlich des aktiven Python-Interpreters! - und legt sie mit Ihrem Skript in einem einzelnen Ordner oder optional in einer einzelnen ausführbaren Datei ab.

Das Tool hat sein Versprechen gehalten. Ich habe es auf die Python-Datei für meine Beispielanwendung verwiesen und es bündelt es leicht genug in einem Verzeichnis mit : pyinstaller sample.py. Wenn ich stattdessen eine ausführbare Datei möchte, fügen Sie einfach den --onefileParameter hinzu.

Es wird etwas schwieriger, wenn Sie Ihrem Bundle Nicht-Python-Daten hinzufügen müssen. Dies ist der Fall bei den HTML- und JS-Dateien, die die Grundlage von Sofi bilden, und bei dem einfachen Browser, der die Anwendungsoberfläche von früher darstellt. Das PyInstaller-Dienstprogramm bietet --add-datagenau dies und ermöglicht eine Zuordnung zu dem Pfad in Ihrem Bundle, in dem sich die Datendatei (oder das Verzeichnis) befindet. Es dauerte jedoch eine Weile, bis ich herausgefunden hatte, wie ich aus meinem Code heraus richtig auf diese Verzeichnisse zugreifen kann. Zum Glück hat mich die Dokumentation in die richtige Richtung gelenkt.

Wie sich herausstellt, können Sie sich beim Ausführen einer gebündelten PyInstaller-Anwendung nicht auf __file__ähnliche Mechanismen verlassen, um Pfade zu bestimmen. Stattdessen speichert der PyInstaller-Bootloader den absoluten Pfad zum Bundle in sys._MEIPASSund fügt ein frozenAttribut hinzu, um Sie darüber zu informieren, dass Sie in einem Bundle ausgeführt werden. Wenn dies der Fall sys.frozenist, Trueladen Sie Ihre Dateien basierend auf sys._MEIPASS. Verwenden Sie andernfalls normale Pfadfunktionen, um festzustellen, wo sich die Dinge befinden.

Ich konnte sowohl eine OSX-gebündelte App als auch eine ausführbare Linux-Binärdatei desselben Python-Skripts erfolgreich erstellen. Ich habe überprüft, ob ich dasselbe mit einer ausführbaren Windows-Datei tun kann, hatte aber noch keine Zeit, eine Windows-Version des cefsimple- Browsers zusammenzustellen, um den Bundle-Pfad zu testen.

Das Endprodukt

Ein Beispiel für die browserbasierte Benutzeroberfläche mit dem hier beschriebenen System finden Sie in meiner Präsentation auf der PyCaribbean 2017.

Die für CEF und Verpackung relevante Demo ist eine Bildergalerie und erscheint gegen 18:15 Uhr.

Weitere Informationen darüber, wie ich Sofi hergestellt habe, finden Sie in der A Python Ate My GUI-Reihe.

Wenn Ihnen der Artikel gefallen hat und Sie mehr über Python und Softwarepraktiken erfahren möchten, besuchen Sie bitte tryexceptpass.org. Bleiben Sie mit den neuesten Inhalten auf dem Laufenden, indem Sie die Mailingliste abonnieren.