One Note Jam

Java ME開発・ProGuardをWindows環境で使用する際の注意点 (2006-12-31)

忘れないうちに備忘録として書いておきます。

要旨

  • ProGuardをWindows環境で使用する場合、"-dontusemixedcaseclassnames"オプションを使用するのが無難。
    • そうしないと、クラスファイル数が26を超えた場合に出力jarファイルが不正になる。
  • ProGuardを「J2ME Wireless Toolkit」から使用する場合、ProGuardに詳細なオプションを渡すためには「スクリプトファイル」が必要。
    • ただし、プロジェクトごとにスクリプトファイルを作成する必要があるため、面倒かつ忘れやすい。
  • ProGuardへ固定のオプションを常に指定したい場合、ProGuard自体のデフォルトオプションを変更してしまう方法もある。
    • その場合は、proguard.jar内のオプション設定ファイル"proguard/wtk/default.pro"を変更して、proguard.jarを作成しなおす必要がある。

前置き

容量制限の厳しいJava ME開発では、obfuscator(難読化ツール)を使用したjarアーカイブの容量削減が常套的に行われています。obfuscatorとは、元々は逆コンパイル対策のために、識別子を短くして逆コンパイル後のソースコードを読みにくくするためのツールですが、その結果としてクラスファイルのサイズが小さくなるという効果があります。

個人的には、いまどき容量削減についてはあまり考えないで開発をしていますが、obfuscatorによる容量削減は手間もかからないので行うようにしています。その際には、ProGuardというobfuscatorを使用しています。

ProGuard
http://proguard.sourceforge.net/

ところで私の場合、MIDletを開発する際の開発環境として、普段はEclipseを使用しています(EclipseMEというMIDP開発用プラグインを導入済み)。しかし、リリース用のバイナリを作成する際には、なるべくトラブルを避けるため、標準開発環境である「J2ME Wireless Toolkit」を使用するようにしています。いずれの環境にしても、obfuscator(ProGuard)を使用してのパッケージ作成を標準でサポートしているので、ProGuardの詳細を意識せずとも、簡単に使うことができます。

トラブル発生

ところが、以前「Rev.2」の開発中に、ProGuardがらみのトラブルに見舞われました。開発も終わりが見え始めた頃、リリース用のバイナリを作成するために「J2ME Wireless Toolkit」でリビルドを行いました。ところが、KToolbarのメニューから「Package→Obfuscated Package」を選択すると、以下のようなエラーメッセージが出力されて、パッケージ作成に失敗してしまいました。

Error preverifying class A
com.sun.kvem.ktools.ExecutionException: Preverifier returned 1

    Class loading error: Wrong name

ちなみに、Eclipseで「Create Obfuscated Package」を選択した場合だと、難読化されたjarファイルが問題なく作成できます。

オプション指定であっさり解決か?

ProGuardのウェブサイトを調べると、エラーメッセージで「InvalidClassException」「class loading error」「verification error」などが出た場合の対処方法が載っていました。

Troubleshooting - Problems while preverifying for J2ME
http://proguard.sourceforge.net/manual/troubleshooting.html#preverifying

If you get any such message from the preverifier, you are probably working on a platform with a case-insensitive file system, such as Windows. The preverify tool always unpacks the jars, so class files with similar lower-case and upper-case names overwrite each other. You can use ProGuard's -dontusemixedcaseclassnames option to work around this problem.

以下、適当な訳:

もしpreverifierからこのようなメッセージが出た場合、おそらく大文字/小文字を区別しないファイルシステムのプラットフォーム(例えばWindows)の上で実行しようとしているのだろう。preverifyツールは常にjarファイルを展開するので、同じ名前で大文字/小文字のクラスファイルは、互いに上書きされてしまう。これは、ProGuardの"-dontusemixedcaseclassnames"オプションを使用することで、この問題を回避できる。

