Introduction.
Developing “Mia,” a talking cat-shaped robot that speaks in various dialects.
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.
/// 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.
_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)
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
.
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.