Skip to content

Expose a way to register native WebView instances with Google Mobile Ads SDK WebView API for Ads #3960

Open

Description

@saif71

Google requires apps that monetize AdSense or Google Ad Manager display ads inside a WebView to implement the WebView API for Ads.

This requires calling a native Google Mobile Ads SDK method with the actual native WebView instance:

  • Android: MobileAds.registerWebView(webView)
  • iOS: MobileAds.shared.register(webView) / GADMobileAds.sharedInstance().register(webView)

Currently, react-native-webview does not appear to expose a way for React Native apps to access or register the underlying native WebView / WKWebView instance with the Google Mobile Ads SDK.

This creates a compliance issue for apps that use react-native-webview to display owned web content that includes AdSense or Google Ad Manager ads.

Google documentation:

Google states that apps monetizing AdSense or Google Ad Manager display ads inside a WebView must implement the WebView API for Ads.

The required integration is native and must be performed on the actual WebView object.

Android example:

MobileAds.registerWebView(webView)

iOS example:

MobileAds.shared.register(webView)

Problem

In React Native apps using react-native-webview, developers usually render WebViews like this:

import WebView from 'react-native-webview';

export function MyScreen() {
  return (
    <WebView source={{ uri: 'https://example.com' }} />
  );
}

However, there is no JS prop or imperative method that allows the app to register the native WebView instance with Google Mobile Ads SDK.

This is especially problematic for Expo apps using development builds / EAS builds, where native code can be included but the WebView is still provided by react-native-webview.

Proposed solution

Add first-class support for registering the native WebView with Google Mobile Ads SDK when requested.

Possible API:

<WebView
  source={{ uri: 'https://example.com' }}
  googleMobileAdsWebViewRegistrationEnabled
/>

When enabled:

Android

Calls:

MobileAds.registerWebView(webView)

after the native WebView is created.

iOS

Calls:

MobileAds.shared.register(webView)

or the appropriate Google Mobile Ads SDK equivalent after the WKWebView is created.

Why this belongs here

The Google API must be called with the actual native WebView object.

Because react-native-webview owns creation of the native WebView / WKWebView, this library is in the best position to expose a safe and stable way to perform that registration.

