Skip to content

Repository files navigation

GMA React Native WebView Example

A beginner-friendly React Native example showing how to connect web ads inside an Android WebView or iOS WKWebView to the Google Mobile Ads SDK.

The app contains a safe-area-aware launcher with three cards:

Card URL Purpose
Google WebView Ads Test https://google.github.io/webview-ads/test/ Validate WebView settings, GMA registration, media, cookies, and click behavior
Gamezop Portal https://peslsv.play.gamezop.com Open the configured Gamezop games portal
Random Game https://www.gamezop.com/g/random Resolve and launch an individual random game

This is the React Native companion to:

Read this first: what is and is not officially supported

Google provides official Google Mobile Ads SDKs for Android and iOS. Google also documents MobileAds.registerWebView(...) on Android and MobileAds.shared.register(...) on iOS.

Google does not currently provide an official React Native plugin or a JavaScript method that registers a React Native WebView.

That distinction matters because Google's API requires the real native object:

React Native JavaScript ref
        ↓ cannot be passed directly to GMA
android.webkit.WebView / WKWebView
        ↓
Google Mobile Ads registerWebView API

Calling a JavaScript initialization method is not enough. The exact native WebView that renders the monetized page must be registered.

This project solves that missing layer with a small custom native component:

  • Kotlin creates and registers the Android WebView.
  • Swift creates and registers the iOS WKWebView.
  • TypeScript renders the component and handles shared UI state.

The native component is application code, not an official Google React Native integration. The Google Mobile Ads binaries underneath it are the official Google SDKs.

What this sample intentionally does

  • Initializes the native Google Mobile Ads SDK.
  • Creates an ad-optimized native WebView.
  • Registers every WebView instance before its first URL load.
  • Enables JavaScript, DOM storage, cookies, and inline media as appropriate.
  • Keeps approved Gamezop and Google test pages embedded.
  • Allows all subframe navigation, including about:blank and about:srcdoc.
  • Opens off-domain web click-outs without destroying the running game.
  • Handles target="_blank" and JavaScript window.open(...).
  • Shows an iOS Simulator warning and a separate Android emulator warning.
  • Supports React Native's New Architecture compatibility layer.

It does not display React Native banner, rewarded, or interstitial ads, and it does not include strict-mode or partner-security simulation.

Official references

Run this sample

1. Install the tools

You need:

  • Node.js 22.11 or newer
  • npm
  • React Native development prerequisites
  • Android Studio, Android SDK, and a Java 17+ JDK
  • Xcode 16+ and CocoaPods for iOS

Check the environment:

npx react-native doctor

If java -version reports Java 11 on macOS, use Android Studio's JDK for the current terminal:

export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"

2. Install JavaScript and iOS dependencies

From the project root:

npm install
cd ios
pod install
cd ..

Always open the generated .xcworkspace, not the .xcodeproj, when working in Xcode:

open ios/GMAReactNativeWebViewExample.xcworkspace

3. Start Metro

Keep this command running in its own terminal:

npm start

4. Run Android

Start an Android emulator from Android Studio's Device Manager, or connect a physical device with USB debugging enabled.

Confirm that React Native can see it:

adb devices

Run the app:

npm run android

Use a Play Store-enabled emulator or a physical device when testing Google Play redirects. An emulator without Play Store support might not have an activity that understands market:// URLs.

5. Run iOS

Run the default simulator:

npm run ios

Choose a specific simulator:

npx react-native run-ios --simulator "iPhone 17"

App Store redirects cannot be fully tested in the iOS Simulator. Use a physical iPhone or iPad for that part of Google's click test.

How the integration works

The order is deliberate:

  1. React Native asks for a GmaWebView.
  2. Native code constructs the platform WebView.
  3. Native code applies ad-friendly settings.
  4. Native code initializes the Google Mobile Ads SDK once.
  5. Native code registers that exact WebView instance.
  6. Only after registration completes does native code load sourceUrl.
  7. Progress, error, and back-history events return to TypeScript.

