Android APK軽量化とコードの難読化でハマったこと

ユーザーの端末の容量を圧迫しない設計,リバースエンジニアリング対策,という観点から,Play ストアに公開するときは APK の軽量化とコードの難読化を行うほうが良いとされています.

Android Studio では ProGuard ツールを使うことで,簡単に軽量化と難読化ができるようになっていますが,簡単といってもエラーは出まくったので,エラーの解決方法を残しておきます.間違ってたらご容赦ください.

APK を圧縮する方法

Android 公式の コードとリソースの圧縮 を参考にしています.

build.gradle

android {
    ...
    buildTypes {
        debug {
            minifyEnabled true // コードの圧縮
            useProguard false // デバッグ版では難読化と最適化は行わず,未使用のコードのみ削除
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'shrinker-rules.pro'
        }
        release {
            shrinkResources true // リソースの圧縮
            minifyEnabled true // コードの圧縮
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'shrinker-rules.pro'
        }
    }
}

ProGuard を適用するとビルドにかかる時間が長くなりますが,デバッグ版では難読化や最適化を行わないため,リリース版よりはビルドが早く終わります.

エラーや警告が出るときの処理

上記の方法で圧縮できますが,ビルドするときにエラーが出ることがあります.難読化によってクラスが参照できなくなるようです.

それを防ぐために,一部のクラスは難読化の対象から外す必要があります.

難読化によって読み込むことができなかったクラスは Build タブ内の Toggle View で can't find referenced class... という警告文で表示されます.

Google のチュートリアル含め,数多くのサイトで除外したいクラスは -keep で宣言するように,と案内されていますが,一概にそれが望ましいとも言えないらしいです.

参考にした記事 (一番下に掲載) の内容を踏まえて,次のように記述しました.

proguard-rules.pro

-keepclassmembernames class com.example.** { *; }
-dontwarn com.example.**

クラス名は適宜変更してください.

それから, -dontwarn は参照先のクラスが存在しないときの警告を無視するための設定ですが,これは軽量化により使用しないクラスが削除されたときに,参照せずとも問題ないと判断できるために使われているようです.

注意点

デバッグ版では難読化と最適化を行わないため,デバッグ版が問題なく動作していても,難読化した後のリリース版で動かない可能性があるので,最終的にはリリース版のテストも必要になります.

他に遭遇したエラーの内容

Please correct the above warning first

すごくざっくりしたエラーメッセージが最初に表示されたので,追ってみると Job failed, see logs for details というメッセージが出ています.

以前の Android Studio では Message タブがあり,そこで確認できたらしいのですが,今は削除されていて,今は Build タブ内の Toggle View ボタンに代替されています.

Toggle View に切り替えると,詳しい内容が載っています.

Warnings found during shrinking please use dontwarn or ignorewarnings to suppress them

デバッグ版のアプリをビルドするときにこのエラーが出ることがあります.

shrinker-rules.pro

-ignorewarnings

上記のように記述した shrinker-rules.pro を追加し,build.gradle 内で読み込むことによって警告を無視することができます.

build.gradle

android {
    ...
    buildTypes {
        debug {
            debuggable true
            minifyEnabled true
            useProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'shrinker-rules.pro'
        }
    }
}

しかし,リリース版では警告を無視するわけにもいかないんじゃ...と思ったりしています.当然,そもそもビルドしたときに警告が出ないなら,このエラーも出ません.

参考