WebViews in Flutter

Note: you can check out the video for this post here and the code for this post can be found here.

Presenting a web view is pretty common in mobile apps. In Flutter, this is done by using the webview_flutter package. This package is part of a larger Github repository github.com/flutter/plugins which serves as a "companion repo to the main flutter repo. It contains the source code for Flutter first-party plugins (i.e., plugins developed by the core Flutter team)."

This tutorial, will be pretty simple, we'll:

Fancy a Video?

Note, the video version of this post can be found at my "Flutter in 10 Minutes" video series here at fluttercrashcourse.com or my YouTube channel here.

How the WebView Widget Works

On iOS the WebView widget is backed by a WKWebView, the newer and now official UIKit control for displaying web views. On Android the WebView widget is backed by a WebView.

Step 1 of 3: Creating our Home Screen

Generating Our Project and main.dart

Generate a new Flutter project via the Flutter command line tool via: flutter create flutter_webviews. Open the generated project and replace main.dart file with the following:

// main.dart

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

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


Next, create a file called app.dart, which will contain some basic Material Design styling. It will also set our app's home navigation route to a new widget we'll create next called Home:

// app.dart

import 'package:flutter/material.dart';
import 'screens/home.dart';

class App extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Web Views',
      theme: ThemeData(
          primarySwatch: Colors.blue,
          fontFamily: "Arial",
          textTheme: TextTheme(
              button: TextStyle(color: Colors.white, fontSize: 18.0),
              title: TextStyle(color: Colors.red))),
      home: Home(),

Step 2 of 3: Creating home.dart

Our Home screen will show a single button that opens a URL. In this example, we'll use standard Material Design widgets too keep things simple. The screen may contain a few widgets you may not be familiar with, but the import part is understanding the _handleURLButtonPress below, which will navigate to our web view, presented by a custom widget we'll create next called WebViewContainer:

// screens/home.dart

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

class Home extends StatelessWidget {
  final _links = ['https://google.com'];

  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            child: SingleChildScrollView(
                child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: _links.map((link) => _urlButton(context, link)).toList(),

  Widget _urlButton(BuildContext context, String url) {
    return Container(
        padding: EdgeInsets.all(20.0),
        child: FlatButton(
          color: Theme.of(context).primaryColor,
          padding: const EdgeInsets.symmetric(horizontal: 50.0, vertical: 15.0),
          child: Text(url),
          onPressed: () => _handleURLButtonPress(context, url),

  void _handleURLButtonPress(BuildContext context, String url) {
        MaterialPageRoute(builder: (context) => WebViewContainer(url)));

Step 3 of 3: Presenting Our WebView

Our WebView widget will be present in a full screen, implemented by a new widget we'll create called WebViewContainer. The widget is a simple screen.

The key takeaway for this screen is the WebView widget, availble to us by importing the webview_flutter package:

    key: _key,
    javascriptMode: JavascriptMode.unrestricted,
    initialUrl: _url)

First, the key parameter allows the Flutter widget tree to refer to this widget easily using a unique key created via Flutter's UniqueKey() method you'll soon see in the full example below.

javascriptMode simply allows us to control what kind of Javascript can be run in our web view.

Finally, initialUrl is the URL we want to display.

Implementing Our WebViewContainer

And finally, here's the code for our web view screen:

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

class WebViewContainer extends StatefulWidget {
  final url;


  createState() => _WebViewContainerState(this.url);

class _WebViewContainerState extends State<WebViewContainer> {
  var _url;
  final _key = UniqueKey();


  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(),
        body: Column(
          children: [
                child: WebView(
                    key: _key,
                    javascriptMode: JavascriptMode.unrestricted,
                    initialUrl: _url))

The important gotcha here is that we'll need to use a StatefulWidget because it appears that if we use a StatelessWidget, the WebView will not load properly.

We pass in a url parameter to this widget, which is used in the state of our StatefulWidget.

There are additional features of the WebView widget, offering abilities such as detecting various gestures on the web page as well as callbacks so we can be notified when the web page is created. Feel free to Ctrl/Command + Click into the WebView widget to read up on more of those features.

One More Requirement for iOS Devices

To use WebView on iOS, it's required to add an special setting in our XCode project. If you're not familiar with iOS projects, every project as a special file called Info.plist, which is a simple list of configuration settings. We can edit this file by opening <project root>/ios/Runner/Info.plist and adding the following to the file's <dict> element:


For example, the start of the file will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">


WebView provides us an easy way to render web pages in our app. Once you start using the Flutter plugin, it'll become easy to try other cool plugins listed on the Github repo here.

Happy Fluttering, Nick

Further Reading


The code for this post can be found here.