Ganger
Ganger

Reputation: 101

Flutter WebviewPlugin remove header and footer of website

By implementation of FlutterWebviewPlugin, I want to show a particular website in a widget but without header and footer. is this possible in Flutter? I guess there is a function in FlutterWebviewPlugin class .evalJavascript('some code') but don't know how to use this function. can I add javascript code to this?

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

String url = "https://flutter.io/";

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Webview Example',
      theme: ThemeData.dark(),
      routes: {
        "/": (_) => Home(),
        "/webview": (_) => WebviewScaffold(
          url: url,
          withJavascript: true,
          withLocalStorage: true,
          withZoom: true,
        )
      },
    );
  }
}

class Home extends StatefulWidget {
  @override
  HomeState createState() => HomeState();
}

class HomeState extends State<Home> {
  final webView = FlutterWebviewPlugin();
  TextEditingController controller = TextEditingController(text: url);

  @override
  void initState() {
    super.initState();
    webView.close();
    controller.addListener(() {
      url = controller.text;
    });
  }
  @override
  void dispose() {
    webView.dispose();
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("WebView"),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              Container(
                padding: EdgeInsets.all(10.0),
                child: TextField(
                  controller: controller,
                ),
              ),
              RaisedButton(
                child: Text("Open Webview"),
                onPressed: () {

                  Navigator.of(context).pushNamed("/webview");
                },
              )
            ],
          ),
        )
    );
  }
}

Upvotes: 6

Views: 9802

Answers (4)

avishak chakroborty
avishak chakroborty

Reputation: 312

Lorenzo's answer answer didn't work for me well. The element always returned null. So here's can be a possible solution:

onLoadStop{
  _webViewController.evaluateJavascript(
  source:"
     var main = document.querySelector('#__next'); 
     var header = main.querySelector('.sc-FTTUS.jnFTCj'); 
     var footer = document.getElementsByTagName('footer')[0];
     header.remove(); 
     footer.remove()"
);
}

using such nested locator,it worked well.

Upvotes: 0

Lorenzo Pichilli
Lorenzo Pichilli

Reputation: 3439

You can use the flutter_inappwebview plugin (I'm the author) and inject an UserScript at UserScriptInjectionTime.AT_DOCUMENT_START to hide or remove HTML elements when the web page loads (check JavaScript - User Scripts official docs for User Scripts details).

As I have already answered here for a similar issue, here is a code example using the current latest version 6 (6.0.0-beta.18) with URL https://getmobie.de/impressum that removes the header and footer HTML elements:

import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  if (!kIsWeb &&
      kDebugMode &&
      defaultTargetPlatform == TargetPlatform.android) {
    await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
  }
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("InAppWebView test"),
        ),
        body: Column(children: <Widget>[
          Expanded(
            child: InAppWebView(
              key: webViewKey,
              initialUrlRequest:
                  URLRequest(url: WebUri("https://getmobie.de/impressum")),
              initialUserScripts: UnmodifiableListView([
                UserScript(source: """
                window.addEventListener('DOMContentLoaded', function(event) {
                  var header = document.querySelector('.elementor-location-header'); // use here the correct CSS selector for your use case
                  if (header != null) {
                    header.remove(); // remove the HTML element. Instead, to simply hide the HTML element, use header.style.display = 'none';
                  }
                  var footer = document.querySelector('.elementor-location-footer'); // use here the correct CSS selector for your use case
                  if (footer != null) {
                    footer.remove(); // remove the HTML element. Instead, to simply hide the HTML element, use footer.style.display = 'none';
                  }
                });
                """, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START)
              ]),
              onWebViewCreated: (controller) {
                webViewController = controller;
              },
            ),
          ),
        ]));
  }
}

For your use case, use the right CSS selector inside the user script js source to correctly get and remove the header and footer HTML elements from your web page!

Android example iOS example

Upvotes: 3

Koek
Koek

Reputation: 131

_webViewController.runJavascript(
          "document.getElementsByTagName('header')[0].style.display='none'");
      _webViewController.runJavascript(
          "document.getElementsByTagName('footer')[0].style.display='none'");

Upvotes: 6

Omatt
Omatt

Reputation: 10559

I suggest using Flutter's official WebView plugin: webview_flutter

The plugin also has a method that can run Javascript using WebViewController.evaluateJavascript(String). This method is recommended to be run after WebView.onPageFinished callback.

Your WebView widget should look like this.

WebView(
    initialUrl: 'https://flutter.dev',
    javascriptMode: JavascriptMode.unrestricted,
    onWebViewCreated: (WebViewController webViewController) {
      _webViewController = webViewController;
      _controller.complete(webViewController);
    },
    onProgress: (int progress) {
      print("WebView is loading (progress : $progress%)");
    },
    onPageStarted: (String url) {
      print('Page started loading: $url');
    },
    onPageFinished: (String url) {
      print('Page finished loading: $url');

      // Removes header and footer from page
      _webViewController
          .evaluateJavascript("javascript:(function() { " +
              "var head = document.getElementsByTagName('header')[0];" +
              "head.parentNode.removeChild(head);" +
              "var footer = document.getElementsByTagName('footer')[0];" +
              "footer.parentNode.removeChild(footer);" +
              "})()")
          .then((value) => debugPrint('Page finished loading Javascript'))
          .catchError((onError) => debugPrint('$onError'));
      },
);

Here's a complete sample that you can try.

import 'dart:async';

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  final Completer<WebViewController> _controller =
      Completer<WebViewController>();

  WebViewController _webViewController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Builder(builder: (BuildContext context) {
        return WebView(
          initialUrl: 'https://flutter.dev',
          javascriptMode: JavascriptMode.unrestricted,
          onWebViewCreated: (WebViewController webViewController) {
            _webViewController = webViewController;
            _controller.complete(webViewController);
          },
          onProgress: (int progress) {
            print("WebView is loading (progress : $progress%)");
          },
          javascriptChannels: <JavascriptChannel>{
            _toasterJavascriptChannel(context),
          },
          navigationDelegate: (NavigationRequest request) {
            if (request.url.startsWith('https://www.youtube.com/')) {
              print('blocking navigation to $request}');
              return NavigationDecision.prevent;
            }
            print('allowing navigation to $request');
            return NavigationDecision.navigate;
          },
          onPageStarted: (String url) {
            print('Page started loading: $url');
          },
          onPageFinished: (String url) {
            print('Page finished loading: $url');

            _webViewController
                .evaluateJavascript("javascript:(function() { " +
                    "var head = document.getElementsByTagName('header')[0];" +
                    "head.parentNode.removeChild(head);" +
                    "var footer = document.getElementsByTagName('footer')[0];" +
                    "footer.parentNode.removeChild(footer);" +
                    "})()")
                .then((value) => debugPrint('Page finished loading Javascript'))
                .catchError((onError) => debugPrint('$onError'));
          },
          gestureNavigationEnabled: true,
        );
      }),
    );
  }

  JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
    return JavascriptChannel(
        name: 'Toaster',
        onMessageReceived: (JavascriptMessage message) {
          // ignore: deprecated_member_use
          Scaffold.of(context).showSnackBar(
            SnackBar(content: Text(message.message)),
          );
        });
  }
}

How the app looks running

demo

Upvotes: 10

Related Questions