はじめに
結論
はじめに
こんなエラー見たことありませんか?
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って便利ですね
-
-dontoptimize
の使用が推奨されている模様。仕方ないね ↩ -
transform
で始まるTaskがTransform APIによるものです。 ↩ -
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 ↩
-
面白いことに
TransformTask
のtransform
フィールドはfinalではないのでリフレクションで触れるんです。 ↩ -
少なくとも投稿者の環境では、ですが。 ↩