[unity]Google AdMob とか、すぐ動かなくなってハマるよね

unity ならマルチターゲット簡単! 悩む必要なし!

とはいかないのが世の常。動かすまではなんとなくなるものの、いざ Google Play や App Store に登録となると、ゲーム作成とは別の知見が必要です。

Firebase AdMob など、連携して便利なライブラリもそう。
Unity Editor では動いてるけど、iOS や Android でビルドすると動かなくなる、バージョンあげたら動かなくなる、誰しもがそんな経験をしています。

「動かない」場合、unity だけではなく当然 iOS や Android の知識が必要です。
必要になる、とか言われても xcode や Android Studio、わからないよ?

unity がどのように各 OS で動くプログラムに変換され、どんなセキュリティスイッチを付与されてストアに並ぶのか。
そこへ行きつくために、どれほどの道を登っていくのか。

Google AdMob ではありませんが、そんな私の「いち経験」を時系列に沿って記してみました。
unity-jar-resolver など、知っておいて損のない内容もあります)
結構前の話になるので、ウロ覚えの部分もあります。予めご承知おきください。

unity で GoogleDrive を使いたい

そもそも Google Drive にアクセスするまでの下準備がかなり大変。
それは別の記事に譲るとして、次、unity で Google Drive にアクセスするには……。
実は、(驚くことでもないですが)公式ライブラリは存在しません。

こちらの Google APIs client Library for .NET といういかにも使えそうなライブラリですが、

  • Windows しか使えなさそう(せいぜい Unity Editor どまり)
  • 生トークンをテキストでわかりやすい場所に保存してたり、公開アプリに使うには危険そう

サンプルを動作させたり色々とチェックするとこんな感じだったので、アプリ公開には向いてなさそうです。断念。

他に使えそうなものはないか……と探したところ、UnityGoogleDrive という個人の方が作成したライブラリを発見しました。触ってみましたが、かなり使えそうです。
iOS でも Android でも動作しました。やったね!

ただ、ライブラリが 3 年前で止まっているのは気になりました。
そしてその不安は的中します。後ほど、色々な問題となっていくのです……。

Google Play 登録時にエラー

問題は Google Play 登録時に発生しました。

unity では API Level28 で開発していましたが、Google Play でアップロードエラー。
最低でも API Level31 が必要という無常の宣告を受けてしまいます。

API Level ... Android Build する際に、Player Settings で API(OS) Level を設定する

また、API Level31 以上(今回は最新の 33 にしました)にしてアップロードしようとすると、今度は android:exported がどーたらという謎の警告により、やはりアップロード出来ません。
何いってるか全然わからんが、対処法はあるだろうとググったところ、カスタム AndroidManifest.xml とやらを作って、その xml に android:exported = true を書けという記事がありました。

AndroidManifest.xml ... ファイルに含められない、ビルドに必要な属性が書かれている指示書。実行時に共有する情報だったり、セキュリティやプライバシーに関わる事が書かれている。

なんだ、簡単そうだなぁ? と言われた通りにしてみますが、世間はそんなに甘くありません。
相変わらず Google Play の android:exported 警告は消えず、そこから先に進めませんでした。

UnityGoogleDrive になんかある……?

その後もググって似たような記事をあさり散らかしておりましたが、ふと「Android.xml が複数ある場合、全てに android:exported = true を書かないといけません」と書かれている記事を発見。

私の知る限り Android.xml は1つですが、中身がどうなっているか全く知らずに使っている UnityGoogleDrive

Google Drive にアクセスしているくらいです。この中にきっとなんかあると推測しました。

UnityGoogleDrive を解析する

私は「中身を知らずに使えるなら、それが幸せ」的なお気楽プログラマーなのですが、必要とあれば仕方ありません。UnityGoogleDrive がどのように動作しているのか解析します。

有能なプログラマー諸兄は、むしろ解析を楽しみにしている方がほとんどでしょう。

