iOSのOpenGL ESを使ったアプリへのAdmobの組み込みに苦労した

2013-09-04

要約:iOSアプリでstatというグローバル変数を定義したらAdmobでコケた

本文

iOSでのゲーム作りはしたことがなかったのだけど、How To Create A Simple 2D iPhone Game with OpenGL ES 2.0 and GLKit - Part 1 | Ray Wenderlichを読みながら進めてみた。結構簡単にできちゃう。ES2.0はiPhone4以降でサポートされ、iPhone3Gなどでは動かないらしいので、別途対応した方がいいのかもしれないが、まあそれは別の話。

作ったアプリにAdmobを組み込もうとしたところ、大いに手こずった。iOSへのAdmobの組み込みは、Google DevelopersのGoogle AdMob Ads iOS(初級) - Google Mobile Ads SDK — Google Developersで、OpenGL ESじゃない普通のUIViewControllerのアプリで確認済み(ただこのドキュメントの通りでは動かなくて、AdSupportとStoreKitというframeworkも組み込んで、Other Linker Flagsに-ObjCを追加する必要がある)。

まずXcodeでプロジェクトを作るときに、上記のページのようにEmpty Applicationテンプレートから作ったプロジェクトだとGADBannerViewが表示されないという現象が起こった。setDelegateadViewDidReceiveAdは受け取っているので、読み込み自体はできてるんだけど表示されなくて、これは結局原因が分からなかった。

GLKViewControllerを使ったアプリにAdmobを組み込めないのかと思ったが、プロジェクトをEmpty Applicationからじゃなくて、OpenGL Gameテンプレートから作ると表示されることがわかった。原因は不明。

で自分のアプリに組み込んでいったところ、GADBannerViewloadRequestを呼び出すとEXC_BAD_ACCESSで停止するという現象が出た。エラーの出る位置としては、

[GADCachedFile fileModificationDate] at GADCachedFile.m:86:

というところで止まる。これが必ず止まる訳ではなくて、Cleanしたら一時的に動くけど、なんか変更するとやっぱり発生する、とかいう謎の状態だった。

原因が分からなくて、ゲームのロジックを全部外して、また一つずつ追加したりしてすったもんだしたあげくようやく原因がわかった。グローバル変数にゲームの状態を示すstatという変数を使っていたのが問題だった。この変数はenumの型で宣言していたので、1バイトになってしまってアライメントがずれてうんぬん、かと思って FORCE_DWORD = 0xffffffff とか無理矢理4バイトにしてみたがダメ。とかあれこれやっていたが、ふとC言語のシステムライブラリにstatという関数があることを思い出した。同じ名前を使ってしまっていたのでライブラリにあるstat関数はリンクされず、Admobの中からstatが呼び出されたときに変数領域を実行しようとしてエラーが出ていた、ということだった。

これちょっと発見するの難しいなぁ。そもそもグローバル変数を使わなければいいんだろうけど。