スタンドアロンアプリの自動アップデート機能。

swingを使って、某WEBサービスの補助ツールを開発することになりました。ユーザはPC初心者が多く、不特定多数になりそうなので、色々と考えるべきことがあります。資料の少ない分野なので差し障りない程度に情報を公開していこうと思ってます。

今日の課題

  1. javaでありがちなクラスパスの問題を回避したい。
  2. 起動時にバージョンチェックして自動でバージョンアップしたい。

javaの取り扱いは難しく、PC初心者相手に環境変数にクラスパスを追加なんて不可能に近いですし、バージョンアップの度に毎回ダウンロードして再インストール作業なんて今時やってられないです。間違いなくユーザ離れを引き起こす原因になります。

(Web Startを使えば万事解決な気もしますが)
1.については、全てjarにまとめてexeでラップすれば解決しそうです。
問題は2.で、WEB上に最新バージョンのファイルを用意しておき、起動時に確認して置き換える方法が思いつきますが、再起動が必要だったり、起動中のファイルを置き換えるのは無理なので、色々面倒なことになりそうです。

そこで、jarを起動用とアプリケーションの2つに分けることにします。
起動用.jarはバージョンチェックとダウンロードとクラスロード等の変更の起こらない最低限の機能のみ実装します。同一階層にlibという名前のフォルダでも用意し、そこにアプリケーションと、必要なリソースやjarファイルを格納することにします。最新バージョンのアプリケーションはそこにダウンロードされ、起動用.jarのクラスローダで起動される仕組みです。

public class Launcher {
    public static void main(String[] args) {
        try {
            /*
             ここに最新バージョンをlib下にダウンロードするコードを書きます。
             バージョン情報はpropertyにでも用意しときます。
         prop.load(new FileInputStream("***.property"));
         String version = prop.getProperty("VERSION");
                  if( version < ....
            */

            // クラスローダを作成し、アプリケーションと依存関係にあるjarを設定します。
            // ファイル名をべた書きですが、ここもpropertyから読み込むようにすれば幅が広がります。
            URLClassLoader loader = new URLClassLoader(new URL[]{
                new File("./lib/Application.jar").toURL(),
                new File("./lib/MyLookAndFeel.jar").toURL(),
                new File("./lib/derby.jar").toURL(),
                new File("./lib/swing-layout-1.0.3.jar").toURL()
            });

            // mainメソッドのあるクラスをクラスローダから取得します。
            Class clazz = Class.forName("jp.ne.****.MainApp", true, loader);
            Method method = clazz.getMethod("main", new Class[]{args.getClass()});
            
            // デフォルトのクラスローダを変更し
            Thread.currentThread().setContextClassLoader(loader);
            // アプリのmainメソッドを実行します。
            method.invoke(null, new Object[]{args});
            
        } catch (IllegalAccessException ex) {

こんな感じになりますね。後はJSmoothでも使ってexe化しておけば完璧です。