幸いほとんどは C# コードで記述されており理解しやすくなっていました。
ブレークを置いて動作を確認、Debug.Log で出力結果を確認……。

ほぼ全ての動作ルートを調べ上げたところ、C# コードではなく、ネイティブプラグインを使っている部分を発見します。

ブラウザの Google 認証画面に飛び、認証が終わったらアプリに戻る。

……確かに、この一連の流れは言葉にすると簡単ですが、unity のみでやるのは難しそうですよね。

セキュリティリスクがあるため、1つのアプリから別のものを起動したり、その結果を返してもらう実装は困難なことが多いです。

Android 用のネイティブプラグインは次のファイルでした。iOS も同じフォルダにありました。

com.elringus.unitygoogledriveandroid.aar
com.elringus.unitygoogledriveios.mm

iOS はプログラムテキストファイルのようです。Xcode の慣れない書式に少しウッ、としてしまいましたが確認できるだけ優しい。
対して Android の aar ファイルはなんだかややこしそう。

aar を調べたおす

どうにかリバースエンジニアリングできないか……とネットから知見を漁っていたら正体はただの zip ファイル(+α)でした。

拡張子を zip にかえ、解凍も出来る。おお。

いたあああああああああああ AndroidManifest.xml!!

        <activity
            android:name="net.openid.appauth.RedirectUriReceiverActivity"
            tools:node="replace" >

android:exported = true ねーんだろ? ねーよな? やっぱねーよ!

どうやら犯人はこいつのようです。

ちなみに、activity タグに全部 android:exported = true を書くわけではないようです。
intent-filter > action を持ってるタグに必要そう?
その先の知識は今回に不要と考え、詳しくは調べませんでした。

ここで私の考えた作戦ですが、

  • aar を解凍する
  • AndroidManifest.xml に必要なキーワードを書き足す
  • もう 1 度 aar に戻す

「もっかい zip で固めて aar に戻せば OK!」なんて記事もあったので期待したんですが、現実はそんなに甘くありませんでした。

zip 圧縮して、拡張子を aar にしても、ファイルが正しく認識されませんでした。

まあ、ちょっと考えてみれば圧縮率が色々ある zip のどの圧縮率にするべきかわからないし、多分 zip のヘッダに aar である事を示す情報なんかも必要なんでしょう。

さて、真面目に向き合うには Android Studio なのか……新しいツール覚えるのか……イヤダ……イヤダ……。

Android Studio 嫌いすぎて調べてたら、他の方法を見つけた

素直に Android Studio にいくのがまっとうな職人です。

だが、私は Android に関しては「ただの趣味プロ」。自分のスマフォも iPhone だし全然モチベーションが上がりません。

正直、この時点で Android 非対応にするまで考えてた

だらだらと他のやり方を探していたところ、複数の AndroidManifest.xml は最終的にマージされる事に気づきます。
ならば unity で作成した AndroidManifest.xml が優先されるんじゃない? と書き足したところ、

なんと Google Play にアップロードする事が出来てしまいました。

これでハッピーエンドだったらよかった

いやー散々 UnityGoogleDrive を調べまわしたけど、結局 unity だけで済んでよかった!
上手くいった時の私は、きっとこんな顔をしていたでしょう。

幸せだったのは Android 実機に入れて実行するまででした。

ここで一応 Android Studio を入れました。実機テストで便利そうだったため。
Android しらなすぎて Canary Build(開発中バージョン。普通は選ばない)使ってたのも、いまとなってはいい思い出。

例の Google 認証画面に移行するところでハングアップ。
せめてエラーメッセージを確認したい、というわけでググって方法を検索します。

Android Studio 入れたにも関わらず unity でログでないか探す私。どれだけ Android Studio 嫌いなんでしょうか。

幸い Android LogCat というパッケージがありました。それを unity に入れてログを確認したところ、GoogleDrive 認証に移行するファンクションが見つからない(android.content.ActivityNotFoundException)というエラーが表示されています。

また目を皿のようにして眺めまわす

終わったと思った UnityGoogleDrive のコードをまたペロペロしはじめます。
色々と新しく知った情報やキーワードでググり直すのも忘れません。
この辺まで来ると、日本語サイトの情報は見尽くし、英語サイトに手を出し始める。


classes.jar ってファイルも zip みたいです。解凍すると *.class というファイルが出現。
これが java コードで、テキストで書かれているのかと思ったところ、なんとバイナリファイル。
コードの中身を見るのは諦め、再び AndroidManifest.xml

その中にキニナル一文を見つけました。

targetSdkVersion = "28" だと……?

Google Play に通すため、API Level は 33 にしています。28 なので不一致です。

不一致だからこのコードは実行プログラムにリンクされず、結果ファンクションがない、という状態になっているのでは?

そう推察しました。

Android Studio さんにすり寄り始める

タグ uses-sdk を unity の AndroidManifest.xml で上書きしようとしましたが、それでは上手くいきませんでした。

さすがに aar をひも解いて、編集する日が来たか……。

Android Studio の使い方は当然わからず、いちから調べ直しです。
SDK の入れ方も覚える。「管理者として実行」は忘れずに。

File > Open すると aar の中身を綺麗に確認することができました。
.class ファイルもバイナリではなく、ちゃんと見える。

でも実は最初、ソースコードが一部しか見えませんでした。
色々やってたら見えるようになった。なにをしていたか思い出せない。

全てテキストとして確認できるなら、次のシナリオです。

  • 新しい、空の aar を作成する
  • 元の aar をコピーし、新しい aar に移植
  • AndroidManifest.xml は uses-sdk を書き換える
  • aar をコンパイルし、作成!

なんか楽勝そうですが、ツールの使い方がわからないので苦労します。
最初の最初からつまづいていました。

aar を作成するには……どこのサイトでも「New Module...」選べって書いてあるんだが、メニューにない。
いくら探しても見当たらない。

ここで自分の Android Studio Canary Build が「人柱バージョン」である事に気づき、リリースバージョンを入れなおしたりしましたが、問題はそこじゃなかった。

どうやら、空プロジェクトを開かないとメニューに出てこないみたいです。

知らないってこういう事。
知ってれば数分もかからないのに、数時間(ヘタすると数日)かかったりする。

その後も1つ1つ、確かめるように aar の作成を進めます。

・build.gradle に net.openid:appauth:0.7.+ を入れる必要があった
・AuthorizationActivity$~.class は自動的に生成されるので自分では作らない

コピーするだけだと発生したエラーメッセージを頼りにググり、1つずつ問題を解消していきます。

net.openid:appauth:0.7.+

最終的なゴールの布石となりますが、ここでは aar 作成エラー解消のための記述です。
UnityGoogleCloud の Editor フォルダにある Dependencies.xml から拝借しました。

Dependencies.xml ... Google 関係のライブラリを使う場合ほぼ必須といってもいい unity-jar-resolver (External Dependency Manager) が参照、必要なライブラリとそのバージョンを書き記すテキスト。

無事 aar ファイルを作成できました!

このストレスと、ストレスからの解放の繰り返しがプログラマーだよなぁと、Android Studio から散々逃げ回っていた男は今までの苦闘の道を思い返しましたが、

苦闘はまだ続くのでした。中島みゆきの歌が終わらない。

そう、uses-sdk targetSdkVersion を変えるだけでは、動かなかったのです。

もうちっとだけ続くんじゃ

そう言ってからの方が長いくらいドラゴンボールは延々と続きましたが、この苦闘はいい加減早く終わらせたくて仕方ない。
とはいえ、ここまで一生懸命解決の糸口を探したけど、完全に途絶えてしまいました。

もう1度今までやった事を見返したりしましたが、特に問題になりそうな事もありません……。

万策尽きたので、UnityGoogleDrive issues にヒントを求めました。

GitHub の issues

issues ではライブラリを使った人に生じた問題と、それに対する作者の回答を見ることができます。
英語ですが、Chrome の日本語訳を使えば困ることはないでしょう。

ここで API Level30 で動かないという人のイシューがありました。
解決策として、Dependencies.xml を変更してください、と書いてありました。

<dependencies>
  <androidPackages>
    <androidPackage spec="net.openid:appauth:0.7.+" />
  </androidPackages>
  <iosPods>
    <iosPod name="AppAuth" version="~> 1.3.0" bitcodeEnabled="true" minTargetSdk="7.0" />
  </iosPods>
</dependencies>

先ほど aar を作成した時に参照した net.openid:appauth:0.7.+
これが Google 認証画面を出すためのライブラリなのですが、ふとここで疑問がわきました。

そもそもこのライブラリ、今最新いくつなんだ?

調べてみると 1.1.+ が最新のようです。API Level 33(最新)なら、これも最新にするべきじゃないのか……?

Dependencies.xml は Editor フォルダに入れますが、これも Packages より Assets 以下のファイルが優先される事もわかりました。AndroidManifest.xml と同じく、上書き作戦が可能と言うことです。

UnityGoogleDrive の Dependencies.xml を Assets/Editors/Dependencies.xml にコピーし、バージョンを 1.1.+ に書き換えます。
その後 External Dependency Manager > Android Resolver > Force Resolve でライブラリを強制アップデート!

解決……ッ……!

頼むッ! これで動いてくれ!

天にも祈るような気持ちで Android 実機で試すと……やった! 動いた!!
散々遠回りしたけど、なんとかなった! やったー!

ここまでに要した時間を正確には覚えていませんが、おそらく 10~20 時間以上はかかったでしょう。
短いゲームならクリアできそうです。

こんなちょっとした事のために、プログラマーは膨大な時間やリソースを必要とする事があります。
ですが、同時に私が得たものはとても大きかったです。

  • UnityGoogleCloud を使わず GoogleCloud にアクセスできるコードが書けそうなくらい知見が深まった
  • Android Studio の基本的な使い方を学んだ
  • unity-jar-resolver を学んだ。API Level とこれが密接に関わっていることもわかった
  • AndroidManifest.xml や Dependencies.xml を理解した
  • unity とネイティブライブラリのやりとりの仕方を理解した
  • ほかの こんなんに たちむかう ゆうきを えた

今度似たような問題に直面したとき、おそらく解決まで 1 時間もいらないでしょう。
少なく見積もっても 10 倍、下手すると 50 倍もの時短が可能になるわけです。

面倒な事、したくないよね

そう思うプログラマーが市井に溢れれば溢れるほど、「解決できる」プログラマーは英雄として扱われ、仕事単価も上がっていきます。苦労すればするほど、己の解決速度が上がっていく(=時短)ので、上がるしかないのです。

時短すればするほど仕事を増やされる場合、交渉能力を磨き、転職も視野に入れましょう。

そこまで自分を優秀と思わないベテランプログラマーでも、全くプログラムを知らない新人 10 人より、俺がやった方が速いな……そう思うことはあるはずです。
それぐらい、プログラマーは人によるスキルの格差が、仕事の速度や質に出るジョブです。

ただ、漠然と自分に必要ないと思いながら学び続けるのは、一部の生粋プログラマーを除き困難なことも確かです。

そんな自分でもスキルを高められる秘訣は、

  • 自分の作りたいもの(目標)を必ず持つ
  • 自分の作りたいものをなるべく妥協せず作る

At Coder や Paiza などで、ゲーム感覚でスキルを伸ばすのもいいですし、完成品を作り、自分なりの成功体験を積み重ねていきましょう。

最初から大作は必要ありません。
でも、今自分が出来ることより少し上を常に目指してください。
それを年単位で続けていると、いつしか周りが貴方に向かってこう言うでしょう。

プログラムの才能あるよね? うらやましい。



返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA