Betten Sie den Quellcode mit qmake und qrc direkt in Ihre Qt-App ein, um GPL-Konformität zu gewährleisten

 C Programming >> C-Programmierung >  >> Tags >> Qt
Betten Sie den Quellcode mit qmake und qrc direkt in Ihre Qt-App ein, um GPL-Konformität zu gewährleisten

In meinem früheren Beitrag zum Verkauf von GPL-Software habe ich einige Punkte skizziert, die den Verkauf von GPL-Software erschweren. Einer davon ist die Verfügbarkeit des Quellcodes. Sie könnten es online stellen, aber dann hat jeder Zugriff, ohne zu bezahlen. Andere Optionen wie das Platzieren hinter einem Login oder das Senden eines Links nach dem Kauf erfordern zusätzliche Systeme und das Speichern von mehr Benutzerinformationen, viel zusätzlichen Aufwand für mich und die Benutzer. Eine meiner Ideen zur "Lösung" dieses Problems besteht darin, den eigentlichen Quellcode zu versenden direkt in der Anwendung. Dieser Artikel zeigt Ihnen, wie Sie das tun, indem Sie bei jedem Build mit qmake ein Archiv des aktuellen Quellcodes erstellen und das Einbetten in die Anwendung mit qrc , einschließlich einer Schaltfläche zum lokalen Speichern des Archivs auf der Festplatte. Es funktioniert sowohl auf dem Desktop als auch auf Android, einschließlich der erforderlichen Berechtigungen.

Das Beispielprogramm hat 2 Schaltflächen, eine zum Speichern des ZIP-Archivs, das wir dynamisch bei jedem Build erstellen, und eine zum Speichern des Beispielbilds. Das Beispielbild ist ein zufälliger Screenshot, den ich in einem alten Ordner von einem meiner früheren Jobs gefunden habe, dieses System wird nicht mehr verwendet.

Dies löst eine weitere Hürde, den Aspekt der mobilen App-Quelle. Auf einem Desktop kann ich eine ZIP-Datei mit dem Installer und dem Quellcode bereitstellen, aber in den App-Stores kann ich das nicht tun, nur einen .apk Datei oder .aab bündeln.

Durch Einbetten des Codes in die Anwendung können die Benutzer unter Android den Code aus der App heraus auf ihrem System speichern, ohne dass ein Quellarchiv heruntergeladen werden muss.

Dieses Handbuch funktioniert für Qt5 und setzt voraus, dass Sie mit dem Qt-Framework und Qml vertraut sind. Das Demoprogramm ist auf github zu finden. Der erste Teil des Leitfadens behandelt die dynamische Erstellung des Quellarchivs bei jedem Build und der zweite Teil die Einbettung in eine Qt-Anwendung.

Dies ist Teil 2 meiner Serie über den Verkauf von GPL-Software. Die anderen Teile findest du hier:

  • Teil 1:Eigene GPL-Software verkaufen, Teil 1:Viele Hürden
  • Teil 2:Betten Sie den Quellcode mit qmake und qrc direkt in Ihre Qt-App ein, um GPL-Konformität zu gewährleisten
  • Teil 3:Vorhandene GPL-Software zum Verkauf

Verfügbarkeit des Quellcodes

Wenn Sie den vorherigen Artikel nicht gelesen haben, empfehle ich Ihnen, dies zu tun, da dies erklärt, warum ich mit diesem Teil, der Verfügbarkeit des Quellcodes, zu kämpfen habe. Ich möchte, dass die Quelle verfügbar ist, aber nur für tatsächliche Kunden. Was auch immer sie dann mit dem Quellcode tun, ist ihr Recht, solange es mit der GPL konform ist. Ich bin also nicht dagegen, den Code zu veröffentlichen, aber ich möchte auch nicht, dass die Software überall verfügbar ist. Am Ende, wenn ein Kunde das Programm kauft und die Quelle veröffentlicht, ist es sein Recht, dies zu tun, und ich bin damit einverstanden.

Die GPL-FAQ enthält drei Frage-Antwort-Elemente zu Gebühren und Quellverteilung, die alle Fragen beantworten, die Sie möglicherweise haben:

Erlaubt mir die GPL, Kopien des Programms gegen Geld zu verkaufen?

Erlaubt mir die GPL, eine Gebühr für das Herunterladen des Programms von meiner Vertriebsseite zu erheben?

