Edited at

ProGuardで-dontoptimizeを使いたくないから作った何か

More than 1 year has passed since last update.


はじめに


結論

https://github.com/nao20010128nao/ProguardTransformFix


はじめに

こんなエラー見たことありませんか?

Unexpected error while computing stack sizes:

Class = [com/google/android/gms/internal/zzgr]
Method = [run()V]
Exception = [java.lang.IllegalArgumentException] (Stack size becomes negative after instruction [166] pop in [com/google/android/gms/internal/zzgr.run()V])
Warning: Exception while processing task java.io.IOException: java.lang.IllegalArgumentException: Stack size becomes negative after instruction [166] pop in [com/google/android/gms/internal/zzgr.run()V]

Support Libraryとかgms更新すると-dontoptimize無しには難読化はできなくなってしまいます。

でも使いたい! 1

もちろん、

-keep class com.google.android.gms.internal.zzgr { *; }

は効きません。

ProGuard改造なんてしてもまともに動かない。

でも結局諦めるしか...と思いつつ考えていたら、ある結論にたどり着きました。

ProGuardを2回やればいいんだ


Transform API

AndroidのGradleプラグインには、Transform APIなるものがあります。2

詳細については省きますが、これにはProGuardで難読化する部分があります。3


優先順位は選べない

GradleにはdependsOnみたいにTaskの順番を左右する指定をすることができますが、Transform APIが崩壊するのは間違いないので使わないことにしました。

また、android.registerTransformはTransformの順番を変えられないので、途中に挿入することは諦めました。


改造

じゃあTransform自体を改造すればいいじゃない!

Transformをなんとか改造すれば、ProGuardを起動するまでの部分に手を加えることができます。

TransformTaskがガバガバだったこともあり4これだ!と一瞬閃きました。

ですがJVMの仕様上、一度読み込まれたクラスは書き換えられません。

書き換えるのではなく、継承をしつつ、TransformTaskにはフィールドの読み書きで対応することにしました。

意外とコピペでもエラーは多く出ないんですね。びっくりしました。


2段階ProGuardって一体何してるの?


1段階目

ユーザーの指定したProGuard設定を少し変更し、入力ファイルの組成を変更して難読化をします。

ProGuard設定の変更内容

-keep class **.R { *; } # 追加

-keep class **.R$** { *; } # 追加

libraryJars

- android.jarと愉快な仲間たち

- jarファイル(大体ライブラリです)

inJars

- ディレクトリのクラスファイル群(大体プロジェクトに属するコードです)

inJarsからライブラリを排除することが重要で、これをすれば難読化ができます。


2段階目

ユーザーの指定したProGuard設定を少し変更し、入力ファイルの組成を再変更して難読化をします。

ProGuard設定の変更内容

-dontoptimize # 追加

libraryJars

- android.jarと愉快な仲間たち

inJars

- 1段階目でのjarファイル(1段階目の時点では変わっていません)

- 1段階目で吐き出したjarファイル

ここまでの時点ですべての入力クラスファイルが全てProGuardによって処理されます。

エラー? 出ませんよ5


最後に

ここまでご覧いただきありがとうございました。

ソースコードはここに置いておいたので、改変するなりPRするなりIssueするなりご自由に。

そしてJitPack.ioって便利ですね






  1. -dontoptimizeの使用が推奨されている模様。仕方ないね 



  2. transformで始まるTaskがTransform APIによるものです。 



  3. https://github.com/nao20010128nao/android-gradle-plugin-source-codes/blob/master/gradle-core-2.4.0-alpha7-sources/com/android/build/gradle/internal/transforms/ProGuardTransform.java 



  4. 面白いことにTransformTasktransformフィールドはfinalではないのでリフレクションで触れるんです。 



  5. 少なくとも投稿者の環境では、ですが。