'Flutter - Disable navigation InAppWebView

I'm new to Flutter, and I want to put a web view between other widgets and I'm using the InAppWebView flutter in order to do it, but I want to prevent the user to navigate to other pages when he clicks on a button inside the web view. Do I have to write some native code for iOS and Android to prevent the navigation?

Thanks



Solution 1:[1]

something like that:

InAppWebView(
....
 shouldOverrideUrlLoading: (controller, navigationAction) async {
  final uri = navigationAction.request.url!;
  if(whitenAvigationHosts.contains(uri.host)){
    return NavigationActionPolicy.ALLOW;
  }
  return NavigationActionPolicy.CANCEL;
})
                

Solution 2:[2]

For disable navigate user to another page you can use onPageCommitVisible call back to determine the user is click on url that redirect to another one, so just call goBack inside it

 InAppWebView(
        onPageCommitVisible: (con,uri){
          print("url ${uri.toString()}");
          con.goBack();
        },

      ),

Solution 3:[3]

Since you are using InAppWebView package you can intercept each URL the Webview would navigate to before it is actually navigate and then make a decision of whether to navigate or not using the callback shouldOverrideUrlLoading like the following:

shouldOverrideUrlLoading: (controller, navigationAction) async {
    // You can access the URL like this
    final url = navigationAction.request.url.toString();

    if (condition) {
        // This one means do not navigate
        return NavigationActionPolicy.CANCEL;
    }

    // This one means navigate
    return NavigationActionPolicy.ALLOW;
},

Note that to use the callback shouldOverrideUrlLoading, you have to enable it in the initialOptions of the webview like the following because the default is false:

initialOptions: InAppWebViewGroupOptions(
    crossPlatform: InAppWebViewOptions(
        useShouldOverrideUrlLoading: true,
    ),
),

Solution 4:[4]

You can prevent navigation in webview through navigation delegate property like following:

WebView(
        debuggingEnabled: true,
        initialUrl: _currentURL,
        onWebViewCreated: (controller) {
          _controller = controller;
          return _controller;
        },
        onPageFinished: (url) {
          if (url.contains(ConstUtils.course)) {
            updateProfile();
          }
        },
        navigationDelegate: (navigation) => NavigationDecision.prevent,
        onWebResourceError: (error) {
          NavigationUtils(context).popCurrentPage();
        },
        onPageStarted: (url) {
          
        },
        javascriptMode: JavascriptMode.unrestricted,
      ),

Solution 5:[5]

Disable navigation InAppWebView:-

we have onUpdateVisitedHistory property in Inappwebview widget.Using this onUpdateVisitedHistory property we can listen url changes in the Inappwebview widget.So disable navigation we can use webcontroller.goback() method.

widget code:

InAppWebView(
              key: webViewKey,
              onWebViewCreated: (controller) {
                webViewController = controller;
                _loadHtmlFromAssets();
              },
              onUpdateVisitedHistory: (controller, url, androidIsReload) {
                if (url!.host.contains("google.com")) {
                  webViewController?.goBack();
                  //You can do anything
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen1()),
                  );
                  //Prevent that url works
                  return;
                } else if (url.host.contains("yahoo.com")) {
                  //You can do anything
                  webViewController?.goBack();
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen3()),
                  );
                  //Prevent that url works
                  return;
                } else if (url.host.contains("duckduckgo.com")) {
                  //You can do anything
                  webViewController?.goBack();
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen2()),
                  );
                }
              })

enter image description here

Here we skipping loading the search engine and jump to other widget

nb: if we did'nt add webcontroller.goback().it will load site and move to the widget .if we back pressed it will show webpage.

sampleCode:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  WebViewController? _controller;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
  late PullToRefreshController pullToRefreshController;
  InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
      crossPlatform: InAppWebViewOptions(
        useShouldOverrideUrlLoading: true,
        mediaPlaybackRequiresUserGesture: false,
      ),
      android: AndroidInAppWebViewOptions(
        useHybridComposition: true,
      ),
      ios: IOSInAppWebViewOptions(
        allowsInlineMediaPlayback: true,
      ));

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

    pullToRefreshController = PullToRefreshController(
      options: PullToRefreshOptions(
        color: Colors.blue,
      ),
      onRefresh: () async {
        if (Platform.isAndroid) {
          webViewController?.reload();
        } else if (Platform.isIOS) {
          webViewController?.loadUrl(
              urlRequest: URLRequest(url: await webViewController?.getUrl()));
        }
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            webViewController?.goBack();
          },
          child: Icon(Icons.arrow_back),
        ),
        appBar: AppBar(
          backgroundColor: Colors.black87,
          title: Text(widget.title),
        ),
        body: Center(
          child: InAppWebView(
              key: webViewKey,
              onWebViewCreated: (controller) {
                webViewController = controller;
                _loadHtmlFromAssets();
              },
              onUpdateVisitedHistory: (controller, url, androidIsReload) {
                if (url!.host.contains("google.com")) {
                  webViewController?.goBack();
                  //You can do anything
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen1()),
                  );
                  //Prevent that url works
                  return;
                } else if (url.host.contains("yahoo.com")) {
                  //You can do anything
                  webViewController?.goBack();
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen3()),
                  );
                  //Prevent that url works
                  return;
                } else if (url.host.contains("duckduckgo.com")) {
                  //You can do anything
                  webViewController?.goBack();
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => const Screen2()),
                  );
                }
              }),
        ));
  }

  _loadHtmlFromAssets() {
    var fileText =
        "<!DOCTYPE html> <html> <head> <title>HTML, CSS and JavaScript demo</title> <style> .rotate { transform: rotate(1700deg) ; } .rotate2 { transform: rotate(90deg) ; } .bg { background: url(https://picsum.photos/2000/1000?image=1069) center/cover; height: 50vh; width: 50vh; } body { margin:0; overflow:hidden; } </style> </head> "
        "<!-- Start your code here --> <ul> <li> <a href ='http://duckduckgo.com/' /><p> duckduckgo.com</a> </li>  <li> <a href='http://www.google.com'>google.com </a> </li>    <li> <a href='http://www.yahoo.com/'> yahoo.com </a> </li></ul> </html>";
    // return Uri.dataFromString(fileText,
    //         mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
    //     .toString();
    webViewController!.loadUrl(
        urlRequest: URLRequest(
            url: new Uri.dataFromString(fileText, mimeType: 'text/html')));

    // _controller?.loadUrl(Uri.dataFromString(fileText,
    //         mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
    //     .toString());
  }
}

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

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class Screen1 extends StatelessWidget {
  const Screen1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Text("Screen 1 google.com"),
      ),
    );
  }
}

class Screen2 extends StatelessWidget {
  const Screen2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: MaterialApp(
        home: Container(
          child: Text("Screen 2 yahoo.com"),
        ),
      ),
    );
  }
}

class Screen3 extends StatelessWidget {
  const Screen3({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Text("Screen 3 duck.com"),
      ),
    );
  }
}

Disable navigation in Webview Widget:

We can use navigationDelegate to monitor url changes in webview.NavigationDecision.prevent will block jump to website

WebView(
      // initialUrl: 'https://flutter.dev',
      onWebViewCreated: (WebViewController webViewController) {
        _controller = webViewController;
        _loadHtmlFromAssets();
      },
      navigationDelegate: (NavigationRequest request) {
        if (request.url.contains("google.com")) {
          //You can do anything
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Screen1()),
          );
          //Prevent that url works
          return NavigationDecision.prevent;
        } else if (request.url.contains("yahoo.com")) {
          //You can do anything
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Screen1()),
          );
          //Prevent that url works
          return NavigationDecision.prevent;
        } else if (request.url.contains("duckduckgo.com")) {
          //You can do anything
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Screen3()),
          );
          //Prevent that url works
          return NavigationDecision.prevent;
        }
        //Any other url works
        return NavigationDecision.navigate;
      },
    );

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marcelo Juan Cabrera Gutierrez
Solution 2 Mahmoud Abu Alheja
Solution 3 Moaz El-sawaf
Solution 4 Jay Dangar
Solution 5 lava