πŸŽ’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)
}

Step 2: Make updates to AndroidManifest.xml

The 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>

Using android:configChanges="orientation|screenSize" stops the activity from being recreated on rotation. Keep this attribute if your activity is simple and doesn’t need to restart during orientation changes, but for complex activities, it may be better to rely on the default configuration‑change handling.

Step 3: Setup a WebViewClient to intercept URLs

Create 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()
        }
    }
}

Step 4: Set this CustomWebViewClient as your WebView client

To do so, add the following line in the Activity where you created your WebView:

myWebView.webViewClient = CustomWebViewClientKotlin()

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)

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()
}

Destroying the WebView releases its internal resources (JavaScript threads, rendering cache, etc.) without clearing the shared application cache.

This keeps Gamezop games and other web content loading fast on subsequent visits while ensuring the app itself does not leak memory.

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 Manager

Step 7: Integrate the WebView API for Ads

You can avoid this step if you are integrating Gamezop games or any of our other products with ads disabled. However, if you are working with us on our advertising revenue-share model, following this step is crucial for optimal ad monetisation.

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.

Prerequisites
  • Google Mobile Ads SDK version 20.6.0 or higher

  • Android API level 21 or higher

  • Add the following <meta-data> tag in your AndroidManifest.xml file to bypass the check for the APPLICATION_ID. If you miss this step and don't provide the <meta-data> tag, the Google Mobile Ads SDK throws an IllegalStateException on app start.

<!-- Bypass APPLICATION_ID check for web view APIs for ads -->
 <meta-data
     android:name="com.google.android.gms.ads.INTEGRATION_MANAGER"
     android:value="webview"/>

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)


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()

The WebView resource cache is shared across all WebViews within your app.

If you clear it frequently (for example, every time the WebView is destroyed), all downloaded game assets will need to be fetched again, increasing load times and data usage.


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

Last updated

Was this helpful?