WebView in Flutter: A Complete Tutorial for 2026
Last Updated: | Author: Deep Singh
Sometimes your Flutter app needs to show a web page — maybe a help center, a terms of service page, or a payment gateway. That's where WebView comes in. It lets you embed a browser directly inside your app so users never have to leave.
In this tutorial, we'll walk through how to add a WebView in Flutter using the latest webview_flutter plugin. I'll show you the full working code, explain what each part does, and point out the things that have changed recently so your code actually compiles.
Before You Start
Make sure you have the following ready:
- Flutter SDK installed (use the latest stable version for best compatibility)
- Android Studio or VS Code with the Flutter plugin
- A basic understanding of Dart and Flutter widgets
- For Android: Set your
minSdkVersionto at least 21 inandroid/app/build.gradle - For iOS: Set your deployment target to at least iOS 13.0 in your Podfile (iOS 15.0 is recommended for App Store compliance)
Adding the WebView Plugin
The easiest way to add the plugin is to run this command in your project folder:
flutter pub add webview_flutter
Or, if you prefer, open your pubspec.yaml file and add it manually under dependencies:
dependencies:
webview_flutter: ^4.14.1
Then run flutter pub get to fetch the package.
The Full Code
Here's a complete, working example. It loads Google in a WebView, shows a loading spinner while the page loads, and lets the user navigate back using the Android back button.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const MaterialApp(
home: MyWebViewTutorial(),
title: 'WebView Tutorial',
));
}
class MyWebViewTutorial extends StatefulWidget {
const MyWebViewTutorial({super.key});
@override
State<MyWebViewTutorial> createState() => _MyWebViewTutorialState();
}
class _MyWebViewTutorialState extends State<MyWebViewTutorial> {
late final WebViewController _controller;
bool _isLoading = true;
@override
void initState() {
super.initState();
// Set up the WebView controller
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
setState(() => _isLoading = true);
},
onPageFinished: (String url) {
setState(() => _isLoading = false);
},
onWebResourceError: (WebResourceError error) {
debugPrint('WebView error: ${error.description}');
},
),
)
..loadRequest(Uri.parse('https://www.google.com/'));
}
// Handle the Android back button so it navigates back inside the WebView
Future<bool> _onWillPop() async {
if (await _controller.canGoBack()) {
_controller.goBack();
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: const Text('WebView Tutorial'),
),
body: Stack(
children: [
WebViewWidget(controller: _controller),
if (_isLoading)
const Center(child: CircularProgressIndicator()),
],
),
),
);
}
}
What's Changed in Recent Versions
If you've seen older WebView tutorials online, you might notice the code looks different. That's because the plugin had a major update. Here's what changed:
- The old
WebViewwidget is gone. Older tutorials usedWebView(...)directly, but that class was removed. If you try to use it, your code won't compile. - Now you use two separate pieces. You create a
WebViewControllerto handle all the logic (loading, navigation, JavaScript), and aWebViewWidgetto display the content on screen. - The controller is easier to set up. You can now create it right in
initState()instead of waiting for a callback. - Some methods got new names. For example,
loadUrl()is nowloadRequest(), and navigation callbacks are set throughsetNavigationDelegate().
Wrapping Up
That's it — you've now got a working WebView inside your Flutter app. The plugin is actively maintained by the Flutter team, so keep your dependencies up to date to stay compatible with the latest Android and iOS requirements.
If you need platform-specific features like inline media playback on iOS or media gesture controls on Android, you can access them through the controller's platform property.
No comments:
Post a Comment