invertase/react-native-google-mobile-ads

Native ads not loading on certain Android devices

Geschlossen

#852 geöffnet am 07.05.2026

 (7 Kommentare) (0 Reaktionen) (0 zugewiesene Personen)TypeScript (213 Forks)github user discovery
help wantedstale

Repository-Metriken

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

Beschreibung

What happened?

Native ads load correctly when I use TestIds.NATIVE. With my real AdMob Native Advanced ad unit, ads do not show on an Android 13 device, but the same real ad unit works on Android 15.

From logcat, I consistently see:

Ads I Ad failed to load : 3

import React, { useEffect, useRef, useState } from 'react'; import { Text, StyleSheet, Image, Platform, View } from 'react-native'; import { useSelector } from 'react-redux'; import { NativeAd, NativeAdView, NativeAsset, NativeAssetType, NativeMediaView, TestIds, } from 'react-native-google-mobile-ads';

const adUnitId = DEV ? TestIds.NATIVE : Platform.OS === 'ios' ? 'ca-app-pub-9xxx' : 'ca-app-pub-9xxx';

const AD_LOAD_TIMEOUT_MS = 12000; const MAX_AD_LOAD_ATTEMPTS = 2;

const wait = (delay: number) => new Promise(resolve => { setTimeout(resolve, delay); });

const createNativeAdWithTimeout = async () => { let timeoutId: ReturnType | null = null; let timedOut = false;

try { const requestPromise = NativeAd.createForAdRequest(adUnitId) .then(ad => { if (timedOut) { ad.destroy(); return null; }

    return ad;
  })
  .catch(error => {
    if (timedOut) {
      console.log('Native ad failed after timeout', {
        adUnitId,
        isDevMode: __DEV__,
        errorCode: error?.code ?? error?.errorCode,
        errorMessage: error?.message ?? error?.nativeErrorMessage,
      });
      return null;
    }

    throw error;
  });

return await Promise.race([
  requestPromise,
  new Promise<null>(resolve => {
    timeoutId = setTimeout(() => {
      timedOut = true;
      console.log('Native ad timed out', { adUnitId, isDevMode: __DEV__ });
      resolve(null);
    }, AD_LOAD_TIMEOUT_MS);
  }),
]);

} finally { if (timeoutId) { clearTimeout(timeoutId); } } };

const NativeAdComponent = () => { const userData = useSelector((state: any) => state.userData?.userData); const hasSubscribed = Boolean(userData?.hasSubscribed); const [nativeAd, setNativeAd] = useState<NativeAd | null>(null); const [loading, setLoading] = useState(true); const activeAdRef = useRef<NativeAd | null>(null);

useEffect(() => { let isMounted = true;

const loadAd = async () => {
  setLoading(true);

  if (hasSubscribed) {
    activeAdRef.current?.destroy();
    activeAdRef.current = null;
    setNativeAd(null);
    setLoading(false);
    return;
  }

  for (let attempt = 1; attempt <= MAX_AD_LOAD_ATTEMPTS; attempt += 1) {
    try {
      const ad = await createNativeAdWithTimeout();

      if (!isMounted) {
        ad?.destroy();
        return;
      }

      if (ad) {
        console.log('Native ad loaded', {
          platform: Platform.OS,
          adUnitId,
          attempt,
        });

        if (activeAdRef.current && activeAdRef.current !== ad) {
          activeAdRef.current.destroy();
        }
        activeAdRef.current = ad;
        setNativeAd(ad);
        setLoading(false);
        return;
      }

      console.log('Native ad request returned no ad', {
        platform: Platform.OS,
        adUnitId,
        attempt,
      });
    } catch (e: any) {
      console.log('Native Ad attempt failed', {
        platform: Platform.OS,
        adUnitId,
        attempt,
        errorCode: e?.code ?? e?.errorCode,
        errorMessage: e?.message ?? e?.nativeErrorMessage,
      });
    }

    if (attempt < MAX_AD_LOAD_ATTEMPTS) {
      await wait(1500 * attempt);
    }
  }

  if (isMounted) {
    setLoading(false);
  }
};

loadAd();

return () => {
  isMounted = false;
  activeAdRef.current?.destroy();
  activeAdRef.current = null;
};

}, [hasSubscribed]);

if (hasSubscribed) { return null; }

if (loading || !nativeAd) { return null; }

return ( {nativeAd.icon && ( <Image source={{ uri: nativeAd.icon.url }} style={styles.icon} /> )} {nativeAd.headline} Sponsored {nativeAd.body && {nativeAd.body}} {nativeAd.callToAction && ( {nativeAd.callToAction} )} ); };

