The mobile application landscape continually evolves, and developers strive to provide seamless in-app experiences. With the rise of Flutter as a comprehensive app SDK for crafting natively compiled applications, the need for robust web content integration has never been more pronounced. This is where the Flutter InAppWebView package shines, providing a feature-rich solution for embedding interactive web content directly within your Flutter apps.
In this blog, we will dive deep into the world of Flutter InAppWebView, understanding its significance, exploring its capabilities, and learning how to integrate it into your Flutter applications to create immersive and dynamic user experiences.
Flutter InAppWebView is a plugin that allows developers to embed a powerful browser inside their Flutter app easily. But it's not just a widget but a leap forward from traditional webview plugins. Unlike the default WebView widget that comes with Flutter, the Flutter InAppWebView plugin offers an array of additional functionalities that greatly expand developers' control over web content.
Its importance lies in its ability to create an inline native web view integrated seamlessly into the flutter widget tree or to instantiate in headless mode for off-screen operations. This flexibility gives Flutter developers the tools to handle sophisticated web-related tasks without sacrificing the performance and coherence of native app components.
Many app developers often need to display web content directly in their apps. While Flutter’s native webview might seem sufficient at first glance, the InAppWebView plugin’s capabilities truly enrich the user experience in Flutter apps. There are tangible benefits to using Flutter InAppWebView that make it the preferred choice.
InAppWebView provides a smooth and consistent webview experience that closely resembles the familiar feel of browsers like Google Chrome mobile browser. Thanks to detailed customization options, it ensures users do not feel a disconnect between the native app content and the displayed web pages.
Regarding technical advantages, inappwebview flutter supports a wide array of features. Developers have detailed control over the webview’s behavior, including managing cookies, handling downloads, uploading files, and utilizing custom context menus in the webview.
Flutter InAppWebView makes the inline integration of a native webview a breeze. It doesn’t stand out as 'just a widget' in your Flutter app; instead, it can be styled and controlled to work harmoniously with the rest of the widget tree. It also supports headless webview instances, which allows web content to be rendered off-screen, a feature that can be used in background processing and preloading content.
Flutter app developers no longer have to juggle incorporating webview widgets and retaining app performance. With Flutter InAppWebView, the seamless integration ensures web content is handled without compromising the native app feel or performance.
With its thriving plugin ecosystem, inappwebview Flutter benefits from constant updates and a community of developers who contribute to its growth. The flutter_inappwebview plugin also remains an official flutter plugin that adheres to the high standards set by Flutter's parent company, ensuring reliability and quality.
As we explore the features and implementation in the upcoming sections, these benefits will become even more apparent, outlining why the Flutter InAppWebView should be a staple in your toolkit when dealing with web content within Flutter apps.
The Flutter InAppWebView plugin is not just about embedding web pages into your app – it’s a complete suite of tools that enhances your Flutter app's capabilities to the next level. The plugin is packed with features that grant you extensive control over how web content is managed and displayed within your application. Here’s a look at some of the main classes and features that the plugin provides:
Each feature provided by the Flutter InAppWebView package is designed to empower developers to incorporate web content into their Flutter applications effectively. This makes your app more dynamic and opens new possibilities in functionality that could set your app apart.
Integrating the Flutter InAppWebView into your Flutter application is straightforward, but it requires careful adherence to setup requirements to ensure smooth operation. Here, we will walk through the steps to set up the inappwebview_flutter plugin and prepare your app for advanced webview functionalities.
Before diving into the code, ensure that your development environment meets the following requirements:
>=2.14.0 <3.0.0
">=3.0.0
"Firstly, you must add the Flutter InAppWebView as a dependency in your pubspec.yaml file:
1dependencies: 2 flutter_inappwebview: ^5.8.0
Then, run the following command to get the package:
1flutter pub get
Ensure your Android project is set to use AndroidX. This likely involves changes to your gradle.properties file with the following lines:
1android.useAndroidX=true 2android.enableJetifier=true
For iOS, make sure you use Swift as your iOS language and that your Xcode version is current. The Flutter InAppWebView plugin is written in Swift, so your project must be compatible with this language.
If you’re starting a new project, you can specify Swift and Kotlin for iOS and Android, respectively, using:
1flutter create -i swift -a kotlin my_app
With the project setup out of the way, you can now start using the InAppWebView widget in your Flutter app. Here's a simple example to get you started:
1import 'package:flutter/material.dart'; 2import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 3 4void main() => runApp(MyApp()); 5 6class MyApp extends StatelessWidget { 7 @override 8 Widget build(BuildContext context) { 9 return MaterialApp( 10 home: InAppWebViewExample(), 11 ); 12 } 13} 14 15class InAppWebViewExample extends StatefulWidget { 16 @override 17 _InAppWebViewExampleState createState() => _InAppWebViewExampleState(); 18} 19 20class _InAppWebViewExampleState extends State<InAppWebViewExample> { 21 InAppWebViewController _webViewController; 22 23 @override 24 Widget build(BuildContext context) { 25 return Scaffold( 26 appBar: AppBar(title: Text("InAppWebView Example")), 27 body: InAppWebView( 28 initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), 29 onWebViewCreated: (InAppWebViewController controller) { 30 _webViewController = controller; 31 }, 32 ), 33 ); 34 } 35}
This code snippet sets up a basic Flutter app with an InAppWebView widget that loads Flutter's official website. By running this example, you can see an inline webview integrated into your app, showcasing just how easy it is to embed web content within a Flutter app using Flutter InAppWebView.
With these steps, you have the flutter_inappwebview plugin installed and a simple example to build upon. Now you can tailor the webview experience to your application's needs.
Having set up your Flutter app to incorporate the InAppWebView plugin, let's walk through an example demonstrating the primary usage and key functionalities typical of a more advanced implementation.
Here, we'll create an example Flutter app that loads a website and handles user interaction, such as link clicks and page loads.
Firstly, we will define the main widget that contains the InAppWebView:
1import 'package:flutter/material.dart'; 2import 'package:flutter_inappwebview/flutter_inappwebview.dart'; 3 4class WebViewContainer extends StatefulWidget { 5 final String targetUrl; 6 7 WebViewContainer({Key key, this.targetUrl}) : super(key: key); 8 9 @override 10 _WebViewContainerState createState() => _WebViewContainerState(); 11} 12 13class _WebViewContainerState extends State<WebViewContainer> { 14 InAppWebViewController _webViewController; 15 16 @override 17 Widget build(BuildContext context) { 18 return Scaffold( 19 appBar: AppBar( 20 title: Text('Flutter InAppWebView Example'), 21 ), 22 body: InAppWebView( 23 initialUrlRequest: URLRequest(url: Uri.parse(widget.targetUrl)), 24 onWebViewCreated: (controller) { 25 _webViewController = controller; 26 }, 27 onLoadStart: (controller, url) { 28 setState(() { 29 print('Page started loading: $url'); 30 }); 31 }, 32 onLoadStop: (controller, url) { 33 setState(() { 34 print('Page finished loading: $url'); 35 }); 36 }, 37 ), 38 ); 39 } 40}
This widget initializes an InAppWebView that navigates to the URL passed to it and sets up event handlers to react to the start and stop of page loads.
Handling link clicks and navigation within the webview is essential for an integrated web experience. Add navigation delegate logic to handle requests:
1onLoadStart: (controller, url) { 2 setState(() { 3 print('Page started loading: $url'); 4 }); 5}, 6onLoadStop: (controller, url) async { 7 setState(() { 8 print('Page finished loading: $url'); 9 }); 10},
These callbacks are triggered when a page starts loading and when it stops.
Add a basic AppBar with action buttons that allow the user to interact with the webview:
1appBar: AppBar( 2 title: Text('Flutter InAppWebView Example'), 3 actions: <Widget>[ 4 IconButton( 5 icon: Icon(Icons.arrow_back), 6 onPressed: () { 7 if (_webViewController != null) { 8 _webViewController.goBack(); 9 } 10 }, 11 ), 12 IconButton( 13 icon: Icon(Icons.arrow_forward), 14 onPressed: () { 15 if (_webViewController != null) { 16 _webViewController.goForward(); 17 } 18 }, 19 ), 20 IconButton( 21 icon: Icon(Icons.refresh), 22 onPressed: () { 23 if (_webViewController != null) { 24 _webViewController.reload(); 25 } 26 }, 27 ), 28 ], 29),
These buttons call goBack, goForward, and reload on the InAppWebViewController, allowing users to navigate backward and forward through their browsing history and refresh the current page.
Finally, instantiate your WebViewContainer widget in the main app:
1void main() => runApp(MyApp()); 2 3class MyApp extends StatelessWidget { 4 @override 5 Widget build(BuildContext context) { 6 return MaterialApp( 7 home: WebViewContainer(targetUrl: "https://flutter.dev"), 8 ); 9 } 10}
When you run your app, you should see a fully functional webview loading the Flutter website. You can navigate through pages, go back, go forward, and refresh, just like in a browser.
The true power of the Flutter InAppWebView lies in its ability to display web content and in how it can be customized to fit the specific needs of your Flutter app. A wide array of options lets you govern how the webview behaves, interacts with the user, and integrates with the rest of your app. Let's discuss some key customization options available.
One of the first aspects you might want to customize is the webview's settings. InAppWebView provides an array of settings you can tweak to modify aspects like JavaScript execution, cache policy, user-agent string, and more.
Below is an example of how to customize these settings:
1InAppWebView( 2 initialOptions: InAppWebViewGroupOptions( 3 crossPlatform: InAppWebViewOptions( 4 debuggingEnabled: true, 5 useShouldOverrideUrlLoading: true, 6 mediaPlaybackRequiresUserGesture: false, 7 ), 8 android: AndroidInAppWebViewOptions( 9 useHybridComposition: true, 10 ), 11 ios: IOSInAppWebViewOptions( 12 allowsInlineMediaPlayback: true, 13 ), 14 ), 15 // Rest of the InAppWebView configuration... 16)
By modifying the InAppWebViewGroupOptions, you can define a set of configurations applied to your webview across different platforms.
The appearance of the browser controls and the functionality within the webview can also be tailored to match the theme and behavior of your app. For instance, you can decide how the scrollbars appear or don't appear, set custom colors for progress indicators, and even create your own widgets to control the webview navigation.
InAppWebView offers numerous event listeners that can be overridden to handle various browser events. This feature becomes especially handy when you want to execute custom Dart code on specific webview events like the start or end of a page load, page redirects, or encountering errors. Here's a simple demonstration:
1InAppWebView( 2 initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), 3 onLoadStart: (controller, url) { 4 // Your Dart code here... 5 }, 6 onLoadStop: (controller, url) { 7 // Your Dart code here... 8 }, 9 onProgressChanged: (controller, progress) { 10 // Update a progress indicator with the current progress value... 11 }, 12)
For a highly interactive web experience, you can use JavaScript channels to enable two-way communication between your Dart code and the web page's JavaScript code. This is perfect for capturing events from within the web page or manipulating the web page content dynamically from your Flutter app.
Setting up a JavaScript channel looks like this:
1InAppWebView( 2 initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), 3 //... 4 javascriptChannels: Set.from([ 5 JavascriptChannel( 6 name: "FlutterChannel", 7 onMessageReceived: (JavascriptMessage message) { 8 // Logic here when message received from JavaScript side... 9 }, 10 ), 11 ]), 12)
In the example, we create a JavascriptChannel called FlutterChannel, then within the web content, you can trigger messages to this channel using JavaScript.
For inline webview content integrated within your Flutter app, the key lies in the seamless blend of the web content with your native UI. This could mean overriding default behaviors like link clicks, form submissions, or intercepting AJAX requests made from the webpage to control how data is loaded and displayed within the in-app browser window.
Effective navigation handling within a webview is vital to maintaining a user-friendly interface and ensuring your users have a positive experience. The Flutter InAppWebView package offers comprehensive navigation control, and you can intercept and respond to various navigation events to create a seamless browsing session. Let’s explore how we can handle web navigation within an app.
Your first step in controlling navigation is to handle the events fired when the webview starts loading a new URL or finishes loading it. The onLoadStart and onLoadStop callbacks are ideal for this:
1InAppWebView( 2 initialUrlRequest: URLRequest(url: Uri.parse("https://your-website.com")), 3 onLoadStart: (controller, url) { 4 // Indicate to the user that a page has started loading 5 }, 6 onLoadStop: (controller, url) { 7 // Update the UI to show that the page has finished loading 8 }, 9 onLoadError: (controller, url, code, message) { 10 // Handle errors in loading a page 11 }, 12)
Sometimes you might want to prevent certain URLs from being loaded within your webview or handle them differently—perhaps opening them in a different app or a browser. This can be done using the shouldOverrideUrlLoading method:
1InAppWebView( 2 // ... 3 shouldOverrideUrlLoading: (controller, navigationAction) async { 4 Uri uri = navigationAction.request.url; 5 6 // Check if the URL is an external link that you want to open outside of your app 7 if (uri.toString().contains('some-external-link-domain.com')) { 8 // Use Flutter's url_launcher package or similar to open the link outside the app 9 await canLaunch(uri.toString()) ? await launch(uri.toString()) : throw 'Could not launch $uri'; 10 return NavigationActionPolicy.CANCEL; 11 } 12 13 return NavigationActionPolicy.ALLOW; 14 }, 15)
This approach lets you control which URLs can load within your webview. If the link is something you don't want to load inside your app, you can cancel the navigation and, opting instead to launch the URL externally, effectively dictate the navigation flow.
For apps that need to interact deeply with web content, intercepting AJAX requests could prove useful for fine-grained control over webview content:
1InAppWebView( 2 // ... 3 onLoadResourceWithCustomScheme: (controller, request) async { 4 if (request.url.scheme == "my-custom-scheme") { 5 // Perform some operation like fetching data from a different source 6 return CustomSchemeResponse( 7 data: Uint8List.fromList("Custom data response".codeUnits), 8 contentType: "text/plain", 9 contentEncoding: "utf-8", 10 ); 11 } 12 13 return null; 14 }, 15)
This snippet shows how to handle a custom scheme by providing a CustomSchemeResponse. You can replace this with your logic to send whatever content you need back to the web page directly from within your Flutter app.
One of the most powerful features of the Flutter InAppWebView package is its ability to facilitate communication between Flutter and JavaScript. This opens up numerous possibilities for interactive content, form submission handling, data fetching, and many other operations where coordination between the webview content and the host Flutter app is required.
The JavaScript Bridge allows your Flutter code to send messages to JavaScript code running in the webview and vice versa, which is particularly useful for invoking JavaScript functions and handling events.
Here's how you can set up this two-way communication:
1// Inside your InAppWebView configuration 2 3// Inject supporting JavaScript code into the webview 4onWebViewCreated: (InAppWebViewController controller) { 5 controller.addJavaScriptHandler( 6 handlerName: 'myFlutterHandler', 7 callback: (List<dynamic> args) { 8 // Get message from JavaScript code, which could be the result of some operation. 9 String message = args[0]; 10 print(message); 11 }, 12 ); 13}, 14 15// ...
And the corresponding JavaScript code that communicates with the above handler could be as simple as:
1// In the JavaScript running on your web page 2flutter_inappwebview.callHandler('myFlutterHandler', 'Hello from JavaScript!').then(function(result) { 3 // You can also receive a reply back from Flutter 4 console.log(result); 5});
This demonstrates how easy it is to set up handlers in Flutter that the JavaScript code can invoke. You can also do the reverse, invoking JavaScript code from Dart:
1// Inside one of your event callbacks 2onLoadStop: (InAppWebViewController controller, Uri url) async { 3 // Call a JavaScript function after the webview has loaded 4 controller.evaluateJavascript(source: """ 5 if (window.myJsFunction) { 6 window.myJsFunction('Data from Flutter'); 7 } 8 """); 9},
In the example, we invoke a JavaScript function called myJsFunction from Dart code, passing it a string of data from the Flutter side.
You can set up a JavaScript channel to send data from the web page back to your Flutter code. This can trigger Dart functions from user actions within the web page, such as button clicks or form submissions.
1InAppWebView( 2 // ... 3 javascriptChannels: Set.from([ 4 JavascriptChannel( 5 name: 'MessageChannel', 6 onMessageReceived: (JavascriptMessage message) { 7 print('JavaScript message received: ${message.message}'); 8 }, 9 ), 10 ]), 11)
This sets up a channel named MessageChannel to which the web page can post messages. Those messages are then received in your Dart code, where you can handle them appropriately.
Beyond the basics, the Flutter InAppWebView package offers more sophisticated features designed for complex scenarios and enhanced functionality within your Flutter app. These capabilities allow you to provide rich content and advanced web interactions. Let’s explore some advanced features and understand how they can be leveraged.
One of the valuable features of inappwebview_flutter is its support for file uploads and downloads. It allows users to interact with file input fields and download links as they would do in any standard web browser.
To handle file uploads, InAppWebView offers an onFileUploadChooser callback, where you can respond to file input prompts:
1InAppWebView( 2 // ... 3 onFileUploadChooser: (controller, fileUploadRequest) async { 4 // Open file chooser and retrieve the file path(s) 5 // Then, call fileUploadRequest.action with the file path to complete the upload process 6 return fileUploadRequest.action([yourFilePath]); 7 }, 8)
Downloads can be managed via the onDownloadStart event:
1InAppWebView( 2 // ... 3 onDownloadStart: (controller, url) { 4 // You can use Flutter’s external plugins to download the file from the URL 5 }, 6)
To handle media playback within your webview, such as playing videos or audio, you need to set appropriate options for media playback:
1InAppWebView( 2 initialOptions: InAppWebViewGroupOptions( 3 crossPlatform: InAppWebViewOptions( 4 mediaPlaybackRequiresUserGesture: false, 5 ), 6 ios: IOSInAppWebViewOptions( 7 allowsInlineMediaPlayback: true, 8 ), 9 // ... 10 ), 11 // ... 12)
Regarding interactivity, you can use the addJavaScriptHandler and evaluateJavascript functions to create a rich interaction between your app and the web content. For instance, retrieving data from the website, manipulating DOM elements, or even invoking complex JavaScript functions.
1InAppWebView( 2 // ... 3 onWebViewCreated: (controller) { 4 controller.addJavaScriptHandler(handlerName: 'getDocumentTitle', callback: (args) { 5 // Execute any Dart code after receiving data from JavaScript 6 String title = args[0]; 7 print('Document title: $title'); 8 }); 9 }, 10)
Invoking this handler from the web content would look like:
1flutter_inappwebview.callHandler('getDocumentTitle', document.title);
For scenarios where you might want to run web content in the background without displaying it to the user, the HeadlessInAppWebView class can be beneficial:
1// Create a headless webview 2var headlessWebView = new HeadlessInAppWebView( 3 initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), 4 onWebViewCreated: (controller) { 5 print('HeadlessInAppWebView created!'); 6 }, 7 onConsoleMessage: (controller, consoleMessage) { 8 print(consoleMessage); 9 } 10); 11 12// Run the headless webview 13await headlessWebView.run();
With HeadlessInAppWebView, you could scrape web content, run background jobs, or perform automated testing.
While the Flutter InAppWebView package is quite powerful, developers inevitably encounter issues during the implementation and operation phases. Let's address some common problems and best practices for solving them, ensuring that your work with Flutter InAppWebView remains smooth and efficient.
For Android, webview might require location, camera, and storage permissions. You’ll often need to handle permission requests:
1InAppWebView( 2 // ... 3 androidOnPermissionRequest: (controller, origin, resources) async { 4 // Handle the permission request 5 return PermissionRequestResponse( 6 resources: resources, 7 action: PermissionRequestResponseAction.GRANT); 8 } 9)
Always ensure that your app has the necessary permissions specified in your AndroidManifest.xml. For iOS, check your Info.plist.
It's common to see a blank screen when you expect web content to be displayed. This can happen for several reasons, such as a poor internet connection, unsupported URLs, or issues with the web content itself. Implement onLoadError and onConsoleMessage to gain more insights:
1InAppWebView( 2 // ... 3 onLoadError: (controller, url, code, message) { 4 print("Error loading $url: $message"); 5 }, 6 onConsoleMessage: (controller, consoleMessage) { 7 print(consoleMessage); 8 }, 9)
The Flutter InAppWebView plugin supports debugging. Enable it through the InAppWebView options:
1InAppWebView( 2 initialOptions: InAppWebViewGroupOptions( 3 crossPlatform: InAppWebViewOptions( 4 debuggingEnabled: true, 5 ), 6 // ... 7 ), 8 // ... 9)
For Android, use the chrome://inspect page to debug the webview content. On iOS, you can use Safari's Develop menu.
When injecting JavaScript code, errors can be silent. Use evaluateJavascript with error handling, and always ensure the JavaScript code being executed is correct and within the context of the web content loaded.
1onLoadStop: (InAppWebViewController controller, Uri url) async { 2 try { 3 await controller.evaluateJavascript(source: """ 4 myJavaScriptFunction(); 5 """); 6 } catch (e) { 7 // Handle exception 8 print(e); 9 } 10},
For performance concerns, particularly with many webview instances or significant interactive content, profile your app to understand better where issues might lie. Consider lazy loading, disposing of webviews when not in use, and enabling hardware acceleration on Android.
1AndroidInAppWebViewOptions( 2 hardwareAcceleration: true, 3)
Troubleshooting is an inevitable part of development with complex plugins like Flutter InAppWebView, and these tips should help you mitigate common pitfalls.
The Flutter InAppWebView package is an exemplary tool that provides a rich set of features enabling deep integration of web content into Flutter apps. It exceeds expectations, allowing you to display web pages and interact with them through file handling, custom menus, JavaScript communication, and more. With Flutter InAppWebView, developers can enjoy the smooth blending of native app performance with web flexibility.
As an essential plugin for any Flutter developer’s toolbox, Flutter InAppWebView is backed by an active community and a wealth of resources for troubleshooting and support. By following best practices and leveraging the advanced capabilities of this plugin, you can create sophisticated apps that make web content a native experience.
Whether your project is already utilizing Flutter InAppWebView or considering it for your next app, this package promises to elevate how you think about and implement web content in mobile applications.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.