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 geöffnet am 10. Juni 2026

Auf GitHub ansehen
 (1 Kommentar) (1 Reaktion) (0 zugewiesene Personen)TypeScript (213 Forks)github user discovery
help wantedstale

Repository-Metriken

Stars
 (1.010 Stars)
PR-Merge-Metriken
 (PR-Metriken ausstehend)

Beschreibung

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)

Contributor Guide