πAdd Unique Link using in-app WebView
This document outlines how you can use Android WebViews to run our products inside your app.
This document has been written assuming you're integrating a Gamezop Unique Link or individual games. However, the steps to follow are the same even if you're integrating Quizzop / Astrozop or any of our other products in your app.
Integration guide
This guide applies to Android WebView integration only. Follow the steps given below closely to get a perfectly working WebView implementation in your app:
Step 1: Create the WebView via code (instead of XML)
We recommend creating the WebView in code for simplicity. To prevent memory leaks, make sure to call destroy() on the WebView in the Activityβs onDestroy().
You may have a particular Android Activity where you place the Gamezop icon / banner. When a user taps on that icon / banner, you want to open your game URL within a WebView. Within the onCreate method of this Activity, you will have to create the WebView as mentioned below:
private lateinit var myWebView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myWebView = WebView(this)
setContentView(myWebView)
}// At the top of your Activity class:
private WebView myWebView;
// In onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myWebView = new WebView(this);
setContentView(myWebView);
}Step 2: Make updates to AndroidManifest.xml
AndroidManifest.xmlThe primary objective of making these updates is to enable the following:
Internet access for the WebView
Screen orientation changes within the WebView (since games can be landscape as well)
Hardware acceleration for better game performance
Here are the updates to be made within your app's AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.WebViewSetup">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>Step 3: Setup a WebViewClient to intercept URLs
WebViewClient to intercept URLsCreate a CustomWebViewClient file within the same directory as where you have your MainActivity file. Java and Kotlin versions of this file are given below:
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.util.Log
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast
import java.net.MalformedURLException
import java.net.URI
import java.net.URISyntaxException
class CustomWebViewClientKotlin : WebViewClient() {
private val TAG = "CustomWebViewClient"
// Replace with the host of the unique link provided by your Gamezop Account Manager
private val GAMEZOP_DOMAIN = "gamezop.com"
private val NO_APPLICATION_ERROR = "You do not have an application to run this."
/** Allow exactly gamezop.com or any subdomain like *.gamezop.com */
private fun isGamezopHost(uri: Uri?): Boolean {
val host = uri?.host ?: return false
return host.equals(GAMEZOP_DOMAIN, ignoreCase = true) ||
host.endsWith(".${GAMEZOP_DOMAIN}", ignoreCase = true)
}
private fun isHttpOrHttps(uri: Uri?): Boolean {
val scheme = uri?.scheme ?: return false
return scheme.equals("http", true) || scheme.equals("https", true)
}
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
val uri = request.url
// Early exit: if both host & scheme are missing, let WebView handle it.
if (uri.host == null && uri.scheme == null) {
return false
}
// Handle custom (non-http/https) schemes externally (e.g., market://, intent://).
if (!isHttpOrHttps(uri)) {
return tryOpenExternally(view, uri)
}
// Keep Gamezop links in-WebView
if (isGamezopHost(uri)) {
// Do NOT call loadUrl here; returning false lets WebView handle it.
return false
}
// Same-domain navigation: if current page host == target host, keep inside.
val currentHost = try {
view.url?.let { URI(it).toURL().host }
} catch (_: URISyntaxException) { null }
catch (_: MalformedURLException) { null }
val targetHost = uri.host
if (currentHost != null && targetHost != null &&
currentHost.equals(targetHost, ignoreCase = true)) {
return false
}
// External navigation: open in the user's default browser
openOutside(view, uri)
return true
}
// Fallback for older callers (String overload is deprecated but may still be invoked)
@Deprecated("Deprecated in Android API, kept here for compatibility")
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
val uri = runCatching { Uri.parse(url) }.getOrNull()
if (uri == null) return false
// Non-http(s) β try external app
if (!isHttpOrHttps(uri)) {
return tryOpenExternally(view, uri)
}
// Gamezop or same-domain β keep inside
if (isGamezopHost(uri)) return false
val currentHost = runCatching { view.url?.let { URI(it).toURL().host } }.getOrNull()
val targetHost = uri.host
if (currentHost != null && targetHost != null &&
currentHost.equals(targetHost, ignoreCase = true)) {
return false
}
// External https/http β default browser
openOutside(view, uri)
return true
}
/** Attempt to open non-http/https schemes in an external app. */
private fun tryOpenExternally(view: WebView, uri: Uri): Boolean {
return try {
val external = Intent(Intent.ACTION_VIEW, uri)
view.context.startActivity(external)
true
} catch (e: ActivityNotFoundException) {
Log.d(TAG, "No app to handle custom scheme: $uri", e)
Toast.makeText(view.context, NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show()
true
}
}
/** Open standard http/https external URLs in the user's default browser. */
private fun openOutside(view: WebView, uri: Uri?) {
if (uri == null) {
Toast.makeText(view.context, NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show()
return
}
val intent = Intent(Intent.ACTION_VIEW, uri)
val pm: PackageManager = view.context.packageManager
val activities = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
if (activities.isNotEmpty()) {
view.context.startActivity(intent)
} else {
Toast.makeText(view.context, NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show()
}
}
}import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URI;
import java.util.List;
public class CustomWebViewClient extends WebViewClient {
private static final String TAG = "CustomWebViewClient";
// Replace with the host value of the link provided to you by your Gamezop Account Manager
private static final String GAMEZOP_DOMAIN = "gamezop.com";
private static final String NO_APPLICATION_ERROR = "You do not have an application to run this.";
private boolean isGamezopHost(Uri uri) {
if (uri == null) return false;
String host = uri.getHost();
if (host == null) return false;
// allow exactly gamezop.com or any subdomain like *.gamezop.com
return host.equals(GAMEZOP_DOMAIN) || host.endsWith("." + GAMEZOP_DOMAIN);
}
private boolean isHttpOrHttps(Uri uri) {
if (uri == null || uri.getScheme() == null) return false;
String s = uri.getScheme();
return "http".equalsIgnoreCase(s) || "https".equalsIgnoreCase(s);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request != null ? request.getUrl() : null;
// If both host and scheme are missing, let WebView handle it
if (uri == null || (uri.getHost() == null && uri.getScheme() == null)) {
return false;
}
// Handle non-http(s) custom schemes (e.g. market://, intent://)
if (!isHttpOrHttps(uri)) {
try {
Intent external = new Intent(Intent.ACTION_VIEW, uri);
view.getContext().startActivity(external);
} catch (ActivityNotFoundException e) {
Log.d(TAG, "No app to handle custom scheme: " + uri, e);
Toast.makeText(view.getContext(), NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show();
}
return true;
}
// Stay within WebView for Gamezop or same-domain navigations
if (isGamezopHost(uri)) {
return false; // Let WebView load Gamezop URLs itself
}
String currentHost = null;
try {
String currentUrl = view.getUrl();
if (currentUrl != null) {
currentHost = new URI(currentUrl).toURL().getHost();
}
} catch (URISyntaxException | MalformedURLException ignore) { }
String targetHost = uri.getHost();
// Same-domain navigation β keep inside the WebView
if (currentHost != null && targetHost != null && currentHost.equalsIgnoreCase(targetHost)) {
return false;
}
// External navigation β open in the userβs default browser
openOutside(view, uri);
return true;
}
// Fallback for deprecated String overload
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = url != null ? Uri.parse(url) : null;
if (uri == null) return false;
if (isGamezopHost(uri)) {
return false;
} else {
openOutside(view, uri);
return true;
}
}
private void openOutside(WebView view, Uri uri) {
if (uri == null) {
Toast.makeText(view.getContext(), NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show();
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
PackageManager pm = view.getContext().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (!activities.isEmpty()) {
view.getContext().startActivity(intent);
} else {
Toast.makeText(view.getContext(), NO_APPLICATION_ERROR, Toast.LENGTH_LONG).show();
}
}
}Step 4: Set this CustomWebViewClient as your WebView client
CustomWebViewClient as your WebView clientTo do so, add the following line in the Activity where you created your WebView:
myWebView.webViewClient = CustomWebViewClientKotlin()myWebView.setWebViewClient(new CustomWebViewClient());Step 5: Configure WebView settings in the holder Activity
Add the following lines in the Activity where you created your WebView:
val settings = myWebView.settings
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.javaScriptCanOpenWindowsAutomatically = true
settings.setGeolocationEnabled(true)
settings.loadsImagesAutomatically = true
settings.useWideViewPort = true
settings.setSupportZoom(false)
settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
// Crucial for optimal ad monetisation
settings.mediaPlaybackRequiresUserGesture = false
myWebView.setSoundEffectsEnabled(true)
myWebView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY
myWebView.setBackgroundColor(Color.argb(1, 0, 0, 0))
// Cookies
CookieManager.getInstance().setAcceptCookie(true)
// Enabling 3rd-party cookies is crucial for optimal ad monetisation
CookieManager.getInstance().setAcceptThirdPartyCookies(myWebView, true)WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setGeolocationEnabled(true);
settings.setLoadsImagesAutomatically(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(false);
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
// Crucial for optimal ad monetisation
settings.setMediaPlaybackRequiresUserGesture(false);
myWebView.setSoundEffectsEnabled(true);
myWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
myWebView.setBackgroundColor(Color.argb(1, 0, 0, 0));
// Cookies
CookieManager.getInstance().setAcceptCookie(true);
// Enabling 3rd-party cookies is crucial for optimal ad monetisation
CookieManager.getInstance().setAcceptThirdPartyCookies(myWebView, true);To prevent memory leaks, always destroy the WebView when the activity or fragment that hosts it is destroyed.
Add the following line inside your activityβs onDestroy() method:
override fun onDestroy() {
myWebView.destroy()
super.onDestroy()
}@Override
protected void onDestroy() {
if (myWebView != null) {
myWebView.destroy();
}
super.onDestroy();
}Step 6: Open your Gamezop Unique Link
Once you are done with the 5 steps mentioned above, you are ready to open your Gamezop game URL within your WebView. Add this line at the end of the Activity where you created your WebView:
myWebView.loadUrl("https://3025.play.gamezop.com") //ensure you replace this with the URL provided to you by your Gamezop Account ManagermyWebView.loadUrl("https://3025.play.gamezop.com"); //ensure you replace this with the URL provided to you by your Gamezop Account ManagerStep 7: Integrate the WebView API for Ads
The WebView Ads API shares app signals with Google ad tags used within Gamezop, helping optimise ad delivery and increase monetisation β which in turn boosts your revenue share.
Register the web view
Call registerWebView() on the main thread to establish a connection with the JavaScript handlers in the AdSense code or Google Publisher Tag within each WebView instance. This should be done as early as possible, such as in the onCreate() method of your MainActivity.
import com.google.android.gms.ads.MobileAds
// After Step 5 (settings) and before/after Step 6 (loadUrl), simply register:
MobileAds.registerWebView(myWebView)import com.google.android.gms.ads.MobileAds;
// After Step 5 settings (and before/after Step 6 loadUrl), register the same WebView:
MobileAds.registerWebView(myWebView);Cache and performance
WebView automatically caches Gamezopβs game assets and user cookies to make reloads much faster for returning users. To maintain this performance, avoid clearing the WebView cache or cookies unnecessarily.
β Best practice: Let WebView manage its own cache and cookie storage.
β Avoid:
webView.clearCache(true)CookieManager.getInstance().removeAllCookies(null)WebStorage.getInstance().deleteAllData()
Test ads performance
Use this URL to test if your WebView is properly optimised for ad monetisation:
https://google.github.io/webview-ads/test/The test URL has success criteria for a complete integration if the following are observed:
WebView settings
Third-party cookies work
First-party cookies work
JavaScript enabled
DOM storage enabled
Video ad
The video ad plays inline and does not open in the full screen built-in player
The video ad plays automatically without clicking the play button
The video ad is replayable
WebView API for Ads
If you followed Step 7 above, visit this link in your app's WebView to check if it successfully connected to the Google Mobile Ads SDK. The test URL should show green status bars for a successful integration.
Optimal click behaviour
Open this link in your app's WebView. Click each of the different link types to see how they behave in your app. Here are some things to check:
Each link opens the intended URL.
When returning to the app, the test page's counter doesn't reset to zero to validate the page state was preserved.
After testing is complete, substitute the test URLs from Google with your Gamezop Unique Link.
Useful resources
Ad monetisation best practises (Android): https://developers.google.com/ad-manager/mobile-ads-sdk/android/browser/webview
Ad monetisation best practises (iOS): https://developers.google.com/ad-manager/mobile-ads-sdk/ios/browser/webview
Last updated
Was this helpful?