横画面(Landscape)固定で開発しているiOSアプリ(Kotlin Multiplatform / UIKit環境)において、Google AdMobのインタースティシャル広告(GADInterstitialAd)を表示した際、「上部のタイマーやTest Modeバッジ、右上の閉じるボタン等の外枠は表示されるが、中央の広告本体が真っ黒(ブランク)になる」という不具合に遭遇した。
Info.plist の UISupportedInterfaceOrientations に Landscape のみ(UIInterfaceOrientationLandscapeLeft / Right)を指定していると、AdMob SDK 内部でモーダル表示される GADFullScreenAdViewController および広告描画用 WKWebView が、Portrait基準のクリエイティブ(Google公式テスト広告等)の Viewport・レイアウト計算を行えず、WebKitのレンダリングが抑制・停止してしまうため。Info.plist の UISupportedInterfaceOrientations は「アプリ全体で許可しうる画面向きの最大集合(スーパーセット)」として定義し、Portrait も許可リストに含める。その上で、アプリ側の各画面(RootViewController や WindowScene)で Landscape 固定の制御を行う。GADInterstitialAd)ca-app-pub-3940256099942544/4411468910AdMob のインタースティシャル広告が表示される内部構造と、レンダリング失敗の流れは以下の通り。
graph TD
A["GADInterstitialAd.present(fromRootViewController:)"] --> B["GADFullScreenAdViewController (モーダル表示)"]
B --> C["① ネイティブUIKit外枠 (タイマー / Test Modeバッジ / ×ボタン)"]
B --> D["② 広告コンテンツ描画コンテナ (WKWebView)"]
C -->|UIKitが直接描画| E["✅ 正常に画面上部・枠線が表示される"]
D -->|Info.plistがLandscape固定| F["❌ PortraitクリエイティブのViewport計算が破綻 / レンダリング抑制"]
F --> G["⬛ 中央の広告コンテンツが真っ黒なまま停止"]
WKWebView を介して動的に HTML5/CSS/メディアをロード・レンダリング している。Info.plist の UISupportedInterfaceOrientations に UIInterfaceOrientationPortrait が含まれていない場合、システム(UIKit)は Portrait 向きのビュー構築・座標系計算を許可しない。WKWebView の CSS Viewport や内部レイアウト計算が破綻し、WebKit のレンダリングレイヤーが描画を完了できずに黒画面(ブランク)のまま停止する。AdActivity)は、端末の画面向きとクリエイティブの向きが一致しない場合でも、OS/SDK レベルで自動的にレターボックス(背景余白+アスペクト比を維持した縮小表示)を適用してレンダリングする強力なフォールバック機能を持っている。Info.plist で Landscape のみにしておくと AdMob インタースティシャル広告の動画やクリエイティブが黒画面になる」というものであり、「Info.plist では Portrait を許可し、アプリ層で画面回転をロックする」 アプローチが標準的な解決策として定着している。Info.plist に UIInterfaceOrientationPortrait を追加し、アプリが取りうる向きの最大集合を定義する。
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
アプリ本体の画面が勝手に縦向きに回転してしまわないよう、RootViewController や WindowScene 側で Landscape 固定を指定する。
// RootViewController 側の制御例
class MainViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscape
}
override var shouldAutorotate: Bool {
return true
}
}
これにより、アプリの通常画面は横画面固定のまま維持されつつ、AdMob SDK が表示する GADFullScreenAdViewController は必要な向きでビューを初期化・レンダリングできるようになる。
GADInterstitialAd のライフサイクル、および最前面の UIViewController からの present(fromRootViewController:) によるモーダル表示仕様。ca-app-pub-3940256099942544/4411468910)の仕様。テスト広告のクリエイティブは Portrait 基準の HTML5 / メディアテンプレートで構成されている。google-admob-ads-sdk「アプリが
Info.plistのUISupportedInterfaceOrientationsで Landscape のみを指定している場合、SDK内部で生成されるフルスクリーン用 ViewController(GADFullScreenAdViewController)は、配信された Portrait 前提のクリエイティブを適切にレイアウト・レンダリングできず、外枠の閉じるボタンやプログレスバーだけが表示されて中身の WebContent 領域が黒/ブランク画面になる場合がある。これを解消するには、Info.plistで Portrait を許可した上で、アプリ側の各画面(ViewController / WindowScene)側で Landscape 固定の制御を行うことが推奨される。」
Info.plist の UISupportedInterfaceOrientations は、「アプリ内で表示されうるすべての ViewController が取りうる向きの最大集合(スーパーセット)」を定義する。setNeedsUpdateOfSupportedInterfaceOrientations() や UIWindowSceneGeometryPreferencesIOS など画面向き制御の推奨APIが刷新されているため、Swift / KMP 側のライフサイクル連携を意識した堅牢な実装を維持する。本記事の調査・原因特定に至った AI アシスタントとのやり取りログ。
調査結果と根本原因の特定に関して、一次情報・参考情報が知りたいです。
AdActivity のレターボックス対応)との差異や、Unity/Flutter 等の横画面ゲームでの共通事例を整理。