invertase/react-native-google-mobile-ads

[🐛] iOS 26.5: app frozen (touches dead) after a rewarded ad auto-dismisses or after backgrounding during the ad — adDidDismissFullScreenContent never fires

Open

#859 opened on 2026年6月10日

GitHub で見る
 (1 comment) (1 reaction) (0 assignees)TypeScript (213 forks)github user discovery
help wantedstale

Repository metrics

Stars
 (1,010 stars)
PR merge metrics
 (PR metrics pending)

説明

What happened?

Description

On iOS 26.5 (physical devices only), after a rewarded full-screen ad is dismissed non-interactively, the underlying app screen becomes frozen: all touches are dead, but the app is not crashed and the JS thread is still alive (our timers keep firing). adDidDismissFullScreenContent (CLOSED) is NEVER emitted. The freeze survives a background→foreground cycle (app switcher AND going to the home screen and back). Only a full force-quit of the app restores interactivity.

When the user manually taps the close (X) button, everything works (CLOSED fires, no freeze). The freeze only happens on a non-interactive dismissal.

Not reproducible in the iOS Simulator — physical device only.

Steps to reproduce

Two reliable triggers:

  1. Auto-dismiss: watch a rewarded ad that closes by itself (end of video / end-card).
  2. Background during the ad (≈100% reproducible): start a rewarded ad → send the app to the background (home screen) while the ad is showing → reopen the app from its icon → the screen behind is frozen.

Expected

The ad dismisses, CLOSED fires, the underlying screen is interactive.

Actual

The ad disappears visually but the underlying screen is unresponsive to touches; CLOSED never fires; only force-quitting the app recovers. Happens on any underlying screen (not tied to a specific navigation).

What we already ruled out (none fixed it)

  • Google Mobile Ads iOS SDK 13.5.0 (latest) — same.
  • react-native-google-mobile-ads 16.3.3 (latest).
  • react-native-screens 4.16 → 4.24 (the iOS 26 "interactions during transition" fix).
  • Disabling AdMob ad pods on the rewarded unit (only helped sequential ads).
  • Our own foreground-recovery / fresh-reload logic, and the keyWindow / app-switcher trick.

This looks like an iOS 26.5 view-controller / window lifecycle issue triggered when the ad's full-screen VC is dismissed without user interaction (we also filed Apple Feedback).

Environment

  • react-native-google-mobile-ads: 16.3.3
  • Google Mobile Ads iOS SDK: 13.5.0 (also seen on 13.1.0 / 13.4.0)
  • React Native 0.81.5, Expo SDK 54, New Architecture (Fabric) enabled
  • iOS 26.5, physical iPhone (seen on iPhone 11/13/15/16/16 Pro/17)
  • Ad format: Rewarded, presented from the rootViewController

Extra

Happy to provide a screen recording of the freeze and a device console log showing show() called with no subsequent reward/dismiss callback. We also have a related Google AdMob support ticket (7-7376000040875).

Platforms

Only on iOS

React Native Info

System:
  OS: macOS 26.5.1
Binaries:
  Node: 25.3.0
  npm: 11.7.0
  Watchman: 2026.04.20.00
Managers:
  CocoaPods: 1.16.2
SDKs:
  iOS SDK: iOS 26.2 (build) — test devices on iOS 26.5
IDEs:
  Xcode: 26.2 / 17C52
npmPackages:
  expo: 54.0.33
  expo-router: 6.0.23
  react: 19.1.0
  react-native: 0.81.5
  react-native-google-mobile-ads: 16.3.3 (Google Mobile Ads iOS SDK 13.5.0)
Expo Workflow: bare (prebuild)
New Architecture: enabled

Are your using Typescript?

  • My project is using Typescript

package.json

{
  "name": "noctua",
  "version": "1.0.0",
  "main": "expo-router/entry",
  "scripts": {
    "start": "expo start",
    "start:tunnel": "expo start --tunnel",
    "start:clear": "expo start --clear",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "expo lint"
  },
  "dependencies": {
    "@expo-google-fonts/archivo-black": "^0.4.1",
    "@expo-google-fonts/cormorant-garamond": "^0.4.1",
    "@expo-google-fonts/crimson-text": "^0.4.0",
    "@expo-google-fonts/eb-garamond": "^0.4.2",
    "@expo-google-fonts/inter": "^0.4.2",
    "@expo-google-fonts/literata": "^0.4.3",
    "@expo-google-fonts/lora": "^0.4.2",
    "@expo-google-fonts/manrope": "^0.4.2",
    "@expo-google-fonts/outfit": "^0.4.3",
    "@expo-google-fonts/playfair-display": "^0.4.2",
    "@expo-google-fonts/plus-jakarta-sans": "^0.4.2",
    "@expo-google-fonts/righteous": "^0.4.1",
    "@expo-google-fonts/sora": "^0.4.2",
    "@expo-google-fonts/space-grotesk": "^0.4.1",
    "@expo-google-fonts/spectral": "^0.4.1",
    "@expo-google-fonts/unbounded": "^0.4.1",
    "@expo/ngrok": "^4.1.3",
    "@expo/vector-icons": "^15.0.3",
    "@gorhom/bottom-sheet": "^5.2.8",
    "@react-native-async-storage/async-storage": "^2.2.0",
    "@react-native-firebase/analytics": "^23.8.5",
    "@react-native-firebase/app": "^23.8.5",
    "@react-native-masked-view/masked-view": "^0.3.2",
    "@supabase/supabase-js": "^2.91.0",
    "expo": "~54.0.33",
    "expo-application": "^7.0.8",
    "expo-blur": "~15.0.8",
    "expo-build-properties": "~1.0.10",
    "expo-clipboard": "~8.0.8",
    "expo-constants": "~18.0.13",
    "expo-device": "~8.0.10",
    "expo-font": "^14.0.11",
    "expo-glass-effect": "~0.1.9",
    "expo-haptics": "~15.0.8",
    "expo-linear-gradient": "~15.0.8",
    "expo-linking": "~8.0.11",
    "expo-network": "~8.0.8",
    "expo-notifications": "~0.32.16",
    "expo-router": "~6.0.23",
    "expo-splash-screen": "^31.0.13",
    "expo-status-bar": "~3.0.9",
    "expo-store-review": "~9.0.9",
    "expo-tracking-transparency": "~6.0.8",
    "lucide-react-native": "^0.562.0",
    "nativewind": "^4.2.1",
    "react": "19.1.0",
    "react-native": "0.81.5",
    "react-native-context-menu-view": "^1.21.0",
    "react-native-gesture-handler": "~2.28.0",
    "react-native-google-mobile-ads": "^16.3.3",
    "react-native-reanimated": "~4.1.1",
    "react-native-safe-area-context": "~5.6.0",
    "react-native-screens": "~4.16.0",
    "react-native-svg": "^15.12.1",
    "react-native-webview": "^13.15.0",
    "react-native-worklets": "^0.5.1",
    "react-native-worklets-core": "^1.6.2",
    "tailwindcss": "^3.3.2",
    "zod": "^4.4.3",
    "zustand": "^5.0.10"
  },
  "devDependencies": {
    "@types/jest": "^29.5.14",
    "@types/react": "~19.1.0",
    "babel-plugin-module-resolver": "^5.0.2",
    "babel-preset-expo": "^54.0.10",
    "eslint": "^9.0.0",
    "eslint-config-expo": "~10.0.0",
    "jest": "^29.7.0",
    "jest-expo": "~54.0.17",
    "sharp": "^0.34.5",
    "typescript": "~5.9.2"
  },
  "private": true
}

app.json

{
  "expo": {
    "name": "Noctua",
    "slug": "noctua",
    "version": "1.1.2",
    "orientation": "portrait",
    "userInterfaceStyle": "dark",
    "newArchEnabled": true,
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.noctuaapp.ios",
      "infoPlist": {
        "ITSAppUsesNonExemptEncryption": false,
        "UIViewControllerBasedStatusBarAppearance": false
      }
    },
    "plugins": [
      "expo-router",
      ["expo-notifications", { "sounds": [] }],
      ["expo-build-properties", {
        "ios": { "useFrameworks": "static", "buildReactNativeFromSource": true }
      }],
      ["expo-tracking-transparency", {
        "userTrackingPermission": "..."
      }],
      ["react-native-google-mobile-ads", {
        "androidAppId": "ca-app-pub-2493346823798924~4168194614",
        "iosAppId": "ca-app-pub-2493346823798924~4714590145",
        "skAdNetworkItems": ["... 47 standard AdMob SKAdNetwork IDs, omitted ..."]
      }],
      "@react-native-firebase/app",
      "./plugins/withFirebaseDebug.js",
      "./plugins/withNavigationBarFix.js",
      "./plugins/withGoogleMobileAdsSdkVersion.js"
    ]
  }
}

ios/Podfile

# Expo-generated Podfile. Relevant lines:
$RNGoogleMobileAdsSDKVersion = '13.5.0'   # pinned via our config plugin (tested 13.4.0 & 13.5.0)
platform :ios, '15.1'
use_expo_modules!
use_frameworks! :linkage => :static       # from expo-build-properties

android/build.gradle

N/A — iOS-only issue (Android is generated by Expo prebuild and unaffected)

android/app/build.gradle

N/A — iOS-only issue (Android is generated by Expo prebuild and unaffected)

android/settings.gradle

N/A — iOS-only issue (Android is generated by Expo prebuild and unaffected)

AndroidManifest.xml

N/A — iOS-only issue (Android is generated by Expo prebuild and unaffected)

コントリビューターガイド