Integration for iOS

Documentation

This guide explains how to embed our Smart Assistant chatbot in your iOS app using a WKWebView. The integration consists of two parts:

  1. An HTML page that loads the Smart Assistant web component.
  2. A SwiftUI view that hosts the WKWebView and bridges native ↔ JavaScript communication (e.g. to close the assistant).

1. Create the HTML page

Add an HTML file (smart_assistant.html) to your app bundle. It loads our launcher.js script and declares the <smart-assistant> web component.

On iOS, the native ↔ JavaScript bridge works through window.webkit.messageHandlers. The Swift code below registers a handler named smartAssistantClose, so the HTML must call window.webkit.messageHandlers.smartAssistantClose.postMessage(...) when the assistant closes.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  <title>Smart Assistant</title>
  <script src="https://sa-media.usizy.es/smart-assistant/launcher.js"></script>
</head>
<body>
  <smart-assistant language="en" api-key="YOUR_API_KEY" opened hide-minimize></smart-assistant>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      const sa = document.querySelector('smart-assistant')

      // Escuchar el evento de cierre del componente (equivalente al Android bridge)
      sa.addEventListener('close', function () {
        if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.smartAssistantClose) {
          window.webkit.messageHandlers.smartAssistantClose.postMessage('close')
        }
      })
    })
  </script>
</body>
</html>
AttributeDescription
languageInterface language (e.g. en, es).
api-keyYour API key. Replace YOUR_API_KEY with the key provided by usizy.
openedOpens the assistant automatically when the page loads.
hide-minimizeHides the minimize button (recommended for full-screen WebView usage).

The close event listener is essential: it calls window.Android.close(), which is the JavaScript bridge that lets the web component close the native Android screen.

3. Create the SwiftUI view

The following example uses SwiftUI. It wraps a native WKWebView inside a UIViewRepresentable, configures the required settings, and registers a script message handler (smartAssistantClose) so the web component can trigger native navigation.

import SwiftUI
import WebKit

struct SmartAssistantView: View {
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        SmartAssistantWebView(onClose: { dismiss() })
            .ignoresSafeArea(edges: .bottom)
            .navigationTitle("Smart Assistant")
            .navigationBarTitleDisplayMode(.inline)
            .toolbarBackground(Color(red: 0.427, green: 0.231, blue: 0.478), for: .navigationBar)
            .toolbarBackground(.visible, for: .navigationBar)
            .toolbarColorScheme(.dark, for: .navigationBar)
    }
}

struct SmartAssistantWebView: UIViewRepresentable {
    let onClose: () -> Void

    func makeCoordinator() -> Coordinator {
        Coordinator(onClose: onClose)
    }

    func makeUIView(context: Context) -> WKWebView {
        let configuration = WKWebViewConfiguration()
        // Allow inline media playback without requiring a user gesture
        configuration.allowsInlineMediaPlayback = true
        configuration.mediaTypesRequiringUserActionForPlayback = []

        // Register the JS → native bridge named "smartAssistantClose"
        let contentController = WKUserContentController()
        contentController.add(context.coordinator, name: "smartAssistantClose")
        configuration.userContentController = contentController

        let webView = WKWebView(frame: .zero, configuration: configuration)
        webView.backgroundColor = .clear
        webView.isOpaque = false
        webView.scrollView.bounces = false
        webView.navigationDelegate = context.coordinator

        // Enable Safari Web Inspector while debugging (iOS 16.4+)
        #if DEBUG
        if #available(iOS 16.4, *) {
            webView.isInspectable = true
        }
        #endif

        // Load the local HTML asset bundled with the app
        if let htmlURL = Bundle.main.url(forResource: "smart_assistant", withExtension: "html") {
            webView.loadFileURL(htmlURL, allowingReadAccessTo: htmlURL.deletingLastPathComponent())
        }
        return webView
    }

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

    class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
        let onClose: () -> Void

        init(onClose: @escaping () -> Void) {
            self.onClose = onClose
        }

        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
                     decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            decisionHandler(.allow)
        }

        // Receives messages posted from JavaScript via window.webkit.messageHandlers
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == "smartAssistantClose" {
                DispatchQueue.main.async {
                    self.onClose()
                }
            }
        }
    }
}

4. Key configuration explained

WKWebView configuration

These settings are required for the Smart Assistant to work correctly:

SettingWhy it is needed
allowsInlineMediaPlayback = truePlays audio/video inline instead of forcing full-screen playback.
mediaTypesRequiringUserActionForPlayback = []Allows media to start without an explicit user gesture.
userContentController.add(_:name:)Registers the smartAssistantClose JS → native message bridge.
loadFileURL(_:allowingReadAccessTo:)Loads the local HTML and grants read access to its folder (and resources).
webView.isInspectable = true (DEBUG)Enables Safari Web Inspector for debugging on iOS 16.4+.

####JavaScript bridge (smartAssistantClose)

The Coordinator conforms to WKScriptMessageHandler and is registered with the name smartAssistantClose. When the user closes the assistant, the web component emits a close event, the HTML calls window.webkit.messageHandlers.smartAssistantClose.postMessage(‘close’), and userContentController(_:didReceive:) invokes your onClose() callback to dismiss the view. Note: Message handlers may be delivered off the main thread depending on the call site, so any UI work (like dismissing the view) is dispatched to the main thread with DispatchQueue.main.async.

5. Present the view in your navigation

Present the view from your navigation stack, for example with a NavigationLink or a sheet:

NavigationLink("Open Smart Assistant") {
    SmartAssistantView()
}

Or as a modal sheet:

.sheet(isPresented: $isAssistantPresented) {
    NavigationStack {
        SmartAssistantView()
    }
}

Add the HTML to your app target

Make sure smart_assistant.html is added to your app target so it is copied into the bundle: Drag the file into your Xcode project. In the dialog, check Copy items if needed. Confirm the file appears under Target → Build Phases → Copy Bundle Resources. If you load remote resources over plain HTTP (not recommended), you will also need to configure App Transport Security (ATS) in Info.plist. Loading our launcher.js over HTTPS requires no extra ATS configuration.

Sample App

Check our sample app for iOS