const styles = StyleSheet.create({ container: { backgroundColor: '#FFFFFF', borderRadius: 8, padding: 12, width: '100%', minHeight: 300, alignSelf: 'center', borderBottomColor: '#E5E5E5', borderBottomWidth: 1, overflow: 'hidden', }, sponsored: { fontSize: 12, color: '#888', marginBottom: 6, }, header: { flexDirection: 'row', alignItems: 'center', marginBottom: 8, }, headerText: { flex: 1, }, icon: { width: 40, height: 40, borderRadius: 8, marginRight: 10, }, headline: { fontSize: 16, fontWeight: '600', flex: 1, }, media: { width: '100%', height: 180, borderRadius: 10, marginVertical: 8, }, body: { fontSize: 14, color: '#444', marginVertical: 6, }, cta: { alignSelf: 'flex-start', paddingHorizontal: 14, paddingVertical: 8, borderRadius: 6, fontWeight: '600', marginTop: 8, }, });

export default NativeAdComponent;

Platforms

Only on Android

React Native Info

ystem:
  OS: macOS 26.4.1
  CPU: (8) arm64 Apple M2
  Memory: 138.89 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 20.19.4
    path: /Users/mohit/.nvm/versions/node/v20.19.4/bin/node
  Yarn:
    version: 1.22.19
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.8.2
    path: /Users/mohit/.nvm/versions/node/v20.19.4/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /Users/mohit/.gem/ruby/3.2.2/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.4
      - iOS 26.4
      - macOS 26.4
      - tvOS 26.4
      - visionOS 26.4
      - watchOS 26.4
  Android SDK:
    API Levels:
      - "29"
      - "30"
      - "31"
      - "33"
      - "34"
      - "35"
      - "35"
      - "36"
    Build Tools:
      - 30.0.2
      - 30.0.3
      - 31.0.0
      - 33.0.0
      - 33.0.1
      - 33.0.2
      - 34.0.0
      - 35.0.0
      - 36.0.0
      - 36.0.0
    System Images:
      - android-33 | Google TV Intel x86 Atom
      - android-33 | Google APIs ARM 64 v8a
      - android-34 | Google TV ARM 64 v8a
      - android-35 | Google Play ARM 64 v8a
      - android-36 | Google Play ARM 64 v8a
      - android-VanillaIceCream | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2025.2 AI-252.27397.103.2522.14617522
  Xcode:
    version: 26.4.1/17E202
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.17
    path: /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home/bin/javac
  Ruby:
    version: 3.2.2
    path: /Users/mohit/.rubies/ruby-3.2.2/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 20.0.0
    wanted: 20.0.0
  react:
    installed: 19.2.0
    wanted: 19.2.0
  react-native:
    installed: 0.83.1
    wanted: ^0.83.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Are your using Typescript?

  • My project is using Typescript

package.json