Loading the URL before step 5 can cause the first page's supported ad tags to miss the native SDK connection.

Project map

Shared React Native code

Android native code

iOS native code

Add this to an existing React Native app

The following section assumes a bare React Native Community CLI application. Expo Go cannot load custom Kotlin or Swift code. An Expo project must use a development build/prebuild workflow before following the native steps.

Step 1: Add the JavaScript support packages

npm install react-native-safe-area-context react-native-device-info

react-native-safe-area-context keeps the launcher and WebView clear of the notch and system bars. react-native-device-info is only used to show the iOS Simulator warning; omit it if that warning is unnecessary.

Step 2: Copy the shared TypeScript files

Copy these files into your app:

src/native/GmaWebView.tsx
src/GmaWebViewScreen.tsx
src/navigationPolicy.ts

Copy src/destinations.ts and src/HomeScreen.tsx if you also want this sample's three-card launcher.

The important JavaScript declaration is:

export const GmaWebView =
  requireNativeComponent<GmaWebViewProps>('GmaWebView');

The string GmaWebView must exactly match the name exported by Android and iOS.

Render it with a network URL:

<GmaWebView
  style={{flex: 1}}
  sourceUrl="https://google.github.io/webview-ads/test/"
  reloadToken={0}
  goBackToken={0}
/>

Do not replace the network URL with injected HTML when monetization matters. Google recommends loading network content directly so cookies and page URLs work as expected.

Step 3: Add the Android SDK dependencies

Open your app module's Gradle file, normally android/app/build.gradle, and add these lines inside dependencies:

dependencies {
    implementation("com.google.android.gms:play-services-ads:24.8.0")
    implementation("androidx.browser:browser:1.9.0")
}

This sample pins GMA 24.8.0 because React Native 0.86 uses a Kotlin 2.1 compiler. GMA 25.4.0 currently contains Kotlin 2.3 metadata and fails to compile in that combination. Check compatibility before changing the version; do not blindly replace it with the newest GMA release.

The browser dependency provides Android Custom Tabs for off-domain HTTPS click-outs.

Step 4: Add the Android manifest configuration

Open android/app/src/main/AndroidManifest.xml.

Ensure internet permission exists directly under <manifest>:

<uses-permission android:name="android.permission.INTERNET" />

Add the integration-manager entry inside <application>:

<meta-data
    android:name="com.google.android.gms.ads.INTEGRATION_MANAGER"
    android:value="webview" />

This tells GMA that the SDK is used only for WebView APIs and bypasses the normal native-ad application-ID check. Without this entry, GMA can throw an IllegalStateException during startup.

If your app also displays native banner, interstitial, rewarded, or app-open ads, follow Google's quick start and configure the real GMA application ID instead of assuming this WebView-only bypass covers those formats.

Step 5: Copy the Android native files

Find your Android package directory:

android/app/src/main/java/com/yourcompany/yourapp/

Copy these four files into it:

GmaWebView.kt
GmaWebViewManager.kt
GmaWebViewEvent.kt
GmaWebViewPackage.kt

Change the first line of every copied file from:

package com.gamezop.gmareactnativewebviewexample

to your application's package, for example:

package com.yourcompany.yourapp

If the package declarations do not match the directory/application package, Android compilation will fail or GmaWebViewPackage will not resolve.

Step 6: Register the Android package

Open MainApplication.kt. In the PackageList(...).packages.apply block, add:

add(GmaWebViewPackage())

It should resemble:

PackageList(this).packages.apply {
  add(GmaWebViewPackage())
}

This manual step is required because these Kotlin files belong to the app rather than an autolinked npm package.

Step 7: Understand the Android registration point

The crucial code is inside GmaWebView.init:

MobileAds.initialize(context.applicationContext) {
  post {
    MobileAds.registerWebView(this)
    isGmaReady = true
    loadPendingSource()
  }
}

sourceUrl is stored while initialization is pending. loadPendingSource() does nothing until isGmaReady becomes true. Keep that guard if you adapt the component.

Step 8: Add the iOS SDK

Open ios/Podfile and add the Google SDK inside your app target:

target 'YourApp' do
  config = use_native_modules!

  pod 'Google-Mobile-Ads-SDK', '13.7.0'

  # existing React Native configuration...
end

Install it:

cd ios
pod install --repo-update
cd ..

Use --repo-update when CocoaPods says it cannot find the requested SDK version.

Step 9: Add the iOS plist configuration

Open the application Info.plist and add:

<key>GADIntegrationManager</key>
<string>webview</string>

This is the iOS equivalent of Android's WebView-only integration-manager metadata. Without it, GMA can raise GADInvalidInitializationException when no normal GMA application identifier is configured.

For production advertising, also copy Google's current SKAdNetworkItems list into Info.plist from the official iOS quick start. Google updates that list over time, so this sample deliberately does not freeze a potentially stale copy in source control. Missing entries do not prevent this WebView example from launching, but they can reduce attribution coverage.

Step 10: Copy and add the iOS native files

Copy:

GmaWebViewManager.swift
GmaWebViewManagerBridge.m

into your iOS application source directory.

Then add both files to Xcode:

  1. Open your .xcworkspace.
  2. Right-click the application group in the Project Navigator.
  3. Choose Add Files to "YourApp".
  4. Select both copied files.
  5. Ensure the application target is checked under Add to targets.
  6. Build once from Xcode.

Copying files into the folder without adding them to the Xcode target is not enough. If the target membership is missing, JavaScript reports that GmaWebView is unavailable.

The Objective-C .m bridge file is required even though the implementation is Swift. It exports sourceUrl, command tokens, and events to React Native.

Step 11: Understand the iOS registration point

GmaWebViewRegistration starts the SDK once and queues each view:

MobileAds.shared.start { _ in
  // On the main actor:
  MobileAds.shared.register(webView)
  completion()
}

Only the completion sets isGmaReady and consumes the pending URL. Do not move webView.load(...) ahead of registration.

Step 12: Rebuild native applications

Metro hot reload cannot install new native code. After adding Kotlin, Swift, Gradle, Pod, or plist changes, rebuild:

npm run android

and:

cd ios
pod install
cd ..
npm run ios

WebView settings used by this sample

Android

  • JavaScript enabled
  • DOM storage enabled
  • First-party cookies enabled
  • Third-party cookies enabled
  • Automatic media playback enabled
  • Multiple windows enabled for _blank/window.open
  • WebView debugging enabled in debug builds

iOS

  • Persistent website storage
  • Inline media playback enabled
  • Automatic media playback enabled
  • JavaScript window opening enabled
  • Back/forward gestures enabled

Third-party cookies are not expected to pass Google's test on iOS due to platform behavior.

Navigation and security policy

Top-level HTTPS navigation remains embedded for:

  • google.github.io
  • gamezop.com
  • Any host ending in .gamezop.com

The subdomain rule matters because /g/random can redirect to a game-specific Gamezop host.

The allowlist is only applied to the top-level page. Subframes are allowed without host filtering because games, ads, analytics, and game engines may use:

  • Additional HTTPS origins
  • about:blank
  • about:srcdoc
  • blob: URLs
  • data: URLs

Applying the top-level HTTPS allowlist to every iframe is a common reason games stop during initialization with about:blank, about:srcdoc, or a disallowedScheme error.

Off-domain HTTPS click-outs open using:

  • SFSafariViewController on iOS
  • Android Custom Tabs on Android

App Store, Play Store, and custom schemes are offered to the operating system. The original WebView stays alive so returning to the app preserves game state.

Validate the integration

Open Google WebView Ads Test and check:

  • JavaScript enabled
  • First-party cookies work
  • Third-party cookies work on Android
  • Video plays inline
  • Video starts automatically
  • Video can replay
  • WebView connected to the Google Mobile Ads SDK
  • Google Publisher Tag connected to GMA
  • target="_top" href opens correctly
  • target="_blank" href opens correctly
  • JavaScript window.open("_blank") opens correctly
  • Returning from a click-out preserves the page counter/state
  • Store links open the correct store application

