Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Locked History Actions

proguard/Options

オプション

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>;\
  }'

以下のようなコードでJSONを使ってシリアライズすることを想定した。この場合、パッケージ名・クラス名は変更されてもよい。 フィールド名が変更されなければよい。

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;

※本当はstatic, transientは名前変更されても良いのだが対応は省略。

リソース取得コードの変更

これは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"));
  ....

マップの取得

難読化後のプログラムがうまく動作せず例外が出る場合、あるいはリリースした後で例外が出る場合、そのスタックトレースも難読化後のパッケージ名、クラス名、メソッド名になっているので、そのまま見てもチンプンカンプンということになる。これを元に戻すためのマップの出力も必須。例えば以下のようにする。

  printmapping 'mapping.txt' // 何でもよい
  renamesourcefileattribute 'SourceFile'
  keepattributes 'SourceFile,LineNumberTable'

例外のスタックトレースをstacktrace.txtに取得したとすると以下のように元のスタックトレースを表示することができる。

C:\proguard5.3.2\bin\retrace.bat mapping.txt stacktrace.txt 

他のkeepattributes

'SourceFile,LineNumberTable'の他にも以下があり、正直どのような働きをするのかわからないが、指定しないと意図しないコードになるようだ。 おいおい調査する予定。

 keepattributes 'Exceptions,InnerClasses,Signature,Deprecated,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod'