What is 
flutter_inappwebviewSo, what’s the difference between 
webview_flutterflutter_webview_pluginCompared to all other WebView plugins, it is feature-rich: a lot of events, methods, and options to control WebViews. Furthermore, they do not have good documentation about their API or, at least, it is not complete. Instead, every feature of 
flutter_inappwebviewIn this article, I’m going to present the main classes and some examples of the 
InAppWebViewMain Classes Overview
This is a list of the main classes that the plugin offers:
- InAppWebView: Flutter Widget for adding an inline native WebView integrated into the flutter widget tree.
- ContextMenu: This class represents the WebView context menu.
- HeadlessInAppWebView: Class that represents a WebView in headless mode. It can be used to run a WebView in background without attaching an 
 to the widget tree.InAppWebView
- InAppBrowser: In-App Browser using native WebView.
- ChromeSafariBrowser: In-App Browser using Chrome Custom Tabs on Android / SFSafariViewController on iOS.
- InAppLocalhostServer: This class allows you to create a simple server on 
 . The defaulthttp://localhost:[port]/
 value isport
 .8080
- CookieManager: This class implements a singleton object (shared instance) which manages the cookies used by WebView instances.
- HttpAuthCredentialDatabase: This class implements a singleton object (shared instance) that manages the shared HTTP auth credentials cache.
- WebStorageManager: This class implements a singleton object (shared instance) which manages the web storage used by WebView instances.
In this article, I’m going to show in particular the 
InAppWebViewInAppWebView is a Widget like any other!
Adding the 
InAppWebViewInAppWebView(initialUrl: 'https://github.com/flutter')NOTE: To use it on iOS, you need to opt-in for the embedded views preview by adding a boolean property to the app's 
Info.plistio.flutter.embedded_views_previewYESThis widget has a set of initial attributes that you can use to initialize the WebView:
- initialUrl: Initial URL that will be loaded;
- initialOptions: Initial WebView options that will be used;
- gestureRecognizers: specifies which gestures should be consumed by the WebView;
- initialData: Initial InAppWebViewInitialData that will be loaded, such as an HTML string;
- initialFile: Initial asset file that will be loaded (check the “Load a file inside assets folder” Section);
- initialHeaders: Initial headers that will be used;
- contextMenu: Context menu which contains custom menu items.
The list of all available WebView options is quite long, for example, you can enable/disable JavaScript using the 
javascriptEnabledcacheEnabledUse InAppWebViewController to control your WebView
Instead, to control the WebView, you have the 
InAppWebViewController onWebViewCreatedThrough it, you can control your WebView or access its properties, such as the current URL using 
getUrlloadUrlpostUrlevaluateJavascripttakeScreenshotgetCertificatenullThe full list of all methods you can use is quite long and available here.
InAppWebView Events
The 
InAppWebView- onLoadStart: event fired when the WebView starts to load an URL;
- onLoadStop: event fired when the WebView finishes loading an URL;
- onLoadHttpError: event fired when the WebView main page receives an HTTP error;
- onConsoleMessage: event fired when the WebView receives a JavaScript console message (such as 
 ,console.log
 , etc.);console.error
- shouldOverrideUrlLoading: gives the host application a chance to take control when a URL is about to be loaded in the current WebView;
- onDownloadStart: event fired when WebView recognizes a downloadable file;
- onReceivedHttpAuthRequest: event fired when the WebView received an HTTP authentication request. The default behavior is to cancel the request;
- onReceivedServerTrustAuthRequest: event fired when the WebView need to perform server trust authentication (certificate validation);
- onPrint: event fired when 
 is called from JavaScript side;window.print()
- onCreateWindow: event fired when the InAppWebView requests the host application to create a new window, for example when trying to open a link with 
 or whentarget="_blank"
 is called by JavaScript side;window.open()
