方言を話すおしゃべり猫型ロボット『ミーア』をリリースしました(こちらをクリック)

[Flutter] How to deal with JavaScript invalidity error when opening Google Forms in web view on Android.

flutter-web-view-android
This article can be read in about 12 minutes.

Introduction.

Developing “Mia,” a talking cat-shaped robot that speaks in various dialects.

https://mia-cat.com/en

A few days ago, we described here an article on “Installing a Google Form for Bug and Error Inquiries in the Application “.

However, we received the following inquiry from a user.

I tried to open a bug/error report from the app and got the following error: “I have javascript enabled in my Chrome browser.”

In this issue, we describe how to deal with the above.

Default setting for webview_flutter plugin is JacaScript disabled

This time, the web view display uses the webview_flutter plugin.

https://pub.dev/packages/webview_flutter

The default setting in the webview_flutter plugin is JavaScriptMode.disabled, meaning that JavaScript is disabled by default.

Dart
  /// Sets the JavaScript execution mode to be used by the WebView.
  Future setJavaScriptMode(JavaScriptMode javaScriptMode) {
    return platform.setJavaScriptMode(javaScriptMode);
  }

For Android, JavaScriptMode.unrestricted must be explicitly set at the code level to enable JavaScript in WebView in the application.

Specifically, JavaScript must be enabled during WebViewController initialization.

Dart
_controller = WebViewController()
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..loadRequest(Uri.parse('https://docs.google.com/forms/d/e/XXXX/viewform'));

This setting allows WebView to execute JavaScript and ensures correct operation of web pages that require JavaScript.

Differences between iOS and Android Javascript settings

In the iOS WebView (WKWebView ), JavaScript is enabled by default. Therefore, websites that use JavaScript (e.g. Google Forms, etc.) can be displayed without any problems without changing any particular settings.

Android’s WebView has JavaScript disabled for security reasons, so if you use WebView in your app and JavaScript is required, you must explicitlysetJavaScriptMode.unrestricted at the code level to You need to enable it.

WebView in the application is independent of the system browser settings on the Android device. In other words, enabling JavaScript in the device’s system browser settings (e.g. Google Chrome) does not mean that JavaScript is enabled in WebView within the application.

Web pages such as Google Forms make heavy use of JavaScript to display interactive elements and dynamic content. For this reason, if JavaScript is disabled, they may not display properly.

Modified code (Google Forms webview)

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

class ErrorReportScreen extends StatefulWidget {
  const ErrorReportScreen({super.key});

  @override
  _ErrorReportScreenState createState() => _ErrorReportScreenState();
}

class _ErrorReportScreenState extends State {
  late WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..loadRequest(Uri.parse(
          'https://docs.google.com/forms/d/e/XXXX/viewform'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ミーア不具合・エラー報告'),
        actions: [
          IconButton(
            icon: const Icon(Icons.close),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      ),
      body: Column(
        children: [
          Container(
            padding: const EdgeInsets.all(16.0),
            color: Colors.yellow[100],
            child: const Text(
              'エラーや不具合の画像や動画をアップロードしていただくために、Googleアカウントでログインしてください。',
              style: TextStyle(fontSize: 16.0),
            ),
          ),
          Expanded(
            child: WebViewWidget(controller: _controller),
          ),
        ],
      ),
    );
  }
}

Configuration of NavigationDelegate

This time, the application only opens the google form directly in webview, so that users cannot access other URLs by themselves.

However, to further reduce the security risk of unexpected redirects and clicks on external links, NavigationDelegate should be used to allow only requests from docs.google.com.

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

class ErrorReportScreen extends StatefulWidget {
  const ErrorReportScreen({super.key});

  @override
  _ErrorReportScreenState createState() => _ErrorReportScreenState();
}

class _ErrorReportScreenState extends State {
  late WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..loadRequest(Uri.parse(
          'https://docs.google.com/forms/d/e/XXXX/viewform'))
      ..setNavigationDelegate(NavigationDelegate(
        onNavigationRequest: (NavigationRequest request) {
          // googleドメインのみ許可
          if (request.url.startsWith('https://docs.google.com/')) {
            return NavigationDecision.navigate;
          }
          return NavigationDecision.prevent;
        },
      ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ミーア不具合・エラー報告'),
        actions: [
          IconButton(
            icon: const Icon(Icons.close),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      ),
      body: Column(
        children: [
          Container(
            padding: const EdgeInsets.all(16.0),
            color: Colors.yellow[100],
            child: const Text(
              'エラーや不具合の画像や動画をアップロードしていただくために、Googleアカウントでログインしてください。',
              style: TextStyle(fontSize: 16.0),
            ),
          ),
          Expanded(
            child: WebViewWidget(controller: _controller),
          ),
        ],
      ),
    );
  }
}

operation check

With the above configuration change, Google Forms are now successfully displayed on the actual Android device.

I had only checked the operation with my own actual iPhone device and occasionally with an Android emulator, but this was a good lesson for me that I should always check the operation with an actual Android device as well.

Click here for an article on setting up a Flutter app to run on an actual Android device.

Copied title and URL