A small Flutter app demonstrating the Google Mobile Ads WebView API for Ads on both Android and iOS.
It is the cross-platform companion to:
The sample intentionally stays focused:
- One shared Flutter implementation
- A white, safe-area-aware launcher with three thumbnail cards
- One reusable
WebViewControllerregistered with Google Mobile Ads - Correct Android and iOS media, cookie, and platform configuration
- In-app handling for off-domain ad and game click-outs
- No strict-mode or partner-security simulation
The implementation follows:
- Use WebView API for ads with Flutter
- Google Mobile Ads Flutter quick start
- Optimize WKWebView click behavior
webview_flutterdocumentation
All three destinations are active at the same time:
| Card | URL | Purpose |
|---|---|---|
| Google WebView Ads Test | https://google.github.io/webview-ads/test/ |
Validate WebView settings, GMA registration, cookies, media, and clicks |
| Gamezop Portal | https://peslsv.play.gamezop.com |
Browse the configured Gamezop portal |
| Random Game | https://www.gamezop.com/g/random |
Resolve and launch an individual game |
Edit lib/sample_destination.dart to change or
extend this list.
At the top of the launcher, the app shows a separate inline warning for each relevant platform. The portal card remains immediately available:
- iOS Simulator: App Store links cannot open in the simulator. Use a physical iPhone or iPad to test those redirects; the portal itself can still be opened.
- Android: This portal URL can crash the Android app/WebView. The red notice makes that known issue explicit before the portal is opened.
The app performs these steps in order:
- Calls
WidgetsFlutterBinding.ensureInitialized(). - Starts native SDK initialization without blocking the launcher screen.
- Creates a platform-aware
WebViewController. - Enables unrestricted JavaScript.
- Enables inline and automatic media playback.
- Enables Android third-party cookies.
- Installs the navigation delegate.
- Awaits the shared SDK initialization future.
- Calls
MobileAds.instance.registerWebView(controller). - Loads the selected network URL.
Registration happens before the first page load. This lets AdSense code or Google Publisher Tags exchange app signals with the native GMA SDK.
This sample uses WebView-only monetization and therefore configures the integration-manager bypass instead of a native ad application ID:
android/app/src/main/AndroidManifest.xml
contains:
<meta-data
android:name="com.google.android.gms.ads.INTEGRATION_MANAGER"
android:value="webview" />ios/Runner/Info.plist contains:
<key>GADIntegrationManager</key>
<string>webview</string>If the application later displays native banner, interstitial, rewarded, or app-open ads, replace this WebView-only setup with the application ID required by the relevant Google Mobile Ads quick-start documentation.
Shared configuration:
- JavaScript enabled
- Persistent platform website storage
- Network URLs loaded with
loadRequest - Main-document load progress and errors surfaced in Flutter
- Back gestures/history supported
Android-specific configuration:
- Third-party cookies enabled
- Media playback does not require a user gesture
- WebView debugging enabled in debug builds
iOS-specific configuration:
- Inline media playback enabled
- No media types require a user gesture
- Back/forward navigation gestures enabled
Third-party cookies are expected to be unavailable on iOS. Google’s test page reports this as informational rather than an integration failure.
Top-level HTTPS navigation stays embedded for:
google.github.iogamezop.com- Any host ending in
.gamezop.com
The Gamezop subdomain rule matters because /g/random can redirect to a
game-specific Gamezop host.
The allowlist only applies to top-level navigation. Subframes are deliberately allowed without host filtering because games, ad tags, analytics, and browser-internal documents can use:
- Additional HTTPS origins
about:blankabout:srcdocblob:anddata:documents
Filtering these frames is a common reason games stop during initialization.
Off-domain HTTPS clicks open above the game using:
SFSafariViewControlleron iOS- Custom Tabs on Android
App Store, Play Store, and custom-scheme links are handed to the operating system. Returning from a click-out preserves the original WebView and running game state.
lib/main.dart: SDK initialization and root applib/mobile_ads_service.dart: single shared SDK initialization futurelib/home_screen.dart: launcher and thumbnail cardslib/sample_destination.dart: the three URLslib/navigation_policy.dart: shared allowlistlib/gma_webview_screen.dart: controller configuration, GMA registration, loading, and click handlingandroid/app/src/main/AndroidManifest.xml: Android internet permission and GMA integration managerios/Runner/Info.plist: iOS GMA integration managertest/: launcher and navigation-policy tests
- Flutter 3.44.8 or later
- Dart 3.12 or later
- Android Studio with Android SDK 24 or later
- Xcode 16 or later
- CocoaPods
Package versions are locked in pubspec.lock.
Install packages:
flutter pub getCheck the local toolchains:
flutter doctorRun on Android:
flutter run -d <android-device-id>Run on iOS:
flutter run -d <ios-device-id>You can list available device IDs with:
flutter devicesflutter analyze
flutter test
flutter build apk --debug
flutter build ios --simulator --debugOpen the Google WebView Ads Test card and verify:
- JavaScript is enabled
- First-party cookies work
- Video plays inline
- Video starts automatically
- Video is replayable
- The WebView is connected to the Google Mobile Ads Flutter plugin
- Google Publisher Tag is connected to GMA
target="_top"andtarget="_blank"href tests open correctly- The JavaScript
window.open("_blank")test opens correctly - Returning from a click-out does not reset the test-page counter
- Store links open the appropriate store app
The Google Play market:// test only applies to Android. Third-party cookies
are not expected to work on iOS.
For network-level verification, inspect an ad request and confirm it includes a
scar parameter as described in Google’s Flutter WebView documentation.
- Complete consent collection before
MobileAds.instance.initialize(). - Native-app consent is not automatically propagated to hosted web content. Coordinate the WebView consent flow with your CMP.
- Register every monetized
WebViewControllerbefore loading its first page. - Do not remove script-message handlers installed by the GMA SDK.
- Keep all production pages on HTTPS; this sample needs no cleartext/ATS exceptions.
- Review App Store and Play privacy declarations before distribution.