and many many more! I recommend checking the API Reference to get more details. As for the WebView options and methods, the full list of all WebView events is quite long and available here.
InAppWebView Simple Example
Here is a simple example that shows an InAppWebView widget, its current URL, and 3 buttons: one to go back, one to go forward, and another one to reload the current page.
This is the full code example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(new MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  InAppWebViewController _webViewController;
  String url = "";
  double progress = 0;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: Container(
            child: Column(children: <Widget>[
              Container(
                padding: EdgeInsets.all(20.0),
                child: Text(
                    "CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) + "..." : url}"),
              ),
              Container(
                  padding: EdgeInsets.all(10.0),
                  child: progress < 1.0
                      ? LinearProgressIndicator(value: progress)
                      : Container()),
              Expanded(
                child: Container(
                  margin: const EdgeInsets.all(10.0),
                  decoration:
                  BoxDecoration(border: Border.all(color: Colors.blueAccent)),
                  child: InAppWebView(
                    initialUrl: "https://flutter.dev/",
                    initialOptions: InAppWebViewGroupOptions(
                        crossPlatform: InAppWebViewOptions(
                          debuggingEnabled: true,
                        )
                    ),
                    onWebViewCreated: (InAppWebViewController controller) {
                      _webViewController = controller;
                    },
                    onLoadStart: (InAppWebViewController controller, String url) {
                      setState(() {
                        this.url = url;
                      });
                    },
                    onLoadStop: (InAppWebViewController controller, String url) async {
                      setState(() {
                        this.url = url;
                      });
                    },
                    onProgressChanged: (InAppWebViewController controller, int progress) {
                      setState(() {
                        this.progress = progress / 100;
                      });
                    },
                  ),
                ),
              ),
              ButtonBar(
                alignment: MainAxisAlignment.center,
                children: <Widget>[
                  RaisedButton(
                    child: Icon(Icons.arrow_back),
                    onPressed: () {
                      if (_webViewController != null) {
                        _webViewController.goBack();
                      }
                    },
                  ),
                  RaisedButton(
                    child: Icon(Icons.arrow_forward),
                    onPressed: () {
                      if (_webViewController != null) {
                        _webViewController.goForward();
                      }
                    },
                  ),
                  RaisedButton(
                    child: Icon(Icons.refresh),
                    onPressed: () {
                      if (_webViewController != null) {
                        _webViewController.reload();
                      }
                    },
                  ),
                ],
              ),
            ])),
      ),
    );
  }
}JavaScript Handlers (Channels)
You can communicate with the JavaScript side and vice-versa. 
To add a JavaScript handler, you can use 
_webViewController.addJavaScriptHandler handlerNamecallbackcallbackInstead, on the JavaScript side, to execute the callback handler and send data to Flutter, you need to use 
window.flutter_inappwebview.callHandler(handlerName <String>, ...args)handlerNameargsIn order to call 
window.flutter_inappwebview.callHandler(handlerName <String>, ...args)flutterInAppWebViewPlatformReadyThis event will be dispatched as soon as the platform (Android or iOS) is ready to handle the 
callHandlerHere is an example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(new MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  InAppWebViewController _webViewController;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                child:InAppWebView(
                    initialData: InAppWebViewInitialData(
                      data: """
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    </head>
    <body>
        <h1>JavaScript Handlers (Channels) TEST</h1>
        <script>
            window.addEventListener("flutterInAppWebViewPlatformReady", function(event) {
                window.flutter_inappwebview.callHandler('handlerFoo')
                  .then(function(result) {
                    // print to the console the data coming
                    // from the Flutter side.
                    console.log(JSON.stringify(result));
                    
                    window.flutter_inappwebview
                      .callHandler('handlerFooWithArgs', 1, true, ['bar', 5], {foo: 'baz'}, result);
                });
            });
        </script>
    </body>
</html>
                      """
                    ),
                    initialOptions: InAppWebViewGroupOptions(
                        crossPlatform: InAppWebViewOptions(
                          debuggingEnabled: true,
                        )
                    ),
                    onWebViewCreated: (InAppWebViewController controller) {
                      _webViewController = controller;
                      _webViewController.addJavaScriptHandler(handlerName:'handlerFoo', callback: (args) {
                        // return data to JavaScript side!
                        return {
                          'bar': 'bar_value', 'baz': 'baz_value'
                        };
                      });
                      _webViewController.addJavaScriptHandler(handlerName: 'handlerFooWithArgs', callback: (args) {
                        print(args);
                        // it will print: [1, true, [bar, 5], {foo: baz}, {bar: bar_value, baz: baz_value}]
                      });
                    },
                    onConsoleMessage: (controller, consoleMessage) {
                      print(consoleMessage);
                      // it will print: {message: {"bar":"bar_value","baz":"baz_value"}, messageLevel: 1}
                    },
                ),
              ),
            ])),
      ),
    );
  }
}WebRTC in InAppWebView
At this moment, WebRTC is supported only on Android, because, unfortunately, on iOS 
WKWebViewI’m going to show an example using https://appr.tc/ to test WebRTC feature. It’s a video chat demo app based on WebRTC (https://github.com/webrtc/apprtc).
To request permissions about the camera and microphone, you can use the permission_handler plugin. Also, you need to set the WebView option 
mediaPlaybackRequiresUserGesturefalseFurthermore, on Android, you need to implement the 
androidOnPermissionRequestIn this case, this event is used to grant permissions for the WebRTC API. Also, you need to add these permissions in the 
AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />Here is the full code example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:permission_handler/permission_handler.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Permission.camera.request();
  await Permission.microphone.request();
  runApp(MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: InAppWebViewPage()
    );
  }
}
class InAppWebViewPage extends StatefulWidget {
  @override
  _InAppWebViewPageState createState() => new _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> {
  InAppWebViewController _webViewController;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("InAppWebView")
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                child: Container(
                  child: InAppWebView(
                      initialUrl: "https://appr.tc/r/704328056",
                      initialOptions: InAppWebViewGroupOptions(
                        crossPlatform: InAppWebViewOptions(
                          mediaPlaybackRequiresUserGesture: false,
                          debuggingEnabled: true,
                        ),
                      ),
                      onWebViewCreated: (InAppWebViewController controller) {
                        _webViewController = controller;
                      },
                      androidOnPermissionRequest: (InAppWebViewController controller, String origin, List<String> resources) async {
                        return PermissionRequestResponse(resources: resources, action: PermissionRequestResponseAction.GRANT);
                      }
                  ),
                ),
              ),
            ]))
    );
  }
}How to enable download files in InAppWebView
InAppWebViewuseOnDownloadStart: trueonDownloadStartOn Android you need to add write permission inside your 
AndroidManifest.xml<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />Then, you need to ask permission using the permission_handler plugin. Instead, to effectively download your file, you can use the flutter_downloader plugin.
Here is a complete example using http://ovh.net/files/ (in particular, the http://ovh.net/files/1Mio.dat as URL) to test the download:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterDownloader.initialize(
      debug: true // optional: set false to disable printing logs to console
  );
  await Permission.storage.request();
  runApp(MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  InAppWebViewController _webViewController;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                  child: InAppWebView(
                    initialUrl: "http://ovh.net/files/1Mio.dat",
                    initialOptions: InAppWebViewGroupOptions(
                      crossPlatform: InAppWebViewOptions(
                          debuggingEnabled: true,
                          useOnDownloadStart: true
                      ),
                    ),
                    onWebViewCreated: (InAppWebViewController controller) {
                      _webViewController = controller;
                    },
                    onDownloadStart: (controller, url) async {
                      print("onDownloadStart $url");
                      final taskId = await FlutterDownloader.enqueue(
                        url: url,
                        savedDir: (await getExternalStorageDirectory()).path,
                        showNotification: true, // show download progress in status bar (for Android)
                        openFileFromNotification: true, // click on notification to open downloaded file (for Android)
                      );
                    },
                  ))
            ])),
      ),
    );
  }
}As you can see, I’m using also the path_provider plugin to get the folder where I want to save the file.
Allow Self-signed SSL Certificates
To allow self-signed SSL certificates, you can use the 
onReceivedServerTrustAuthRequest onReceivedServerTrustAuthRequest: (controller, challenge) async {
  return ServerTrustAuthResponse(action: ServerTrustAuthResponseAction.PROCEED);
},How to manage popup windows opened with target=”_blank” or “window.open”
To manage popup windows when a user clicks on a link with 
target="_blank" window.openonCreateWindowsupportMultipleWindowstrueAlso, in order to be able to allow the usage of JavaScript, you need to set the 
javaScriptCanOpenWindowsAutomaticallytrueIf you want to manage these requests, you should return 
truefalseThe 
CreateWindowRequestwindowIdInAppWebViewwindowIdAlso, 
CreateWindowRequesturlwindow.opennullwindow.openwindow.close windowIdurlHere is a simple example that shows an 
AlertDialogimport 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(new MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: InAppWebViewPage()
    );
  }
}
class InAppWebViewPage extends StatefulWidget {
  @override
  _InAppWebViewPageState createState() => new _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> {
  InAppWebViewController _webViewController;
  InAppWebViewController _webViewPopupController;
  @override
  void initState() {
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('InAppWebView Example'),
        ),
        body: SafeArea(
          child: Container(
              child: InAppWebView(
                initialData: InAppWebViewInitialData(
                    data: """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Flutter InAppWebView</title>
</head>
<body>
  <a style="margin: 50px; background: #333; color: #fff; font-weight: bold; font-size: 20px; padding: 15px; display: block;"
    href="https://github.com/flutter"
    target="_blank">
    Click here to open https://github.com/flutter in a popup!
  </a>
</body>
</html>
"""
                ),
                initialOptions: InAppWebViewGroupOptions(
                    crossPlatform: InAppWebViewOptions(
                      debuggingEnabled: true,
                      // set this to true if you are using window.open to open a new window with JavaScript
                      javaScriptCanOpenWindowsAutomatically: true
                    ),
                    android: AndroidInAppWebViewOptions(
                      // on Android you need to set supportMultipleWindows to true,
                      // otherwise the onCreateWindow event won't be called
                      supportMultipleWindows: true
                    )
                ),
                onWebViewCreated: (InAppWebViewController controller) {
                  _webViewController = controller;
                },
                onCreateWindow: (controller, createWindowRequest) async {
                  print("onCreateWindow");
                  showDialog(
                    context: context,
                    builder: (context) {
                      return AlertDialog(
                        content: Container(
                          width: MediaQuery.of(context).size.width,
                          height: 400,
                          child: InAppWebView(
                            // Setting the windowId property is important here!
                            windowId: createWindowRequest.windowId,
                            initialOptions: InAppWebViewGroupOptions(
                                crossPlatform: InAppWebViewOptions(
                                    debuggingEnabled: true,
                                ),
                            ),
                            onWebViewCreated: (InAppWebViewController controller) {
                              _webViewPopupController = controller;
                            },
                            onLoadStart: (InAppWebViewController controller, String url) {
                              print("onLoadStart popup $url");
                            },
                            onLoadStop: (InAppWebViewController controller, String url) {
                              print("onLoadStop popup $url");
                            },
                          ),
                        ),
                      );
                    },
                  );
                  return true;
                },
              ),
            ),
          ),
      ),
    );
  }
}Manage platform URLs such as whatsapp:, fb:, tel:, mailto:, etc.
Generally, a WebView knows nothing on how to manage 
whatsapp:tel: fb:shouldOverrideUrlLoadinguseShouldOverrideUrlLoading: trueThis way you can cancel the request made for the WebView and, instead, open the App, for example, using the 
url_launcherinitialOptions: InAppWebViewGroupOptions(
  crossPlatform: InAppWebViewOptions(
      debuggingEnabled: true,
      useShouldOverrideUrlLoading: true
  ),
),
shouldOverrideUrlLoading: (controller, request) async {
  var url = request.url;
  var uri = Uri.parse(url);
  if (!["http", "https", "file",
    "chrome", "data", "javascript",
    "about"].contains(uri.scheme)) {
    if (await canLaunch(url)) {
      // Launch the App
      await launch(
        url,
      );
      // and cancel the request
      return ShouldOverrideUrlLoadingAction.CANCEL;
    }
  }
  return ShouldOverrideUrlLoadingAction.ALLOW;
},Manage WebView Cookies
To manage WebView cookies, you can use the 
CookieManagerHere is an example of how to set a cookie:
CookieManager _cookieManager = CookieManager.instance();
final expiresDate =
    DateTime.now().add(Duration(days: 3)).millisecondsSinceEpoch;
_cookieManager.setCookie(
  url: "https://flutter.dev/",
  name: "session",
  value: "54th5hfdcfg34",
  domain: ".flutter.dev",
  expiresDate: expiresDate,
  isSecure: true,
);Custom context menus
You can customize WebView’s context menu adding custom menu items, and/or hiding the default system menu items. For each custom menu item, you can declare a callback 
actionSpecialwindow.alertHere is the full code example:
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: InAppWebViewPage()
    );
  }
}
class InAppWebViewPage extends StatefulWidget {
  @override
  _InAppWebViewPageState createState() => new _InAppWebViewPageState();
}
class _InAppWebViewPageState extends State<InAppWebViewPage> {
  InAppWebViewController _webViewController;
  ContextMenu contextMenu;
  @override
  void initState() {
    super.initState();
    contextMenu = ContextMenu(
        menuItems: [
          ContextMenuItem(androidId: 1, iosId: "1", title: "Special", action: () async {
            print("Menu item Special clicked!");
            var selectedText = await _webViewController.getSelectedText();
            await _webViewController.clearFocus();
            await _webViewController.evaluateJavascript(source: "window.alert('You have selected: $selectedText')");
          })
        ],
        options: ContextMenuOptions(
            hideDefaultSystemContextMenuItems: false
        ),
        onCreateContextMenu: (hitTestResult) async {
          print("onCreateContextMenu");
          print(hitTestResult.extra);
          print(await _webViewController.getSelectedText());
        },
        onHideContextMenu: () {
          print("onHideContextMenu");
        },
        onContextMenuActionItemClicked: (contextMenuItemClicked) async {
          var id = (Platform.isAndroid) ? contextMenuItemClicked.androidId : contextMenuItemClicked.iosId;
          print("onContextMenuActionItemClicked: " + id.toString() + " " + contextMenuItemClicked.title);
        }
    );
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("InAppWebView")
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                child: Container(
                  child: InAppWebView(
                      initialUrl: "https://github.com/flutter",
                      contextMenu: contextMenu,
                      initialOptions: InAppWebViewGroupOptions(
                        crossPlatform: InAppWebViewOptions(
                          debuggingEnabled: true,
                        ),
                      ),
                      onWebViewCreated: (InAppWebViewController controller) {
                        _webViewController = controller;
                      },
                  ),
                ),
              ),
            ]))
    );
  }
}Conclusion
In this article, I made a little introduction to the 
flutter_inappwebview4.0.0+4The next article will be on how to implement a Full-Featured Browser using this plugin.
That’s all for today! I hope it has opened new use cases for your Flutter apps.