要するに、クラスファイルの数が多すぎた(26個を超えた)ことにより、リネーム後のクラスファイル名として"a.class"〜"z.class"の次に"A.class"が使われてしまったため、いったんファイル上に展開した際に上書きされてしまって不正な状態になったということのようです。この"-dontusemixedcaseclassnames"オプションを指定することで、同じ名前で大文字/小文字だけ異なるクラスファイルを作成しないようになるようです。

というわけで、この"-dontusemixedcaseclassnames"オプションを指定してやれば問題解決、と思ったのですが……。

どうやってオプション指定を行うのか?

KToolbar上で「Package→Obfuscated Package」を実行するとProGuardが起動することについては前述しましたが、ProGuardに渡すオプションをどうやって設定すればいいのでしょうか? いろいろ調べたところ、以下の文書が参考になりました。

FAQ - Obfuscation, Classes and FileSystems
http://developers.sun.com/techtopics/mobility/midp/questions/wtk-proguard/

この文書に書いてある方法によると、以下の手順でProGuardに渡すオプションを指定できるとのことです。

  • まずは、ProGuard用の「スクリプトファイル」を生成する。一度KToolbar上で「Package→Obfuscated Package」を実行すると、KToolbarが"MIDlet名.pro"という名前のスクリプトファイルをMIDletのベースディレクトリに生成するので、これをスクリプトファイルの元ネタにすればよい。
  • そのスクリプトファイルに、ProGuardのオプションである"-dontusemixedcaseclassnames"を追記する。
  • MIDletのベースディレクトリに、そのスクリプトファイルを別名で保存する。
  • "wtklib\Windows\ktools.properties"ファイル内に、"obfuscate.script.name: スクリプトファイル名"というプロパティを追加する。

このとき、"obfuscate.script.name"に指定するスクリプトファイルは、ファイル名のみを記載する必要があるようです(ディレクトリパスを記載しないようにする)。

これで無事にobfuscatorを使用することができるようになったわけですが、この方法の場合、新しいプロジェクトを作るたびにスクリプトファイルを新しく作ってやる必要があります。これはちょっと面倒ですし、つい忘れてしまいそうです。

ProGuardのデフォルト設定自体を変えてしまう

何か他によい方法はないかとProGuardのマニュアルを探していたら、以下の文書を見つけました。

ProGuard Manual - J2ME Wireless Toolkit Integration
http://proguard.sourceforge.net/manual/wtk.html

つまるところ、こういうことのようです。

  • 「J2ME Wireless Toolkit」には、ProGuardを使うためのプラグインが最初から組み込まれている。
  • それとは別に、ProGuard自身もプラグインとして使うことができる。その場合、"wtklib\Windows\ktools.properties"ファイルを下記のように変更すればOK。
obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
obfuscator.runner.classpath: bin\\proguard.jar
  • ProGuard自身をプラグインとして使用する場合、proguard.jar内部の設定ファイル"proguard/wtk/default.pro"を変更することで、ProGuardの設定をカスタマイズできる。

この方法ならば、ProGuardのオプションを恒久的に設定することができそうです。

proguard.jarの改造手順

jarファイルの圧縮・展開には、JDKのツールの一つ"jar.exe"を使用します。

まずはproguard.jarの中身を展開します。

jar xf proguard.jar

展開されたファイルから、"proguard\wtk\default.pro"というファイルを探して、"-dontusemixedcaseclassnames"の一行を追加します。

その後、新しく"proguard_new.jar"という名前で、再度アーカイブします。

jar cfm proguard_new.jar META-INF/MANIFEST.MF proguard/

これで改造完了です。後は、この"proguard_new.jar"を、元の"proguard.jar"という名前にリネームした上で、"\WTK22\bin\"以下に上書きコピーします(オリジナルのproguard.jarは、どこかにバックアップを残しておくのが無難です)。

posted at 2006-12-31 | Permalink

© 2004-2008 ENDO