{
  "name": "GoalPost",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest",
    "postinstall": "patch-package"
  },
  "dependencies": {
    "@codler/react-native-keyboard-aware-scroll-view": "^2.0.1",
    "@fawazahmed/react-native-read-more": "^3.0.4",
    "@gorhom/bottom-sheet": "^5",
    "@react-native-async-storage/async-storage": "^2.2.0",
    "@react-native-firebase/app": "^23.8.3",
    "@react-native-firebase/messaging": "^23.8.3",
    "@react-native/new-app-screen": "0.83.0",
    "@react-navigation/bottom-tabs": "^7.10.0",
    "@react-navigation/elements": "^2.9.5",
    "@react-navigation/native": "^7.1.28",
    "@react-navigation/native-stack": "^7.10.0",
    "@reduxjs/toolkit": "^2.11.2",
    "@types/react-native-read-more-text": "^1.0.4",
    "link-preview-js": "^4.0.0",
    "moment": "^2.30.1",
    "patch-package": "^8.0.1",
    "postinstall-postinstall": "^2.1.0",
    "react": "19.2.0",
    "react-native": "^0.83.1",
    "react-native-actions-sheet": "^10.1.1",
    "react-native-background-timer": "^2.4.1",
    "react-native-calendars": "^1.1313.0",
    "react-native-controlled-mentions": "^3.1.0",
    "react-native-date-picker": "^5.0.13",
    "react-native-element-dropdown": "^2.12.4",
    "react-native-fast-image": "^8.6.3",
    "react-native-football-formation": "^1.0.11",
    "react-native-football-lineup": "^0.0.3",
    "react-native-gesture-handler": "^2.28.0",
    "react-native-get-random-values": "^2.0.0",
    "react-native-google-mobile-ads": "^16.3.3",
    "react-native-google-places-autocomplete": "^2.6.4",
    "react-native-hyperlink": "^0.1.2",
    "react-native-iap": "^13.0.4",
    "react-native-image-crop-picker": "^0.51.1",
    "react-native-linear-gradient": "^2.8.3",
    "react-native-otp-textinput": "^1.1.7",
    "react-native-pager-view": "^8.0.0",
    "react-native-parsed-text": "^0.0.22",
    "react-native-permissions": "^5.4.4",
    "react-native-phone-number-input": "^2.1.0",
    "react-native-reanimated": "^4.2.1",
    "react-native-reanimated-carousel": "^4.0.3",
    "react-native-safe-area-context": "^5.6.2",
    "react-native-screens": "^4.19.0",
    "react-native-see-more-inline": "^1.3.0",
    "react-native-svg": "^15.15.1",
    "react-native-toast-notifications": "^3.4.0",
    "react-native-webview": "^13.16.0",
    "react-native-worklets": "^0.7.2",
    "react-redux": "^9.2.0",
    "redux": "^5.0.1",
    "redux-persist": "^6.0.0",
    "redux-saga": "^1.4.2",
    "socket.io-client": "^4.8.3"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/runtime": "^7.25.0",
    "@react-native-community/cli": "20.0.0",
    "@react-native-community/cli-platform-android": "20.0.0",
    "@react-native-community/cli-platform-ios": "20.0.0",
    "@react-native/babel-preset": "0.83.0",
    "@react-native/eslint-config": "0.83.0",
    "@react-native/metro-config": "0.83.0",
    "@react-native/typescript-config": "0.83.0",
    "@types/jest": "^29.5.13",
    "@types/react": "^19.2.0",
    "@types/react-test-renderer": "^19.1.0",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-native-svg-transformer": "^1.5.2",
    "react-test-renderer": "19.2.0",
    "typescript": "^5.8.3"
  },
  "engines": {
    "node": ">=20"
  }
}

app.json

{
  "name": "GoalPost",
  "displayName": "GoalPost",
   "react-native-google-mobile-ads": {  
    "ios_app_id":"ca-app-pub-9639796024445418~2891414222",  
    "android_app_id": "ca-app-pub-9639796024445418~6954820301",
    "delay_app_measurement_init": false,
    "optimize_initialization": true,
    "optimize_ad_loading": true,
    "sk_ad_network_items": [
      "cstr6suwn9.skadnetwork",
      "4fzdc2evr5.skadnetwork",
      "2fnua5tdw4.skadnetwork",
      "ydx93a7ass.skadnetwork",
      "p78axxw29g.skadnetwork",
      "v72qych5uu.skadnetwork",
      "ludvb6z3bs.skadnetwork",
      "cp8zw746q7.skadnetwork",
      "3sh42y64q3.skadnetwork",
      "c6k4g5qg8m.skadnetwork",
      "s39g8k73mm.skadnetwork",
      "3qy4746246.skadnetwork",
      "f38h382jlk.skadnetwork",
      "hs6bdukanm.skadnetwork",
      "mlmmfzh3r3.skadnetwork",
      "v4nxqhlyqp.skadnetwork",
      "wzmmz9fp6w.skadnetwork",
      "su67r6k2v3.skadnetwork",
      "yclnxrl5pm.skadnetwork",
      "t38b2kh725.skadnetwork",
      "7ug5zh24hu.skadnetwork",
      "gta9lk7p23.skadnetwork",
      "vutu7akeur.skadnetwork",
      "y5ghdn5j9k.skadnetwork",
      "v9wttpbfk9.skadnetwork",
      "n38lu8286q.skadnetwork",
      "47vhws6wlr.skadnetwork",
      "kbd757ywx3.skadnetwork",
      "9t245vhmpl.skadnetwork",
      "a2p9lx4jpn.skadnetwork",
      "22mmun2rn5.skadnetwork",
      "44jx6755aq.skadnetwork",
      "k674qkevps.skadnetwork",
      "4468km3ulz.skadnetwork",
      "2u9pt9hc89.skadnetwork",
      "8s468mfl3y.skadnetwork",
      "klf5c3l5u5.skadnetwork",
      "ppxm28t8ap.skadnetwork",
      "kbmxgpxpgc.skadnetwork",
      "uw77j35x4d.skadnetwork",
      "578prtvx9j.skadnetwork",
      "4dzt52r2t5.skadnetwork",
      "tl55sbb4fm.skadnetwork",
      "c3frkrj4fj.skadnetwork",
      "e5fvkxwrpn.skadnetwork",
      "8c4e2ghe7u.skadnetwork",
      "3rd42ekr43.skadnetwork",
      "97r2b46745.skadnetwork",
      "3qcr597p9d.skadnetwork"
    ]
  }
}