The market:// test only applies to Android. App Store links require a physical iOS device.

For network verification, inspect an ad request and confirm it includes the GMA app-signal parameter described by Google's WebView documentation.

Troubleshooting

requireNativeComponent: "GmaWebView" was not found

  • Rebuild the app; Metro reload is insufficient.
  • Android: confirm add(GmaWebViewPackage()) exists.
  • Android: confirm all Kotlin package declarations match your app.
  • iOS: confirm both native files belong to the application target.
  • iOS: open the .xcworkspace, not .xcodeproj.

Android throws an application-ID exception

Confirm this is inside <application>:

<meta-data
    android:name="com.google.android.gms.ads.INTEGRATION_MANAGER"
    android:value="webview" />

iOS throws GADInvalidInitializationException

Confirm Info.plist contains:

<key>GADIntegrationManager</key>
<string>webview</string>

GMA 25.x reports incompatible Kotlin metadata

React Native 0.86 currently compiles with Kotlin 2.1 while GMA 25.4.0 publishes Kotlin 2.3 metadata. Keep play-services-ads:24.8.0, or upgrade only after your React Native/Kotlin toolchain supports the metadata version used by GMA.

Android build says Java 17 or newer is required

On macOS:

export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
java -version

Then rerun the build from the same terminal.

Google's GMA connection test stays red

  • Confirm registration happens before loadUrl/load.
  • Confirm the Google SDK dependency is present in the native target.
  • Confirm the integration-manager metadata is present.
  • Use the exact Google test URL before testing your own site.
  • Verify the page uses GPT, AdSense, or IMA for HTML5; other ad tags do not use this API.
  • Allow a few seconds for native SDK initialization on a fresh emulator. The sample intentionally keeps the loader visible instead of loading too early.

iOS logs warnings about missing SKAdNetwork identifiers

Add the current SKAdNetworkItems array from Google's iOS quick start before releasing a production app. The list changes independently of this sample, so it is linked rather than duplicated here.

_blank or window.open does nothing

Android requires multiple-window support and WebChromeClient.onCreateWindow. iOS requires both WKUIDelegate and WKNavigationDelegate. Copy the complete native view implementation rather than only the registration line.

Games stop on about:blank or about:srcdoc

Do not apply a top-level scheme/host allowlist to iframe requests. This sample returns early for subframes and permits browser-internal document schemes.

Android store link fails on an emulator

Use an AVD image with the Play Store badge or test on a physical device. A plain AOSP emulator may not include an application capable of opening market://.

iOS App Store link fails in the Simulator

That is an iOS Simulator limitation. Test store redirects on a physical device.

react-native-google-mobile-ads versus this sample

react-native-google-mobile-ads is a community-maintained wrapper for native banner, interstitial, rewarded, app-open, and native ad formats. It links the official native Google SDKs.

At the time of writing, it does not expose a JavaScript API that accepts and registers the underlying android.webkit.WebView or WKWebView. Adding that package and calling its initialization method does not by itself connect web ad tags inside a React Native WebView.

You may use that package alongside this component if your app also displays native ad formats. Coordinate SDK versions and initialization in that case so the same native GMA SDK is not declared with conflicting versions.

Build and test commands used for this repository

npm run lint
npm test -- --runInBand

export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
cd android
./gradlew app:assembleDebug -PreactNativeArchitectures=arm64-v8a
cd ..

xcodebuild \
  -workspace ios/GMAReactNativeWebViewExample.xcworkspace \
  -scheme GMAReactNativeWebViewExample \
  -sdk iphonesimulator \
  -destination "platform=iOS Simulator,name=iPhone 17" \
  -configuration Debug \
  CODE_SIGNING_ALLOWED=NO \
  build

The Android debug APK is generated at:

android/app/build/outputs/apk/debug/app-debug.apk

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages