Skip to main content

Overview

The Watermelon chat widget can be embedded in any mobile app using a WebView. The steps are similar across platforms:
  1. Create a basic HTML shell.
  2. Inject the Watermelon chat widget script.
  3. Provide your widgetID and settingsID.
  4. Embed the view or present it in your app.
  5. Customize appearance in the watermelon dashboard

iOS Implementation

You can embed the Watermelon chat widget using a WKWebView. Below are minimal SwiftUI and UIKit implementations.

SwiftUI Example

import SwiftUI
import WebKit

struct ChatWidgetView: UIViewRepresentable {
    let widgetID: String
    let settingsID: String

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        let html = """
        <!DOCTYPE html>
        <html>
        <head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
        <body></body>
        </html>
        """
        webView.loadHTMLString(html, baseURL: nil)

        let script = """
        const s = document.createElement('script');
        s.src = 'https://chatwidget-prod.web.app/embed/init.iife.js';
        s.type = 'module';
        s.async = true;
        s.setAttribute('data-watermelon-widget-id', '\(widgetID)');
        s.setAttribute('data-watermelon-settings-id', '\(settingsID)');
        document.body.appendChild(s);
        """
        webView.evaluateJavaScript(script, completionHandler: nil)
        return webView
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {}
}

Usage

struct ChatScreen: View {
    var body: some View {
        ChatWidgetView(
            widgetID: "YOUR_WIDGET_ID",
            settingsID: "YOUR_SETTINGS_ID"
        )
    }
}

UIKit example

import UIKit
import WebKit

class ChatWidgetViewController: UIViewController {

    private var webView: WKWebView!
    let widgetID: String
    let settingsID: String

    init(widgetID: String, settingsID: String) {
        self.widgetID = widgetID
        self.settingsID = settingsID
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground

        webView = WKWebView()
        webView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(webView)

        NSLayoutConstraint.activate([
            webView.topAnchor.constraint(equalTo: view.topAnchor),
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])

        let html = """
        <!DOCTYPE html>
        <html>
        <head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
        <body></body>
        </html>
        """

        webView.loadHTMLString(html, baseURL: nil)

        let script = """
        const s = document.createElement('script');
        s.src = 'https://chatwidget-prod.web.app/embed/init.iife.js';
        s.type = 'module';
        s.async = true;
        s.setAttribute('data-watermelon-widget-id', '\(widgetID)');
        s.setAttribute('data-watermelon-settings-id', '\(settingsID)');
        document.body.appendChild(s);
        """

        webView.evaluateJavaScript(script, completionHandler: nil)
    }
}

Usage

    let vc = ChatWidgetViewController(
        widgetID: "YOUR_WIDGET_ID",
        settingsID: "YOUR_SETTINGS_ID"
    )

    navigationController?.pushViewController(vc, animated: true)

iOS — App Transport Security

In Info.plist, allow HTTPS content (optional):
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

Android Implementation

Below is the minimal implementation using a standard WebView.

1. Enable WebView JavaScript

`AndroidManifest.xml`:

`<uses-permission  android:name="android.permission.INTERNET" />`

2. Add the WebView to your layout

res/layout/activity_chat_widget.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <WebView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/chatWebView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

3. Load the widget

    class ChatWidgetActivity : AppCompatActivity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_chat_widget)

            val webView = findViewById<WebView>(R.id.chatWebView)

            webView.settings.javaScriptEnabled = true

            val html = """
                <!DOCTYPE html>
                <html>
                <head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
                <body></body>
                </html>
            """

            webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)

            val script = """
                const s = document.createElement('script');
                s.src = 'https://chatwidget-prod.web.app/embed/init.iife.js';
                s.type = 'module';
                s.async = true;
                s.setAttribute('data-watermelon-widget-id', 'YOUR_WIDGET_ID');
                s.setAttribute('data-watermelon-settings-id', 'YOUR_SETTINGS_ID');
                document.body.appendChild(s);
            """

            webView.evaluateJavascript(script, null)
        }
    }

Flutter Integration

Flutter apps can load the Watermelon chat widget using the built-in WebView widget.

1. Add dependency

In pubspec.yaml: dependencies: webview_flutter: ^4.7.0

2. Implement the widget

    import 'package:flutter/material.dart';
    import 'package:webview_flutter/webview_flutter.dart';

    class ChatWidget extends StatefulWidget {
      final String widgetID;
      final String settingsID;

      const ChatWidget({
        required this.widgetID,
        required this.settingsID,
        super.key,
      });

      @override
      State<ChatWidget> createState() => _ChatWidgetState();
    }

    class _ChatWidgetState extends State<ChatWidget> {
      late final WebViewController controller;

      @override
      void initState() {
        super.initState();

        controller = WebViewController()
          ..setJavaScriptMode(JavaScriptMode.unrestricted)
          ..loadHtmlString("""
            <!DOCTYPE html>
            <html>
            <head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
            <body></body>
            </html>
          """)
          ..runJavaScript("""
            const s = document.createElement('script');
            s.src = 'https://chatwidget-prod.web.app/embed/init.iife.js';
            s.type = 'module';
            s.async = true;
            s.setAttribute('data-watermelon-widget-id', '${widget.widgetID}');
            s.setAttribute('data-watermelon-settings-id', '${widget.settingsID}');
            document.body.appendChild(s);
          """);
      }

      @override
      Widget build(BuildContext context) {
        return WebViewWidget(controller: controller);
      }
    }