Starting with Flutter: How to embed a webview
Tags: dart, flutter, tutorial, beginners
Published: 2021-10-27 15:31:55

In this tutorial you will learn how to use `WebViews` in your Flutter application. With WebViews you can embed web contents inside your app. We will use the [webview_flutter](https://pub.dev/packages/webview_flutter) package that uses native WebViews ([WKWebView](https://developer.apple.com/documentation/webkit/wkwebview) on iOS and [WebView ](https://developer.android.com/reference/android/webkit/WebView)on Android).

The first thing that you have to do is to add the package to your `pubspec.yaml` file:

```dart
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  webview_flutter: ^2.1.2
```

 

After this run `flutter pub get`, or use the Pub get button.

Now create a new file `webview_scaffold.dart`, and create a new `StatefulWidget` called `WebViewScaffold`. 
Adding a WebView is very simple, we will need to use the `WebView` Widget as the body of the Scaffold. In the following example the WebView will open [`https://google.com`](https://google.com).

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

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

  @override
  State<WebViewScaffold> createState() => _WebViewScaffoldState();
}

class _WebViewScaffoldState extends State<WebViewScaffold> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView'),
      ),
      body: WebView(
        initialUrl: 'https://google.com',
        javascriptMode: JavascriptMode.unrestricted,
      ),
    );
  }
}
```

 

## Navigation 

We can manage the navigation in our WebView, to do so we will use the `WebViewController` object. This is created by the `WebView` widget and passed in a callback that's called once the `WebView` is created. 
Let's add the `WebViewController` to our state and save it for later, when the callback is invoked.

```dart
class _WebViewScaffoldState extends State<WebViewScaffold> {
  WebViewController? _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView'),
      ),
      body: WebView(
        initialUrl: 'https://google.com',
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (controller) {
          setState(() {
            _controller = controller;
          });
        },
      ),
    );
  }
}
```

 

Now we just need to use the controller to make thee `WebView` go back, go forward or reload. The `WebViewController` has functions to go back, forward, reload and to check if the `WebView` can go back or go forward. 
We will put those buttons in a `BottomAppBar` as the `bottomNavigationBar` of our `Scaffold`.

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

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

  @override
  State<WebViewScaffold> createState() => _WebViewScaffoldState();
}

class _WebViewScaffoldState extends State<WebViewScaffold> {
  WebViewController? _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView'),
      ),
      body: WebView(
        initialUrl: 'https://google.com',
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (controller) {
          setState(() {
            _controller = controller;
          });
        },
        onPageFinished: (_) {
          setState(() {});
        },
      ),
      bottomNavigationBar: _controller != null
          ? _WebViewNavigationBar(controller: _controller!)
          : null,
    );
  }
}

class _WebViewNavigationBar extends StatelessWidget {
  final WebViewController controller;

  const _WebViewNavigationBar({
    Key? key,
    required this.controller,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BottomAppBar(
      child: SizedBox(
        height: 60,
        child: IconTheme(
          data: IconThemeData(color: Colors.blue),
          child: Row(
            children: [
              FutureBuilder<bool>(
                future: controller.canGoBack(),
                builder: (context, snapshot) => IconButton(
                  icon: Icon(Icons.arrow_back),
                  onPressed:
                      snapshot.data == true ? () => controller.goBack() : null,
                ),
              ),
              FutureBuilder<bool>(
                future: controller.canGoForward(),
                builder: (context, snapshot) => IconButton(
                  icon: Icon(Icons.arrow_forward),
                  onPressed: snapshot.data == true
                      ? () => controller.goForward()
                      : null,
                ),
              ),
              Expanded(child: Container()),
              IconButton(
                icon: Icon(Icons.refresh),
                onPressed: () => controller.reload(),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```