DEV Community

Chingiz I
Chingiz I

Posted on

Problem with flutter webview on Android - I cannot create dynamically iframes

I'm trying to integrate Kommunicate Web SDK into my Flutter app, but facing issues with dynamic iframe creation specifically on Android.

I do like this

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Stack(
        children: [
          InAppWebView(
            onWebViewCreated: (InAppWebViewController controller) {
              _controller = controller;
              _loadHtmlTemplate();
            },

....

  Future<void> _loadHtmlTemplate() async {
    try {
      String htmlTemplate = await rootBundle.loadString('assets/html/template.html');
      final chatContent = htmlTemplate.replaceAll('__APP_ID__', widget.token);
      await _loadHtmlContent(chatContent);
    } catch (e) {
      debugPrint('⚠️ Failed to load HTML template: $e');
    }
  }

  Future<void> _loadHtmlContent(String content) async {
    await _controller.loadData(
      data: content,
      mimeType: 'text/html',
      encoding: 'utf8',
    );
  }
Enter fullscreen mode Exit fullscreen mode

Inside template.html

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script>

        (function(d, m){
        var kommunicateSettings = {
            "appId": "__APP_ID__",
            "onInit": function() { }
          };

        var s = document.createElement("script"); 
        s.type = "text/javascript"; 
        s.async = true;
        s.src = "https://widget.kommunicate.io/v2/kommunicate.app";
        var h = document.getElementsByTagName("head")[0]; 
            h.appendChild(s);
            window.kommunicate = m; 
            m._globals = kommunicateSettings;
        })(document, window.kommunicate || {});

    </script>
  </head>
  <body>
    <div class="container">
      <div class="loader-overlay" id="loader-overlay">
        <p style="margin-bottom: 12px;">Loading…</p>
        <div class="loader"></div>
      </div>
    </div>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode

So as you can see Immediately Invoke Function Expression which finally causing iframe to be loaded and appeared. Everything according the documentation (https://github.com/Kommunicate-io/Kommunicate-Web-SDK), the integration should work with this script inside html's head:

<script type="text/javascript">
    (function(d, m){
        var kommunicateSettings = {
            "appId": "<APP_ID>",
            "automaticChatOpenOnNavigation": true,
            "popupWidget": true
        };

        var s = document.createElement("script");
        s.type = "text/javascript";
        s.async = true;
        s.src = "https://widget.kommunicate.io/v2/kommunicate.app";
        var h = document.getElementsByTagName("head")[0];
        h.appendChild(s);
        window.kommunicate = m;
        m._globals = kommunicateSettings;
    })(document, window.kommunicate || {});
</script>
Enter fullscreen mode Exit fullscreen mode

The problem: both WebView and InAppWebView (using webviewflutter and flutterinappwebview) fail to load the dynamically created iframe on Android, while everything works perfectly on iOS.

On Android, I get errors like "Kommunicate is not defined" because the iframe creation seems to be blocked. I've tried all possible configurations:

InAppWebView(
    initialSettings: InAppWebViewSettings(
        javaScriptEnabled: true,
        supportMultipleWindows: true,
        mixedContentMode: MixedContentMode.MIXED_CONTENT_ALWAYS_ALLOW,
        iframeAllowFullscreen: true,
        iframeAllow: "microphone; geolocation; camera; autoplay; display-capture",
        allowFileAccessFromFileURLs: true,
        allowUniversalAccessFromFileURLs: true,
        domStorageEnabled: true,
        databaseEnabled: true,
        mediaPlaybackRequiresUserGesture: false,
        allowsInlineMediaPlayback: true,
        allowsAirPlayForMediaPlayback: true,
        useWideViewPort: true,
        loadWithOverviewMode: true,
        builtInZoomControls: false,
        displayZoomControls: false,
    ),
    onLoadStop: (controller, url) async {
        await controller.evaluateJavascript(source: """
            document.addEventListener('DOMContentLoaded', function() {
                try {
                    var iframes = document.querySelectorAll('iframe');
                    iframes.forEach(function(iframe) {
                        iframe.setAttribute('allow', 'microphone; camera; geolocation; autoplay');
                        iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads');
                    });
                } catch(e) {
                    console.log('Iframe setup error: ' + e);
                }
            });
        """);
    },
)
Enter fullscreen mode Exit fullscreen mode

Nothing helps - it feels like there are some security restrictions on Android that prevent dynamic iframe creation. Has anyone faced and solved this issue with Kommunicate or similar Web SDKs on Android WebView?

Full text:

web_chat.dart

template.html

Top comments (0)