Wenn ich GPL-unterstützte Software gegen eine Gebühr vertreibe, muss ich sie dann auch der Öffentlichkeit kostenlos zur Verfügung stellen?

Die letzte Zeile des zweiten Elements, you must offer equivalent access to the source code in the same way through the same place at no further charge ,scheint abgedeckt zu sein, soweit ich das beurteilen kann, wenn ich die Quelle zusammen mit dem Download und innerhalb der Anwendung zur Verfügung stelle (wenn ein Download nicht möglich ist, wie z. B. in App-Stores).

Eine der Auswirkungen dieser Art der Veröffentlichung des Quellcodes besteht darin, dass Sie die Anwendung ausführen müssen, bevor Sie den Quellcode extrahieren können. Neuere Versionen erfordern ebenfalls einen Neukauf, da die App nur mit dem Quellcode dieser Version ausgeliefert wird. Auf Desktop-Plattformen plane ich, nach dem Kauf ein Archiv der Quelle im Download zu liefern, sodass Sie die Anwendung nicht ausführen müssen, um die Quelle zu erhalten, aber auf Android im App Store ist dies nicht möglich. In diesem Fall ist dies also das Beste, wenn es überhaupt die Überprüfung im App Store übersteht.

Quellcodearchiv erstellen

Das Beispielprojekt finden Sie hier auf github. Dieser Abschnitt des Artikels behandelt, wie das Quellcodearchiv erstellt wird, später behandeln wir den qrc Abschnitt, um das Archiv auf der Festplatte zu extrahieren.

Ich versende eine einfache .zip Archiv mit dem Quellcode und relevanten Projektdateien. Die Datei wird mit folgendem Befehl erstellt:

zip -r source.zip ./ -i '*.cpp' '*.h' '*.qml' '*.qrc' '*.pro' '*.png' 'README.md' 'LICENSE'

Dieser Befehl erstellt eine ZIP-Datei relativ zum aktuellen Arbeitsverzeichnis, in der die Ordnerstruktur erhalten bleibt. Es enthält alle Dateien auf der Wildcard-Erweiterungsliste und den README.md Datei.

Diese Datei, source.zip , wird im DISTFILES referenziert Abschnitt des .pro Datei sowie im qrc Datei (die in die Anwendung eingebettet werden soll), diese muss vor dem Erstellen des Programms verfügbar sein.

Zuerst habe ich versucht, dem qmake einen zusätzlichen Compiler hinzuzufügen Projektdatei, wie hier dokumentiert, aber das war ein bisschen umständlich. Entweder musste ich alle Eingabedateien hinzufügen, sonst würden Änderungen nicht erkannt, oder es gäbe eine Menge Variablentricks. Auch wenn der Befehl nicht vollständig vorhersehbar war und ich den Befehl vorher ausführen muss der eigentliche Aufbau. Das liegt daran, dass wir auf source.zip verweisen Datei in unserem qrc Datei, es muss dort sein, bevor wir bauen.

Am Ende habe ich einen einfachen system() verwendet Befehl, der garantiert vor dem eigentlichen Build ausgeführt wird:

system(cd $$PWD; rm source.zip; zip -r source.zip ./ -i \'*.cpp\' \'*.h\' \'*.qml\' \'*.qrc\' \'*.pro\' \'*.png\' \'android/*\' 'README.md' 'LICENSE')

Dies ist nicht plattformübergreifend und funktioniert nur mit den Befehlszeilen-Flags dieser speziellen Zip-Version, aber im Moment ist das in Ordnung. Ich kann später immer einen anderen Befehl in einen Block wie unten einkapseln:

win32 {
    system(windows command)
} else {
    system(linux command)
}

Die Ausgabe beim Erstellen über Qt Creator oder beim Ausführen von qmake sieht so aus:

19:48:23: Running steps for project qrcToDisk...
19:48:23: Starting: "/bin/qmake" /src/QtExamples/qrcToDisk/qrcToDisk.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
  adding: src/QtExamples/qrcToDisk/files/example.png (deflated 14%)
  adding: src/QtExamples/qrcToDisk/SaveToDisk.cpp (deflated 56%)
  adding: src/QtExamples/qrcToDisk/qml.qrc (deflated 36%)
  adding: src/QtExamples/qrcToDisk/main.qml (deflated 64%)
  adding: src/QtExamples/qrcToDisk/main.cpp (deflated 50%)
  adding: src/QtExamples/qrcToDisk/qrcToDisk.pro (deflated 41%)
  adding: src/QtExamples/qrcToDisk/SaveToDisk.h (deflated 33%)
19:48:23: The process "/bin/qmake" exited normally.

Wenn Sie rm weglassen Befehl werden bereits vorhandene Dateien überschrieben und neue Dateien hinzugefügt. Alte Dateien werden nicht entfernt.

Das Zip-Archiv lässt sich problemlos öffnen und der Inhalt ist wie erwartet:

Speichern Sie eine eingebettete Qt-qrc-Datei auf der Festplatte

Ein qrc Datei ist Teil des Qt-Ressourcensystems. Das Qt-Ressourcensystem ist ein plattformunabhängiger Mechanismus zum Speichern von Binärdateien in der ausführbaren Datei der Anwendung. Meistens qmake erzeugt make Regeln zum Generieren der Datei qrc_application.cpp die mit Ihrer Anwendung verknüpft ist. Diese Datei enthält alle Daten für die Bilder und andere Ressourcen als statische C++-Arrays aus komprimierten Binärdaten.

Sie können auch qrc konfigurieren um eine externe binäre Ressourcendatei zu erstellen, die später beim Ressourcensystem registriert wird. Dies ist nützlich, wenn Sie beispielsweise zwei Bildsätze für dieselbe Codebasis haben.

Unten finden Sie den Beispielinhalt meines qml.qrc Datei:

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>files/example.png</file>
        <file>source.zip</file>
    </qresource>
</RCC>

Kopieren einer Datei aus qrc zum Dateisystem ist so einfach wie der Aufruf von QFile::copy . QFile das Qt-Ressourcensystem unterstützt und wenn der Pfad Ihrer Datei mit einem Doppelpunkt beginnt (: ), weiß es, dass es im Ressourcensystem nach dem Dateinamen suchen muss. Ein Beispiel:

QFile::copy(":/files/example.png", "/tmp/example.png");

Mit obigem qrc Datei, die Datei example.png die in die Anwendung eingebettet ist, wird in /tmp kopiert Ordner.

Das Demoprogramm, das ich geschrieben habe, um dies zu testen, macht ein bisschen mehr, wie das Bereinigen des Dateinamens, das Suchen nach nicht vorhandenen Ordnern und das Überschreiben, aber das eineQFile::copy wie ist das Wesentliche.

Ein Problem, das ich hatte, war, dass ich zuerst einen QML-Dateidialog verwendete, um den Benutzer den Ordner auswählen zu lassen, in dem die Dateien gespeichert werden sollen. Der zurückgegebene Pfad jedoch, onlinux, begann mit file:// , anstatt nur den Pfad (/home/user/... ). Auf Android war der zurückgegebene Pfad unabhängig von der Auswahl des Benutzers /data/user/0/org.qtproject.example.qrcToDisk , das kein Ordner ist, zu dem der Benutzer navigieren kann. Zuerst versuchte ich, diese Probleme zu umgehen, aber das funktionierte nicht zuverlässig, also entschied ich mich, einfach QStandardPaths::DocumentsLocation zu verwenden , die immer etwas zurückgeben sollte, erstellen Sie den Ordner bei Bedarf.

Eine andere zu beachtende Sache ist, dass standardmäßig die Berechtigungen von Dateien im qrc Datei sind schreibgeschützt (da Sie nicht zurückschreiben können) und QFile kopiert diese Berechtigungen. Im Beispielprojekt habe ich die Dateiberechtigung der neuen Datei auf beschreibbar gesetzt.

Dasselbe gilt für den Fall, dass die Zieldatei bereits existiert, QFile::copy schlägt fehl, es sei denn, Sie entfernen diese Datei manuell.

In diesem Beispiel überschreibe ich alle vorhandenen Dateien, es liegt an jedem Benutzer dieses Beispiels, eine Benutzerfrage zum Überschreiben zu implementieren.

Es gibt ein bisschen Boilerplate-Code, um Berechtigungen dynamisch auf Android anzufordern, diese Berechtigungen sind bereits in AndroidManifest.xml enthalten Datei, aber neuere Versionen von Android erfordern auch, dass Sie danach fragen, bevor Sie sie verwenden, also tun wir das. Wenn alles funktioniert, sieht es wie folgt aus:

Nach dem Speichern befinden sich die Dateien im Ordner Documents Ordner: