Skip to main content
The recommended way to integrate Molin AI in your Android app is by rendering our widget inside a WebView component. See the full working example on GitHub: molin-ai/molin-ai-android-example.

Basic setup

Create an HTML file that loads the widget and displays the chat component fullscreen. Place it at app/src/main/assets/widget.html:
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      html,
      body {
        height: 100%;
        width: 100%;
        overflow: hidden;
        background: #fdfdfd;
      }
      molin-shop-ai-chat {
        display: block;
        width: 100%;
        height: 100%;
      }
    </style>
    <script src="https://widget.molin.ai/shop-ai.js"></script>
  </head>
  <body>
    <molin-shop-ai-chat show-close widget="YOUR_WIDGET_ID"></molin-shop-ai-chat>
  </body>
</html>
Replace YOUR_WIDGET_ID with your actual widget ID from the Molin dashboard. The show-close attribute is optional. It renders a close button (✕) in the chat header, which is useful when the widget is displayed fullscreen in a webview. You can omit it if your app has its own navigation to dismiss the chat.

Loading the WebView

Create a layout with a fullscreen WebView (res/layout/activity_main.xml):
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Then load the HTML file in your activity:
import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import android.webkit.WebSettings
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        supportActionBar?.hide()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView: WebView = findViewById(R.id.webView)

        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        @SuppressLint("AllowUniversalAccessFromFileURLs")
        webView.settings.allowUniversalAccessFromFileURLs = true

        webView.webViewClient = WebViewClient()
        webView.loadUrl("file:///android_asset/widget.html")
    }
}

Handling the close button

When the user taps the close button, the <molin-shop-ai-chat> element fires a molin-shop-ai-chat:close-click event. Navigate to a custom molin:// URL to tell the native side to go back:
<script>
  document.addEventListener('molin-shop-ai-chat:close-click', function () {
    window.location.href = 'molin://close';
  });
</script>
On the Kotlin side, intercept the molin:// scheme in a WebViewClient:
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(
        view: WebView?,
        request: WebResourceRequest?
    ): Boolean {
        val url = request?.url ?: return false
        if (url.scheme == "molin") {
            if (url.host == "close") {
                finish()
            }
            return true
        }
        return false
    }
}