2010-01-10 14 views
11

SWT đi kèm với JAR cơ sở và một JAR cụ thể trên mỗi nền tảng (Windows, Linux/32bit, Linux/64bit, Mac, AIX, ...). Làm thế nào tôi có thể tạo một JAR thực thi mà sẽ chọn JAR nền tảng chính xác khi chạy?Làm cách nào để tạo JAR có thể thực thi với SWT chạy trên tất cả các nền tảng?

[EDIT] Tôi đã suy nghĩ để cung cấp tất cả các nền tảng JAR trong thư mục con và trong main() sau đó sẽ sửa đổi trình nạp lớp. Có ai đã thử điều này không?

+1

Tại sao bạn không phân phối nhiều thực thi cho mỗi nền tảng (a la Eclipse)? –

+0

Vì SWT chỉ mất một phần nhỏ của ứng dụng: Toàn bộ hiện tại là 30MB. Vì vậy, tôi có thể yêu cầu mọi người tải xuống 32MB cho mỗi nền tảng hoặc tải xuống một tệp 40MB (cho sáu nền tảng) duy nhất chạy ở mọi nơi. –

+0

Trong trường hợp nhật thực, chúng tôi có hơn 10 lượt tải xuống, mỗi tệp> 100MB và sự khác biệt duy nhất giữa chúng là bình SWT. Tôi muốn tải xuống một lần hoặc một bản tải xuống chính lớn và một tải xuống nhỏ trên mỗi nền tảng được tải xuống tự động khi tôi chạy ứng dụng lần đầu tiên. –

Trả lời

1

IIUC, bạn vẫn muốn có các vấn đề về quy định cụ thể các thư viện JNI nền tảng cụ thể. Bạn có thể tận dụng Java Web Start cho việc này, nhưng tôi chưa thử. Ngoài ra, một số dự án xây dựng trình cài đặt tùy chỉnh cho nền tảng được hỗ trợ. Ví dụ: Deploying SWT Applications on Mac OS X mô tả cách tạo gói ứng dụng SWT Mac. Cách tiếp cận này được sử dụng trong số example này. Tôi cũng đã thấy số này JarBundler Ant Task được sử dụng.

Phụ lục: bài viết Deploying an SWT application on Java Webstart bao gồm một số tài liệu tham khảo hữu ích.

+0

Bây giờ tôi đã thử với một Trình tải URLClassLoader nhưng có hai vấn đề: Nếu JAR không nằm trong ClassPath trong tệp MANIFEST.MF, thì việc tải các tệp DLL sẽ không thành công. Điều này có nghĩa là tôi phải thêm * tất cả * SWT JAR vào classpath cùng một lúc. Điều này dẫn đến vấn đề mà các 32bit và 64bit DLLs có thể nhìn thấy và tải hoặc là sẽ thất bại. * thở dài * Cuối cùng, tôi sẽ thêm tất cả các JAR vào đường dẫn lớp nhưng chỉ sao chép một JAR SWT duy nhất vào thư mục lib. Bằng cách này, chỉ một JAR duy nhất sẽ tải. –

+0

Tôi có thể thấy sự hấp dẫn kỹ thuật, nhưng tôi cũng có thể thấy những khó khăn bảo trì. Đối mặt với một vấn đề tương tự, tôi đã thêm một liên kết đến một bài viết SO đề cập đến JWS. – trashgod

0

Sẽ dễ dàng hơn khi sử dụng các tập lệnh shell khác nhau cho các nền tảng khác nhau và chỉ định jar cụ thể cho nền tảng trong tập lệnh.

+0

Tôi có thể viết kịch bản shell nhưng tôi đã thực sự hy vọng để tránh điều đó. Giải pháp hiện tại của tôi (thêm tất cả các JAR SWT vào classpath nhưng chỉ sao chép chính xác một thư mục vào thư mục lib) hoạt động. Bây giờ, tôi chỉ cần viết trình cài đặt :) –

5

Đối với công việc hiện tại của tôi, tôi cần cung cấp một chai thực thi có thể nạp các lọ bên trong chính nó và thực hiện một chính thứ hai(). Về cơ bản là bootstrap main() và một application main().

Bước 1. trong "chính-class" manifest bạn đặt lớp bootstrap của bạn

Bước 2. Khi lớp bootstrap của bạn chạy nó unjar là jar riêng của mình và tất cả các lọ bên trong nó vào một thư mục tạm thời. Sử dụng một cái gì đó giống như dòng dưới đây để có được bình của riêng bạn.

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

Bước 3. lớp bootstrap của bạn phát hiện hệ điều hành thông qua "os.name" bất động sản và tải các lọ thích hợp từ thư mục tạm với điều này

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}); 
} 

Bước 4. Bây giờ bạn sẽ có thể để chạy ứng dụng của bạn bằng cách gọi chính ứng dụng().

LƯU Ý: Bản hack nhỏ này phụ thuộc vào JVM của bạn bằng cách sử dụng URLClassLoader làm SystemClassLoader của nó, điều này đúng với Sun JVM, chứ không phải cho những người khác.

Bằng cách này bạn chỉ có thể cung cấp một cái bình và nó sẽ tự giải nén và chạy với các lọ chính xác.

+1

Nếu bạn muốn độc lập với loại trình nạp lớp, chỉ cần sử dụng phương thức 'newInstance (url, parentClassLoader)' của nhà máy để bọc nó và sau đó cài đặt trình nạp lớp mới với 'Thread .currentThread(). setContextClassLoader() '. –

+0

+1 Ý tưởng thú vị để tạo classpath trong một main và sau đó gọi một classpath khác. –

+0

@Aaron cảm ơn mẹo, tôi sẽ phải thử – karoberts