オプション
proguardは、難読化だけではなく、黙っていると最高度の最適化をしてしまい、意図しないコードを生成し、結果動作しなくなってしまう。 しかも、どのように変更されるのか調査するのが面倒なため、オプションを調整しながら、どのように最適化・難読化されたのかを確認しづらい。 以下では、「難読化」という目的を果たしつつ、「動かない」というトラブルに巻き込まれないための最低限のオプション(あるいは事前のコード変更)について述べる。
以下はbuild.gradleに記述する例。proguardとfatjarも参照のこと。
入出力の指定
入出力指定、警告等の以下のオプションはここでは省略。
injars outjars libraryjars dontwarn dontnote
シュリンクと最適化の拒否
これは必須。苦労したくなければ指定した方がよい。少なくとも最初の段階では絶対に指定しておくべき。
dontshrink dontoptimize
Javaエントリポイント
Javaのエントリポイントを保護する。これが無いと当然実行できなくなるのだが、指定しないとproguardはお構い無しに名前変更してしまう。
keep 'public class sample.AppMain { \ public static void main(java.lang.String[]); \ }'
直列化フィールドの保護
Javaのシリアライゼーションを使う場合には、パッケージ名、クラス名、フィールド名のどれも変更されてはならない。 ここでは、他の仕組み、例えばJSON等を使うことを想定している。
keepclassmembers '@sample.Serialized class * {\ <fields>;\ }'
これは以下のようなコードを想定している。
package sample; import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Serialized { public long key(); }
@Serialized(key=-4069057649147625984L) public class InputFile { private String path;
リソース取得コードの変更
これはproguardオプションではなく、コードの方を変更する。proguardはリソースに対しては何もしない。パッケージ名もそのまま、ファイル名もそのままなのだが、それを取得しようとするコードの方はパッケージの変更もしてしまう。例えば、
sample.resources Resources.java stylesheet.css icon.png
などというパッケージがあり、
@Singleton public class Resources { private Image iconImage = new Image(Resources.class.getResourceAsStream("icon.png")); .... }
などとやってると動作しない。Resourceクラスのパッケージが移動しないように保護するか、あるいはリソースの取得方法を変更する。
@Singleton public class Resources { private static final String PATH = "/sample/resources/"; private Image iconImage = new Image(Resources.class.getResourceAsStream(PATH + "icon.png")); ....