丸ダイスの卓上開発日誌

個人ゲーム開発者「丸ダイス」のページです! がんばりますね!

【Unity】NCMB インポート時のAndroidビルドエラーを読み解く

「NCMBのインポートの仕方」という記事ではないです(公式にやり方載ってますし…)。「よく分かんないエラーが出た時に、ググって出たAnswerをそのまま試すより、ログをしっかり読み込んだ方が早く解決出来たよ!」という記事です。

NCMBのインポート

リリースページ(Releases · NIFTYCloud-mbaas/ncmb_unity · GitHub)から、 v2.2.0 を選んでzipを解凍。

中身の.unitypackageをダブルクリック。表示されたインポートダイアログで「Import」をクリック。うんうん。普通ですね。

ここで、「Assets/Plugins/Android」以下に.jar, .aar ファイルがたくさん放り込まれているのが分かります。 「Unity Plugins フォルダ」なんかでググると、どうやらプラットフォームごとのネイティブプラグインを入れるフォルダのようです。つまり、NCMBではコア部分の実装がネイティブプラグインで提供されているわけですね。

Unity Editor 上では何事もなくコンパイルが通ります。

ビルド失敗!

ネイティブプラグインは、実際にそのプラットフォームでビルドするまで動作を検証出来ません。Android版をビルドしてみると、見事にビルドエラー。

Unity上での表示は「Unable to convert classes into dex format. See the Console for details.」Consoleを見ろって言ってますね。どれどれ。

Consoleを見てみる

CommandInvokationFailure: Unable to convert classes into dex format.
...

この後数千行続きます。長っ!とひるむところですが、ここで”ググりません”。少なくともUnityは「ビルドが失敗した理由はコレだよ!」と言っているのですから、付き合ってあげようじゃありませんか。

エラー出力の構造を推測してみる

先ほどのConsoleの出力の最初数行

CommandInvokationFailure: Unable to convert classes into dex format.
C:/Program Files/Java/jdk1.8.0_111\bin\java.exe -Xmx2048M -Dcom.android.sdkmanager.toolsdir="C:/Program Files (x86)/Android/android-sdk\tools" -Dfile.encoding=UTF8 -jar "C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\sdktools.jar" -

stderr[
Uncaught translation error: java.lang.IllegalArgumentException: already added: Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat;
..

1,2行目を見ると、文章になっている1行目はエラーの概要、2行目はオプション付きの長々としたコマンドのようです。

その後に

stderr[
Uncaught translation error: java.lang.IllegalArgumentException: already added: Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat;
Uncaught translation error: java.lang.IllegalArgumentException: already added: Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat$AccessibilityServiceInfoIcsImpl;
..

と続くところを見ると、「2行目を実行した時に、1行目のエラーが出て、エラーの詳細はstderr の中身の通りだよ」ということのようです。

あれ?じゃあstderrの後は?と見てみると

]
stdout[
processing archive C:\home\(Unityプロジェクトのパス)\Temp\StagingArea\android-libraries\AmazonAppStore\libs\.\classes.jar...
processing com/unity/purchasing/amazon/AmazonPurchasing.class...
processing com/unity/purchasing/amazon/AmazonPurchasing$1.class...
..

とあります。あとは最後まで全部stdoutの中身のようです。processing の後はクラス名のようですから、なるほど、2行目のコマンドでビルドした時の標準出力がstdoutの中に出てるわけですね。 つまりエラー出力の構文は

エラー概要
実行したjavaのビルドコマンド
stderr[ エラー詳細 ]
stdout[ javaのビルドログ ]

ということのようです。

java.lang.IllegalArgumentException: already added を解決しよう

今回のエラーは 「java.lang.IllegalArgumentException: already added」でした。中のクラスはもちろん書いた覚えはないですし、クラス名をProjectビューで検索してもそんな.jarは表示されません。 .jarや.aarの中には複数のクラスがまとまって提供されています。

でも、上のようにエラー出力の構文が分かると、(Unityではなく)javaのビルドした時のビルドログにクラスのビルド順序が記載されています。「already added」 なので、同じクラスを2コ追加しちゃってるのかな?とアタリをつけてログ全体で「android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat」を検索してみると…

processing android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.class

stdout[]の中にこの行が2つありました。フルネームが全く同じクラス名が2つ…なるほど、これではビルドできそうにありませんね…。 どうやら、今回のインポートで同じクラス定義をしている.jar, .aarが2つになってしまったようなので、それを取り除けば良さそうです。

ここで、さきほどの検索結果をもう一度見てみると、

processing archive C:\home\(Unityプロジェクトのパス)\Temp\StagingArea\android-libraries\support-v4-24.0.0\libs\.\classes.jar...
processing android/support/v4/BuildConfig.class...
processing android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.class...
..

ヒットしたクラス定義のすぐ上に、クラス定義ではなく.jarのファイルパスのようなものがあります。stdout[]全体を改めて眺めて見ると

processing archive (ファイルパス.jar)
processing (クラスフルネーム)
processing (クラスフルネーム)
..
processing archive (ファイルパス.jar)
processing (クラスフルネーム)
processing (クラスフルネーム)
..

が何度も繰り返されているようです。

なるほど!つまり(ファイルパス.jar)のアーカイブファイルに定義されているたくさんの(クラスフルネーム)を次々にビルドしているわけですね!

Tempの中に.jarを追加した覚えはないですが、.jarの固有名っぽい 「support-v4-24.0.0」には覚えがあります。UnityのProjectビューで検索してみると、見事ヒット! もう一つの方も、「processing (クラスフルネーム)」の上をたどって、含まれているarchiveは「android-support-v4.jar」だと分かりました。

NCMB.unitypackageをもう一度実行してみると、どうやらandroid-support-v4.jar は今回NCMBのインポート時に追加されたファイルのようです。

とりあえず新しい方のandroid-support-v4.jarを消してビルドしてみると、見事成功!※正確には、別の似たエラーが出たのでそちらも同じように解決しています。

めでたしめでたし。

ログ読みのススメ

こうやってログの中身をしっかり追ってみると、実はエラーの理由は人の目で追える形でしっかりと書かれていることが分かりました。

「よく分からんエラー」に遭遇した時は、エラー文を検索窓に突っ込んで、「こうしたら直りました」を実行するだけで直ることもあります。

でも、問題が起きた時に答えだけを求めるやり方より、一から仕組みを理解するようにした方が、似たケースが起きた時にすぐに対処出来て自分のプロジェクトをより自在に扱えるようになるのかなぁと、今更ながらに思った次第でした。

実際、※の別エラーは本当にあっという間に解決出来ました。

ログを読みましょう!Qiitaには嘘を書けますが、ログは嘘を付きません!