2010-01-10 4 views
11

SWT kommt mit einer Basis-JAR und einer spezifischen JAR pro Plattform (Windows, Linux/32bit, Linux/64bit, Mac, AIX, ...). Wie kann ich eine ausführbare JAR erstellen, die zur Laufzeit das richtige JAR der Plattform auswählt?Wie kann ich ausführbare JAR mit SWT erstellen, die auf allen Plattformen ausgeführt wird?

[EDIT] Ich dachte, alle Plattform JARs in einem Unterverzeichnis zu liefern und in main() würde dann den Klassenlader ändern. Hat das schon jemand probiert?

+1

Warum Sie verteilen nicht mehrere ausführbare Dateien für jede Plattform (a la Eclipse)? –

+0

Da SWT nur einen kleinen Teil der App braucht: Das Ganze ist derzeit 30MB. So kann ich entweder Leute bitten, 32MB für jede Plattform herunterzuladen oder eine einzelne 40MB (für sechs Plattformen) Datei herunterzuladen, die überall läuft. –

+0

Im Fall der Finsternis haben wir 10+ Downloads, jedes> 100MB und der einzige Unterschied zwischen ihnen ist das SWT-Glas. Ich möchte entweder einen einzelnen Download oder einen großen Hauptdownload und einen kleinen Download pro Plattform, der automatisch heruntergeladen wird, wenn ich die App das erste Mal benutze. –

Antwort

1

IIUC, würden Sie haben immer noch das Problem, die plattformspezifischen JNI-Bibliothek angeben. Sie könnten dafür Java Web Start nutzen, aber ich habe es nicht versucht. Alternativ erstellen einige Projekte benutzerdefinierte Installationsprogramme für unterstützte Plattformen. Zum Beispiel beschreibt Deploying SWT Applications on Mac OS X, wie ein SWT-Mac-Anwendungspaket erstellt wird. Der Ansatz wird in diesem example verwendet. Ich habe auch diese JarBundler Ant Task verwendet gesehen.

Nachtrag: Der Artikel Deploying an SWT application on Java Webstart enthält einige nützliche Hinweise.

+0

Ich habe jetzt mit einem URLClassLoader versucht, aber es gibt zwei Probleme: Wenn die JAR nicht im ClassPath in der MANIFEST.MF ist, wird das Laden der DLLs fehlschlagen. Dies bedeutet, dass ich * alle * SWT JARs gleichzeitig dem Klassenpfad hinzufügen muss. Dies führt zu dem Problem, dass die 32-Bit- und 64-Bit-DLLs sichtbar sind und das Laden von beiden fehlschlägt. * seufz * Am Ende werde ich alle JARs zum Klassenpfad hinzufügen, aber nur ein einziges SWT-JAR in das lib-Verzeichnis kopieren. Auf diese Weise wird nur ein einziges JAR geladen. –

+0

Ich kann den technischen Reiz sehen, aber ich sehe auch die Schwierigkeiten bei der Wartung. Angesichts eines ähnlichen Problems habe ich einen Link zu einem SO-Artikel hinzugefügt, der JWS erwähnt. – trashgod

0

Es wird einfacher sein, verschiedene Shell-Skripte für verschiedene Plattformen zu verwenden und plattformspezifische jar im Skript anzugeben.

+0

Ich könnte Shell-Skripte schreiben, aber ich hatte wirklich gehofft, das zu vermeiden. Meine aktuelle Lösung (fügen Sie alle SWT-JARs dem Klassenpfad hinzu, aber kopieren Sie nur die richtige in das lib-Verzeichnis). Jetzt muss ich nur noch ein Installationsprogramm schreiben :) –

5

Für meinen aktuellen Job musste ich eine ausführbare Jar liefern, die Gläser in sich laden und eine zweite main() ausführen konnte. Im Grunde ein Bootstrap main() und eine Anwendung main().

Schritt 1 im Manifest „Hauptklasse“ Sie setzen Ihre Bootstrap-Klasse

Schritt 2. Wenn der Bootstrap-Klasse läuft unjar sein eigenes Glas ist und alle Gläser im Inneren in ein temporäres Verzeichnis. Verwenden Sie etwas wie die Zeile unten, um Ihr eigenes Glas zu bekommen.

Main.class.getProtectionDomain().getCodeSource().getLocation().toURI() 

Schritt 3. Ihre Bootstrap-Klasse erkennt das Betriebssystem über die „os.name“ Eigenschaft und lädt die entsprechenden Gläser aus dem temporären Verzeichnis mit diesem

private static void loadJarIntoClassloader(URL u) throws Exception 
{ 
    URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 

    Class<URLClassLoader> sysclass = URLClassLoader.class; 
    Method method = sysclass.getDeclaredMethod("addURL", URL.class); 
    method.setAccessible(true); 
    method.invoke(sysLoader, new Object[]{u}); 
} 

Schritt 4. Nun sollten Sie in der Lage sein, um Ihre Anwendung zu starten, indem Sie die Anwendung main() aufrufen.

HINWEIS: Dieser kleine Hack hängt von Ihrer JVM ab und verwendet URLClassLoader als SystemClassLoader, was für Sun JVMs gilt, nicht für andere.

Auf diese Weise können Sie nur ein einziges Glas liefern, und es wird sich selbst auspacken und mit den richtigen Gläsern laufen.

+1

Wenn Sie unabhängig vom Typ des Classloaders sein möchten, verwenden Sie einfach die Methode 'newInstance (urls, parentClassLoader)', um sie zu umbrechen und dann den neuen Classloader mit 'Thread 'zu installieren .currentThread(). setContextClassLoader() '. –

+0

+1 Interessante Idee, den Klassenpfad in einem Hauptverzeichnis zu erstellen und dann ein anderes aufzurufen. –

+0

@Aaron danke für den Tipp, ich muss das versuchen – karoberts

Verwandte Themen