💉Injecting JavaScript in Flutter WebView — A Complete Guide 📖

💉Injecting JavaScript in Flutter WebView — A Complete Guide 📖

FlutterPulse

This article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Flutter's webview_flutter is powerful for embedding web content, but sometimes you need more than just loading a page.

👉 What if you want to:

  • Capture form input values (like username or email)?
  • Modify DOM elements dynamically?
  • Add custom click listeners?
  • Communicate between the web page and Flutter?

This is where JavaScript injection comes in.

In this guide, we'll learn how to inject JavaScript into a WebView, capture values, and send them back to Flutter.

📦 Adding webview_flutter

To get started, add the package to your pubspec.yaml:

dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.8.0

(Always check pub.dev for the latest version.)

webview_flutter | Flutter package

A Flutter plugin that provides a WebView widget backed by the system webview.

pub.dev

⚙️ Setting Up WebView

First, let's set up a WebView with unrestricted JavaScript enabled:

final WebViewController controller =
WebViewController.fromPlatformCreationParams(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("Captured from WebView: ${message.message}");
},
)
..loadRequest(Uri.parse("https://example.com/login"));

Here, we've created a JavaScript channel (FormChannel) that acts like a "bridge" between JavaScript and Flutter.

🧑‍💻 Injecting JavaScript

Now, let's inject some JavaScript when the page finishes loading:

Future<void> _injectCustomHook() async {
await _controller.runJavaScript('''
(function() {
const loginButton = document.querySelector('button[type="submit"]');
if (loginButton) {
loginButton.addEventListener('click', function() {
const input = document.getElementById('username')?.value || '';
FormChannel.postMessage(input);
});
}
})();
''');
}

🔍 What this code does

  • Finds the login button inside the WebView.
  • Listens for the click event.
  • Reads the input field with ID username.
  • Sends it back to Flutter using the FormChannel.

📥 Receiving the Data in Flutter

The data flows back into Flutter via the JavaScript channel:

..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("User typed: ${message.message}");
// Use the value in your app
},
)

If the user types hello@example.com in the web form, Flutter will print the following in the console :

User typed: hello@example.com

🚀 Why JavaScript Injection Is Powerful

With JS injection, you can:

  • Capture input values before they are submitted.
  • Automatically fill forms.
  • Hide or restyle unwanted elements.
  • Add extra functionality to existing web pages.

Example: Hide a banner inside the WebView

await _controller.runJavaScript('''
document.querySelector('.ads-banner')?.style.display = 'none';
''');

đź§© Final Reference Code

Here's a complete reference combining WebView setup, JavaScript injection, and data capture:

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

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

@override
State<WebViewExample> createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State<WebViewExample> {
late final WebViewController _controller;

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

final params = const PlatformWebViewControllerCreationParams();
final controller = WebViewController.fromPlatformCreationParams(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (url) {
_injectCustomHook();
},
),
)
..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("Captured from WebView: ${message.message}");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("User typed: ${message.message}")),
);
},
)
..loadRequest(Uri.parse("https://example.com/login"));

_controller = controller;
}

Future<void> _injectCustomHook() async {
await _controller.runJavaScript('''
(function() {
const loginButton = document.querySelector('button[type="submit"]');
if (loginButton) {
loginButton.addEventListener('click', function() {
const input = document.getElementById('username')?.value || '';
FormChannel.postMessage(input);
});
}
})();
''');
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("WebView JS Injection")),
body: WebViewWidget(controller: _controller),
);
}
}

🔄 Alternatives

While webview_flutter supports basic JS injection, other packages offer more:

  1. flutter_inappwebview
flutter_inappwebview | Flutter package

A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser…

pub.dev

Advanced JS injection, network request interception, cookie management and Best choice if you need deep control of the page.

2. flutter_web_auth_2

flutter_web_auth_2 | Flutter package

Flutter plugin for authenticating a user with a web service.

pub.dev

Opens the system browser instead of injecting JS and Great for OAuth flows.

âś… Best Practices

  • Always sanitize and validate data captured from injected JavaScript.
  • Test on multiple platforms (Android & iOS behave slightly differently).
  • Avoid overusing JS injection — use it only when Flutter's native APIs or backend APIs can't achieve the same.

🔥Conclusion

JavaScript injection is like giving your Flutter WebView superpowers💪. Next time you embed a web page in Flutter, don't just display it — inject your own logic and make it smarter!

Report Page