もんりぃ is undefined.

育児ネタとか、技術ネタとか。

Unity Android ビルドの Minify オプションの罠

はじめに

前回のポストから2ヶ月くらい空いてしまいました。

生きてます。ありがたいことに忙しいです。

さて、今回は 含まれているはずの Native Plugin のクラスが AndroidJavaClass で参照出来ない という問題に遭遇したので、備忘録として記します。

現象

Unity 2018.3 でビルドした Android Player が AndroidJavaClassAndroidJavaObject を利用する箇所で ClassNotFoundException *1 を吐く

java.lang.ClassNotFoundException: android.support.v4.content.ContextCompat

前提

  • Unity 2018.3.6f1
  • Build Type: Gradle
    • 今回 Unity 2018.3 対応する際に Internal から切り替えました
  • AndroidJavaClass が参照する Java クラスは .aar ファイルにて提供される
    • 利用したいクラスは android.support.v4.content.ContextCompat

調査

最初は「Firebase SDK に同梱される Play Service Resolver によって提供される .jar ファイルや .aar ファイルが古い…?」とか「Gradle に切り替えた *2 コトにより、ライブラリが競合した…?」などの可能性を模索して mainTemplate.gradle をプロジェクト内に置くなどして頑張ってもダメで、途方に暮れていました。

が、ふと「ビルドまでは存在しているクラスが消える」という現象から「あれ?Code Strip 的な動きじゃね?」と思い至り、そっちの方面から調査を再開しました。

んで、調べていると Android Project として Export した際に吐き出される build.gradle 内に以下のような記述を発見しました。

android {
    buildTypes {
        debug {
            minifyEnabled false
            useProguard false
        }
        release {
            minifyEnabled true
            useProguard true
        }
    }
}

*3

で、「Proguard の難読化によってクラス名変わった!?」と思い、オプション変えるもダメ。

「何でだよー!」と思い、ダメ元で「 minifyEnabledfalse に変える」と「ウゴイタァァァ!!!

原因

ProGuard を用いた Minify 処理により、 AndroidJavaClassAndroidJavaObject からしか参照されていないクラスが落とされていた。

AndroidJavaClassAndroidJavaObject はリフレクション(厳密には違うと思うけど)的な処理であり、コンパイラ的には参照を解決できないために Minify 時に落とされてしまうワケですね。

対策

雑に対応

PlayerSettings の Minify > Release を ProGuard から None に変更する。

f:id:monry84:20190312155758p:plain

カチッと対応

PlayerSettings の Minify > Release は ProGuard のままにし、 User Proguard File を有効にする。

f:id:monry84:20190312160404p:plain

(まだファイルが無ければ)自動生成される proguard-user.txt の内容を以下のようにする。(もっと詳細に指定しても良いかも知れません。)

-keep class android.support.v4.content.** {
    *;
}

所感

実は、デバッグビルドだと問題なく動いていたようで、その確認を怠ったために切り分けが長引いてしまいました。

ビルド周りは、出力先プラットフォームが利用する技術への理解が必要になるので、なかなか大変です…。

*1:C# ではなく Java の Exception です。

*2:これまでは Internal を利用していました。

*3:関係無い行は消しています。