Activity

  1. TOPans commented on Jul 2, 2026

    @TOPans

    @saif71
    I encountered the same issue, did you find any solution?

  2. saif71 commented on Jul 2, 2026

    @saif71
    Author

    @TOPans No not yet. I'm still trying to figuring it out. Might need to move the whole admob implementation to native SDK, but imho that is not an optimal solution. Two more headache to take care of.

  3. TOPans commented on Jul 6, 2026

    @TOPans

    @saif71
    This is bad news :(
    I'm not an expert in native programming, but with the help of assistants, I came up with a working solution. I'm afraid to use it because of possible problems in a production application. I added this code to the library functions for testing.
    react-native-webview 13.16.0

    Android
    react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt

    fun createViewInstance(context: ThemedReactContext, webView: RNCWebView): RNCWebViewWrapper {

    context.runOnUiQueueThread {
         try {
           val mobileAdsClass = Class.forName("com.google.android.gms.ads.MobileAds")
           val registerMethod = mobileAdsClass.getMethod(
             "registerWebView", 
             android.webkit.WebView::class.java
           )
           registerMethod.invoke(null, webView)
           Log.d("registerWebView", "REGISTERED")
         } catch (e: Exception) {
           e.printStackTrace()
         }
        }

    iOs
    react-native-webview/apple/RNCWebViewImpl.m
    (void)didMoveToWindow
    if (self.window != nil && _webView == nil) {
    WKWebViewConfiguration *wkWebViewConfig = [self setUpWkWebViewConfig];
    _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];

    dispatch_async(dispatch_get_main_queue(), ^{
          if (self->_webView != nil) {
            Class gadMobileAdsClass = NSClassFromString(@"GADMobileAds");
            if (gadMobileAdsClass != nil) {
              id sharedInstance = [gadMobileAdsClass performSelector:NSSelectorFromString(@"sharedInstance")];
              if (sharedInstance != nil && [sharedInstance respondsToSelector:NSSelectorFromString(@"registerWebView:")]) {
                #pragma clang diagnostic push
                #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                [sharedInstance performSelector:NSSelectorFromString(@"registerWebView:") withObject:self->_webView];
                #pragma clang diagnostic pop
              }
            }
          }
        });
  4. ziadsabillah-pelm commented on Jul 8, 2026

    @ziadsabillah-pelm

    +1

  5. davidteejay commented on Aug 26, 2026

    @davidteejay

    Here's a patch you can use for this (for 13.16.1):

    diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
    index f83033b..58ed0e4 100644
    --- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
    +++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
    @@ -711,6 +711,18 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
             CookieManager.getInstance().setAcceptThirdPartyCookies(view, enabled)
         }
    
    +    fun setGoogleMobileAdsWebViewRegistrationEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
    +        if (enabled) {
    +            try {
    +                Class.forName("com.google.android.gms.ads.MobileAds")
    +                    .getMethod("registerWebView", WebView::class.java)
    +                    .invoke(null, viewWrapper.webView)
    +            } catch (exception: ReflectiveOperationException) {
    +                Log.w(TAG, "Unable to register WebView with Google Mobile Ads", exception)
    +            }
    +        }
    +    }
    +
         fun setWebviewDebuggingEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
             RNCWebView.setWebContentsDebuggingEnabled(enabled)
         }
    diff --git a/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    index 4709e28..6625091 100644
    --- a/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    +++ b/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    @@ -326,6 +326,12 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
             mRNCWebViewManagerImpl.setThirdPartyCookiesEnabled(view, value);
         }
    
    +    @Override
    +    @ReactProp(name = "googleMobileAdsWebViewRegistrationEnabled")
    +    public void setGoogleMobileAdsWebViewRegistrationEnabled(RNCWebViewWrapper view, boolean value) {
    +        mRNCWebViewManagerImpl.setGoogleMobileAdsWebViewRegistrationEnabled(view, value);
    +    }
    +
         @Override
         @ReactProp(name = "webviewDebuggingEnabled")
         public void setWebviewDebuggingEnabled(RNCWebViewWrapper view, boolean value) {
    diff --git a/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    index 974337f..3bdcd28 100644
    --- a/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    +++ b/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
    @@ -264,6 +264,11 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper> {
             mRNCWebViewManagerImpl.setThirdPartyCookiesEnabled(view, value);
         }
    
    +    @ReactProp(name = "googleMobileAdsWebViewRegistrationEnabled")
    +    public void setGoogleMobileAdsWebViewRegistrationEnabled(RNCWebViewWrapper view, boolean value) {
    +        mRNCWebViewManagerImpl.setGoogleMobileAdsWebViewRegistrationEnabled(view, value);
    +    }
    +
         @ReactProp(name = "webviewDebuggingEnabled")
         public void setWebviewDebuggingEnabled(RNCWebViewWrapper view, boolean value) {
             mRNCWebViewManagerImpl.setWebviewDebuggingEnabled(view, value);
    diff --git a/node_modules/react-native-webview/apple/RNCWebView.mm b/node_modules/react-native-webview/apple/RNCWebView.mm
    index c0816b6..f94a2e3 100644
    --- a/node_modules/react-native-webview/apple/RNCWebView.mm
    +++ b/node_modules/react-native-webview/apple/RNCWebView.mm
    @@ -300,6 +300,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
         REMAP_WEBVIEW_PROP(allowFileAccessFromFileURLs)
         REMAP_WEBVIEW_PROP(allowUniversalAccessFromFileURLs)
         REMAP_WEBVIEW_PROP(allowsInlineMediaPlayback)
    +    REMAP_WEBVIEW_PROP(googleMobileAdsWebViewRegistrationEnabled)
         REMAP_WEBVIEW_PROP(allowsPictureInPictureMediaPlayback)
         REMAP_WEBVIEW_PROP(webviewDebuggingEnabled)
         REMAP_WEBVIEW_PROP(allowsAirPlayForMediaPlayback)
    diff --git a/node_modules/react-native-webview/apple/RNCWebViewImpl.h b/node_modules/react-native-webview/apple/RNCWebViewImpl.h
    index 1f6bbfd..3bb4fc2 100644
    --- a/node_modules/react-native-webview/apple/RNCWebViewImpl.h
    +++ b/node_modules/react-native-webview/apple/RNCWebViewImpl.h
    @@ -80,6 +80,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
     @property (nonatomic, assign) BOOL pagingEnabled;
     @property (nonatomic, assign) CGFloat decelerationRate;
     @property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
    +@property (nonatomic, assign) BOOL googleMobileAdsWebViewRegistrationEnabled;
     @property (nonatomic, assign) BOOL allowsPictureInPictureMediaPlayback;
     @property (nonatomic, assign) BOOL webviewDebuggingEnabled;
     @property (nonatomic, assign) BOOL allowsAirPlayForMediaPlayback;
    diff --git a/node_modules/react-native-webview/apple/RNCWebViewImpl.m b/node_modules/react-native-webview/apple/RNCWebViewImpl.m
    index 7f5c24d..14f0bd4 100644
    --- a/node_modules/react-native-webview/apple/RNCWebViewImpl.m
    +++ b/node_modules/react-native-webview/apple/RNCWebViewImpl.m
    @@ -10,6 +10,7 @@
     #import <React/RCTAutoInsetsProtocol.h>
     #import "RNCWKProcessPoolManager.h"
     #if !TARGET_OS_OSX
    +#import <GoogleMobileAds/GoogleMobileAds.h>
     #import <UIKit/UIKit.h>
     #else
     #import <React/RCTUIKit.h>
    @@ -512,11 +513,26 @@ - (WKWebViewConfiguration *)setUpWkWebViewConfig
       return wkWebViewConfig;
     }
    
    +- (void)setGoogleMobileAdsWebViewRegistrationEnabled:(BOOL)enabled
    +{
    +  _googleMobileAdsWebViewRegistrationEnabled = enabled;
    +#if !TARGET_OS_OSX
    +  if (enabled && _webView != nil) {
    +    [[GADMobileAds sharedInstance] registerWebView:_webView];
    +  }
    +#endif // !TARGET_OS_OSX
    +}
    +
     - (void)didMoveToWindow
     {
       if (self.window != nil && _webView == nil) {
         WKWebViewConfiguration *wkWebViewConfig = [self setUpWkWebViewConfig];
         _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
    +#if !TARGET_OS_OSX
    +    if (_googleMobileAdsWebViewRegistrationEnabled) {
    +      [[GADMobileAds sharedInstance] registerWebView:_webView];
    +    }
    +#endif // !TARGET_OS_OSX
         [self setBackgroundColor: _savedBackgroundColor];
     #if !TARGET_OS_OSX
         _webView.menuItems = _menuItems;
    diff --git a/node_modules/react-native-webview/apple/RNCWebViewManager.mm b/node_modules/react-native-webview/apple/RNCWebViewManager.mm
    index f8f375f..a59ab69 100644
    --- a/node_modules/react-native-webview/apple/RNCWebViewManager.mm
    +++ b/node_modules/react-native-webview/apple/RNCWebViewManager.mm
    @@ -62,6 +62,7 @@ - (RNCView *)view
     RCT_EXPORT_VIEW_PROPERTY(allowFileAccessFromFileURLs, BOOL)
     RCT_EXPORT_VIEW_PROPERTY(allowUniversalAccessFromFileURLs, BOOL)
     RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
    +RCT_EXPORT_VIEW_PROPERTY(googleMobileAdsWebViewRegistrationEnabled, BOOL)
     RCT_EXPORT_VIEW_PROPERTY(allowsPictureInPictureMediaPlayback, BOOL)
     RCT_EXPORT_VIEW_PROPERTY(webviewDebuggingEnabled, BOOL)
     RCT_EXPORT_VIEW_PROPERTY(allowsAirPlayForMediaPlayback, BOOL)
    diff --git a/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.d.ts b/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.d.ts
    index 8dd6cef..1412484 100644
    --- a/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.d.ts
    +++ b/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.d.ts
    @@ -113,6 +113,7 @@ type WebViewDownloadEvent = Readonly<{
         downloadUrl: string;
     }>;
     export interface NativeProps extends ViewProps {
    +    googleMobileAdsWebViewRegistrationEnabled?: boolean;
         allowFileAccess?: boolean;
         allowsProtectedMedia?: boolean;
         allowsFullscreenVideo?: boolean;
    diff --git a/node_modules/react-native-webview/lib/WebViewTypes.d.ts b/node_modules/react-native-webview/lib/WebViewTypes.d.ts
    index 998cc88..ee21b02 100644
    --- a/node_modules/react-native-webview/lib/WebViewTypes.d.ts
    +++ b/node_modules/react-native-webview/lib/WebViewTypes.d.ts
    @@ -182,6 +182,7 @@ export interface BasicAuthCredential {
     }
     export interface CommonNativeWebViewProps extends ViewProps {
         cacheEnabled?: boolean;
    +    googleMobileAdsWebViewRegistrationEnabled?: boolean;
         incognito?: boolean;
         injectedJavaScript?: string;
         injectedJavaScriptBeforeContentLoaded?: string;
    @@ -962,6 +963,14 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
         onLoadSubResourceError?: (event: WebViewErrorEvent) => void;
     }
     export interface WebViewSharedProps extends ViewProps {
    +    /**
    +     * Registers the native WebView with the Google Mobile Ads SDK so ads rendered
    +     * by AdSense or Google Ad Manager can receive app signals.
    +     *
    +     * Requires the Google Mobile Ads SDK to be configured in the native app.
    +     * The default value is `false`.
    +     */
    +    googleMobileAdsWebViewRegistrationEnabled?: boolean;
         /**
          * Loads static html or a uri (with optional headers) in the WebView.
          */
    diff --git a/node_modules/react-native-webview/react-native-webview.podspec b/node_modules/react-native-webview/react-native-webview.podspec
    index 24e7a13..43489d1 100644
    --- a/node_modules/react-native-webview/react-native-webview.podspec
    +++ b/node_modules/react-native-webview/react-native-webview.podspec
    @@ -18,6 +18,7 @@ Pod::Spec.new do |s|
       s.source       = { :git => "https://github.com/react-native-webview/react-native-webview.git", :tag => "v#{s.version}" }
    
       s.source_files    = "apple/**/*.{h,m,mm,swift}"
    +  s.ios.dependency "Google-Mobile-Ads-SDK"
    
       if defined?(install_modules_dependencies()) != nil
         install_modules_dependencies(s);
    diff --git a/node_modules/react-native-webview/src/RNCWebViewNativeComponent.ts b/node_modules/react-native-webview/src/RNCWebViewNativeComponent.ts
    index 7f4e6c4..22ee8f1 100644
    --- a/node_modules/react-native-webview/src/RNCWebViewNativeComponent.ts
    +++ b/node_modules/react-native-webview/src/RNCWebViewNativeComponent.ts
    @@ -143,6 +143,8 @@ type WebViewDownloadEvent = Readonly<{
     // type MenuItem = Readonly<{label: string, key: string}>;
    
     export interface NativeProps extends ViewProps {
    +  googleMobileAdsWebViewRegistrationEnabled?: boolean;
    +
       // Android only
       allowFileAccess?: boolean;
       allowsProtectedMedia?: boolean;
    diff --git a/node_modules/react-native-webview/src/WebViewTypes.ts b/node_modules/react-native-webview/src/WebViewTypes.ts
    index eca8141..568e582 100644
    --- a/node_modules/react-native-webview/src/WebViewTypes.ts
    +++ b/node_modules/react-native-webview/src/WebViewTypes.ts
    @@ -289,6 +289,7 @@ export interface BasicAuthCredential {
    
     export interface CommonNativeWebViewProps extends ViewProps {
       cacheEnabled?: boolean;
    +  googleMobileAdsWebViewRegistrationEnabled?: boolean;
       incognito?: boolean;
       injectedJavaScript?: string;
       injectedJavaScriptBeforeContentLoaded?: string;
    @@ -1171,6 +1172,15 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
     }
    
     export interface WebViewSharedProps extends ViewProps {
    +  /**
    +   * Registers the native WebView with the Google Mobile Ads SDK so ads rendered
    +   * by AdSense or Google Ad Manager can receive app signals.
    +   *
    +   * Requires the Google Mobile Ads SDK to be configured in the native app.
    +   * The default value is `false`.
    +   */
    +  googleMobileAdsWebViewRegistrationEnabled?: boolean;
    +
       /**
        * Loads static html or a uri (with optional headers) in the WebView.
        */
    

    Usage:

    <WebView googleMobileAdsWebViewRegistrationEnabled />
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions