2

I'm using webview_flutter to view a page from the URL on my Flutter application, what I need to do is to detect when changes happen in the HTML code without changing the URL. as there is some data changing overtime using JS and I need to check for HTML and fetch some data out of it whenever it changes, without the need to use any of

 void Function(String)? onPageStarted,
  void Function(String)? onPageFinished,
  void Function(int)? onProgress,

because the page is not reloading or the URL is not changing, everything is the same but the HTML code. here is what the Web view looks like:

WebView(
                            gestureRecognizers: <
                                Factory<OneSequenceGestureRecognizer>>{
                              Factory<VerticalDragGestureRecognizer>(
                                  () => VerticalDragGestureRecognizer()),
                              Factory<HorizontalDragGestureRecognizer>(
                                  () => HorizontalDragGestureRecognizer()),
                              Factory<ScaleGestureRecognizer>(
                                  () => ScaleGestureRecognizer()),
                            },
                            zoomEnabled: true,
                            debuggingEnabled: true,
                            initialUrl: controller.mapURL.value,
                            javascriptMode: JavascriptMode.unrestricted,
                            onWebViewCreated:
                                (WebViewController webViewController) {
                              controller.mapWebViewController =
                                  webViewController;
                            },
                          ),

and here is how to get the HTML content

                              var html = await controller.mapWebViewController!
                                  .evaluateJavascript(
                                      "window.document.getElementsByTagName('html')[0].outerHTML;");
                              print(HTML);

Ahmed Wagdi
  • 3,913
  • 10
  • 50
  • 116

1 Answers1

2

I somewhat managed to do this by injecting some JavaScript of my own into the webpage and having it send back a message whenever the desired action occur on the page.

In my scenario, I wanted to get notified when a success alert shows up on the web page. I added an event listener for DOMSubtreeModified that gets triggered whenever there's a change in the HTML document.

First I create a Javascript channel on the Flutter side. When the page finishes loading, using the runJavascript method, I inject the JavaScript snippet.

Now when that alert showed up on the page, the listener functions detects that and send a message back to Flutter using the postMessage method.

class _MyWebViewState extends State<MyWebView> {
  final Completer<WebViewController> _controller =
      Completer<WebViewController>();

  @override
  void initState() {
    if (Platform.isAndroid) {
      WebView.platform = SurfaceAndroidWebView();
    }

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        FutureBuilder<WebViewController>(
          future: _controller.future,
          builder: (context, snapshot) {
            return WebView(
              initialUrl: widget._buildUrl(),
              javascriptMode: JavascriptMode.unrestricted,
              javascriptChannels: _createJavaScriptChannels(context),
              onWebViewCreated: (webViewController) {
                _controller.complete(webViewController);
              },
              onPageFinished: (url) {
                if (snapshot.hasData) {
                  snapshot.data!.runJavascript(js);
                }
              },
            );
          },
        ),
      ],
    );
  }

  Set<JavascriptChannel> _createJavaScriptChannels(BuildContext context) {
    return {
      JavascriptChannel(
        name: 'MobileApp',
        onMessageReceived: (message) {
            if (message.message == 'success') {
              ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text(message.message)),
            );
          }
        },
      ),
    };
  }
}

String js = '''    
document.addEventListener("DOMSubtreeModified", onDetection);

function onDetection() {
  const successAlertExists =
    document.querySelectorAll("div.alert-success").length > 0;
  if (successAlertExists) {
    MobileApp.postMessage("success");
    
    document.removeEventListener("DOMSubtreeModified", onDetection);
  }
}
''';
Isuru
  • 30,617
  • 60
  • 187
  • 303
  • can u check this once? https://stackoverflow.com/questions/73031132/get-the-edited-html-content-in-flutter-inappwebview-using-inner-html – Sunisha Guptan Jul 20 '22 at 12:37
  • I don't have much knowledge in javascript. So got confused . Am loading as HTML content only..so am not able to detect that. My use case: I have a webView inside flutter app. Webview renders a HTML content. Page contains html textfields and radio buttons, checkboxes. I want to receive the changes of HTML when we click on submit button. Note: The HTML content is getting from backend. And it's dynamic, so to add onClick in each textfield, radio, checkbox it's not practical. And the same HTML web also using. – Sunisha Guptan Jul 20 '22 at 13:09
  • 1
    It's done. I will update in my question also. But ur answer helped me. Thanks. – Sunisha Guptan Jul 20 '22 at 19:48
  • @SunishaSindhu Glad to hear. – Isuru Jul 23 '22 at 07:02