ios/Podfile

# Resolve react_native_pods.rb with node to allow for hoisting
# require Pod::Executable.execute_command('node', ['-p',
#   'require.resolve(
#     "react-native/scripts/react_native_pods.rb",
#     {paths: [process.argv[1]]},
#   )', __dir__]).strip

def node_require(script)
     # Resolve script with node to allow for hoisting
      require Pod::Executable.execute_command('node', ['-p',
       "require.resolve(
       '#{script}',
       {paths: [process.argv[1]]},
   )", __dir__]).strip
  end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')

platform :ios, min_ios_version_supported 
prepare_react_native_project!

# linkage = ENV['USE_FRAMEWORKS']
# if linkage != nil
#   Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
#   use_frameworks! :linkage => linkage.to_sym
# end

use_frameworks! :linkage => :static
setup_permissions([
    'LocationAlways',
    'LocationWhenInUse',
    'Camera',
    'PhotoLibrary',
])

target 'GoalPost' do
  config = use_native_modules!
  pod 'GoogleUtilities', :modular_headers => true

  use_react_native!(
    :path => config[:reactNativePath],
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  post_install do |installer|
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false,
      # :ccache_enabled => true
    )
    # Fix Xcode 16 / fmt compile error
    installer.pods_project.targets.each do |target|
      if target.name == 'fmt'
        target.build_configurations.each do |config|
          config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
        end
      end
    end
  end
end

android/build.gradle

buildscript {
    ext {
        buildToolsVersion = "36.0.0"
        minSdkVersion = 24
        compileSdkVersion = 36
        targetSdkVersion = 36
        ndkVersion = "27.1.12297006"
        kotlinVersion = "2.1.20"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle")
        classpath("com.facebook.react:react-native-gradle-plugin")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
         classpath 'com.google.gms:google-services:4.4.4'
    }
}

apply plugin: "com.facebook.react.rootproject"

android/app/build.gradle

apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
 apply plugin: 'com.google.gms.google-services'
 
    autolinkLibrariesWithApp()
}


def enableProguardInReleaseBuilds = false


def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'

android {
    ndkVersion rootProject.ext.ndkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    compileSdk rootProject.ext.compileSdkVersion

    namespace "com.football.goalpost"
    defaultConfig {
        applicationId "com.football.goalpost"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 7
        versionName "1.0"
        missingDimensionStrategy 'store', 'play'
        

    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
}

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")
//    implementation project(path: ':react-native-iap')
    implementation 'com.facebook.fresco:animated-gif:3.6.0'
    implementation project(':react-native-fast-image')
    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

android/settings.gradle

pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'GoalPost'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme"
      android:usesCleartextTraffic="${usesCleartextTraffic}"
      android:supportsRtl="true">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:screenOrientation="portrait"
        android:exported="true">
        <intent-filter>

            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        
      </activity>
    </application>
</manifest>

Contributor Guide