### Configure Web Platform for InAppWebView Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/intro To ensure proper functionality of the Flutter InAppWebView plugin on the Web platform, you need to include the `web_support.js` file within the `` section of your `web/index.html` file. This setup is crucial for web-specific features, though it's important to note that Flutter widgets overlaying iframes may not respond to mouse gestures, a known Flutter limitation that can be mitigated using the `pointer_interceptor` plugin. ```HTML ``` -------------------------------- ### Handling Custom Scheme Resources with onLoadResourceWithCustomScheme in Dart Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/in-app-webview This comprehensive Dart example demonstrates how to use `onLoadResourceWithCustomScheme` to serve custom resources for specific schemes. It includes platform-specific setup for `WebViewEnvironment` on Windows and `InAppWebViewSettings.resourceCustomSchemes` for other platforms, showing how to load a resource from assets and return it as a `CustomSchemeResponse`. ```Dart import 'package:flutter/services.dart'; WebViewEnvironment? webViewEnvironment; Future main() async { //... if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) { final availableVersion = await WebViewEnvironment.getAvailableVersion(); assert(availableVersion != null, 'Failed to find an installed WebView2 Runtime or non-stable Microsoft Edge installation.'); webViewEnvironment = await WebViewEnvironment.create( settings: WebViewEnvironmentSettings( userDataFolder: 'YOUR_CUSTOM_PATH', customSchemeRegistrations: [ CustomSchemeRegistration( scheme: "my-special-custom-scheme", allowedOrigins: ['*'], treatAsSecure: true, hasAuthorityComponent: true) ])); } //... } //... InAppWebView( webViewEnvironment: webViewEnvironment, initialUrlRequest: URLRequest(url: WebUri('https://example.com')), initialSettings: InAppWebViewSettings(resourceCustomSchemes: ["my-special-custom-scheme"]), onLoadResourceWithCustomScheme: (controller, request) async { if (request.url.scheme == "my-special-custom-scheme") { final bytes = await rootBundle.load( "assets/${request.url.toString().replaceFirst("my-special-custom-scheme://", "", 0)}"); final response = CustomSchemeResponse( data: bytes.buffer.asUint8List(), contentType: "image/svg+xml", contentEncoding: "utf-8"); return response; } return null; }, ) ``` -------------------------------- ### Initialize Flutter Widgets Binding in main() Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro This Dart code snippet demonstrates the essential `WidgetsFlutterBinding.ensureInitialized()` call. It must be the first line in your `main()` method if you need to access the binary messenger or initialize plugins before `runApp()` is called, ensuring proper plugin functionality. ```Dart void main() { // it should be the first line in main method WidgetsFlutterBinding.ensureInitialized(); // rest of your app code runApp(MyApp()); } ``` -------------------------------- ### Initialize Flutter Widgets Binding Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/intro This code snippet demonstrates how to ensure the Flutter Widgets binding is initialized before `runApp()` is called. This is crucial when plugins need to access the binary messenger early in the application lifecycle, such as during their initialization phase. ```Dart void main() { // it should be the first line in main method WidgetsFlutterBinding.ensureInitialized(); // rest of your app code runApp(MyApp()); } ``` -------------------------------- ### Configure Flutter Assets in pubspec.yaml Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro This snippet demonstrates how to declare local asset files (images, JavaScript, CSS, HTML) in the `pubspec.yaml` file to make them accessible to a Flutter application. Assets must be listed under the `flutter: assets:` section to be found and bundled with the app. ```YAML ... # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true assets: - assets/index.html - assets/css/ - assets/images/ ... ``` -------------------------------- ### Complete Flutter InAppWebView Setup for Handlers Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/webview/javascript/communication Provides a complete Flutter application structure demonstrating the setup of `InAppWebView` for JavaScript handler communication, including necessary imports, platform-specific debugging, and basic widget structure. ```Dart import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (Platform.isAndroid) { await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(new MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => new _MyAppState(); } class _MyAppState extends State { InAppWebViewGroupOptions options = InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions( useHybridComposition: true, ),); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("JavaScript Handlers")), body: SafeArea( child: Column(children: [ Expanded( child: InAppWebView( initialData: InAppWebViewInitialData( ``` -------------------------------- ### Flutter InAppLocalhostServer Basic Usage Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/in-app-localhost-server This comprehensive Flutter example demonstrates how to set up and use InAppLocalhostServer to serve web assets from the 'assets' folder. It shows server initialization, conditional startup based on platform, and integrating the server with InAppWebView to load content from http://localhost:8080/index.html. ```Dart import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; final InAppLocalhostServer localhostServer = InAppLocalhostServer(documentRoot: 'assets'); Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb) { // start the localhost server await localhostServer.start(); } if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('InAppLocalhostServer Example'), ), body: Container( child: Column(children: [ Expanded( child: InAppWebView( initialSettings: InAppWebViewSettings( isInspectable: kDebugMode, ), initialUrlRequest: URLRequest(url: WebUri("http://localhost:8080/index.html")), onWebViewCreated: (controller) {}, onLoadStart: (controller, url) {}, onLoadStop: (controller, url) {}, ), ) ])), ); } } ``` -------------------------------- ### Configure Swift Language Version for iOS Podfile Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro Explains how to resolve the "Swift Language Version" build error in iOS projects by modifying the Podfile to set SWIFT_VERSION to '5.0' and ENABLE_BITCODE to 'NO'. This is often required for projects integrating Swift plugins. ```Ruby target 'Runner' do use_frameworks! # required by simple_permission ... end post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.0' # required by simple_permission config.build_settings['ENABLE_BITCODE'] = 'NO' end } end ``` -------------------------------- ### Flutter HeadlessInAppWebView Basic Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/headless-in-app-webview This Flutter example demonstrates the fundamental usage of `HeadlessInAppWebView`. It initializes a headless WebView, loads a URL, handles `onWebViewCreated`, `onConsoleMessage`, `onLoadStart`, and `onLoadStop` events. It also shows how to run, dispose, and interact with the WebView by evaluating JavaScript, along with managing its lifecycle within a Flutter `StatefulWidget`. ```Dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { HeadlessInAppWebView? headlessWebView; String url = ""; @override void initState() { super.initState(); headlessWebView = HeadlessInAppWebView( initialUrlRequest: URLRequest(url: WebUri("https://github.com/flutter")), initialSettings: InAppWebViewSettings(isInspectable: kDebugMode), onWebViewCreated: (controller) { const snackBar = SnackBar( content: Text('HeadlessInAppWebView created!'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onConsoleMessage: (controller, consoleMessage) { final snackBar = SnackBar( content: Text('Console Message: ${consoleMessage.message}'), duration: const Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onLoadStart: (controller, url) async { final snackBar = SnackBar( content: Text('onLoadStart $url'), duration: const Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); setState(() { this.url = url?.toString() ?? ''; }); }, onLoadStop: (controller, url) async { final snackBar = SnackBar( content: Text('onLoadStop $url'), duration: const Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); setState(() { this.url = url?.toString() ?? ''; }); }, ); } @override void dispose() { super.dispose(); headlessWebView?.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "HeadlessInAppWebView Example", )), body: SafeArea( child: Column(children: [ Container( padding: const EdgeInsets.all(20.0), child: Text( "URL: ${(url.length > 50) ? "${url.substring(0, 50)}..." : url}"), ), Center( child: ElevatedButton( onPressed: () async { await headlessWebView?.dispose(); await headlessWebView?.run(); }, child: const Text("Run HeadlessInAppWebView")), ), Center( child: ElevatedButton( onPressed: () async { if (headlessWebView?.isRunning() ?? false) { await headlessWebView?.webViewController ?.evaluateJavascript( source: "console.log('Here is the message!');"); } else { const snackBar = SnackBar( content: Text( 'HeadlessInAppWebView is not running. Click on "Run HeadlessInAppWebView"!'), duration: Duration(milliseconds: 1500), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); } }, child: const Text("Send console.log message")), ), Center( child: ElevatedButton( onPressed: () { headlessWebView?.dispose(); setState(() { url = ''; }); }, child: const Text("Dispose HeadlessInAppWebView")), ) ``` -------------------------------- ### Full Flutter InAppWebView Print Job Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/print-job-controller A complete Flutter application example demonstrating the integration of `InAppWebView` with `PrintJobController`. It covers initializing the web view, triggering a print job with custom settings, handling print job completion, and proper disposal of the controller. ```Dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { final GlobalKey webViewKey = GlobalKey(); InAppWebViewController? webViewController; InAppWebViewSettings settings = InAppWebViewSettings(isInspectable: kDebugMode); PrintJobController? printJobController; @override void dispose() { // dispose any print job printJobController?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Print Job Controller'), actions: [ IconButton( onPressed: () async { // dispose any previous print job printJobController?.dispose(); final jobSettings = PrintJobSettings( handledByClient: true, jobName: "${await webViewController?.getTitle() ?? ''} - PDF Document example", colorMode: PrintJobColorMode.MONOCHROME, outputType: PrintJobOutputType.GRAYSCALE, orientation: PrintJobOrientation.LANDSCAPE, numberOfPages: 1); printJobController = await webViewController ?.printCurrentPage(settings: jobSettings); if (defaultTargetPlatform == TargetPlatform.iOS) { printJobController?.onComplete = (completed, error) async { if (completed) { print("Print Job Completed"); } else { print("Print Job Failed $error"); } printJobController?.dispose(); }; } final jobInfo = await printJobController?.getInfo(); print(jobInfo); }, icon: const Icon(Icons.print)) ], ), body: Column(children: [ Expanded( child: InAppWebView( key: webViewKey, initialUrlRequest: URLRequest(url: WebUri("https://github.com/flutter/")), initialSettings: settings, onWebViewCreated: (InAppWebViewController controller) { webViewController = controller; }, )), ])); } } ``` -------------------------------- ### Declare Assets in pubspec.yaml for Flutter Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/intro To make local asset files such as images, JavaScript, or CSS visible and accessible to your Flutter application, you must declare them in the `assets` section of your `pubspec.yaml` file. Failure to do so will prevent Flutter from locating these files at runtime. This example demonstrates how to include an HTML file, a CSS directory, and an images directory. ```YAML ... # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true assets: - assets/index.html - assets/css/ - assets/images/ ... ``` -------------------------------- ### Flutter HeadlessInAppWebView Basic Usage Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/webview/headless-in-app-webview This comprehensive Flutter example demonstrates how to integrate and manage a `HeadlessInAppWebView`. It initializes the WebView with a URL, handles various lifecycle events like creation, console messages, and page load start/stop. The UI provides buttons to run, send JavaScript messages, and dispose of the headless WebView, showcasing essential interactions and state management. ```Dart import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (Platform.isAndroid) { await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(MaterialApp(home: new MyApp())); } class MyApp extends StatefulWidget { @override _MyAppState createState() => new _MyAppState(); } class _MyAppState extends State { HeadlessInAppWebView? headlessWebView; String url = ""; @override void initState() { super.initState(); headlessWebView = new HeadlessInAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("https://github.com/flutter")), onWebViewCreated: (controller) { final snackBar = SnackBar( content: Text('HeadlessInAppWebView created!'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onConsoleMessage: (controller, consoleMessage) { final snackBar = SnackBar( content: Text('Console Message: ${consoleMessage.message}'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onLoadStart: (controller, url) async { final snackBar = SnackBar( content: Text('onLoadStart $url'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); setState(() { this.url = url?.toString() ?? ''; }); }, onLoadStop: (controller, url) async { final snackBar = SnackBar( content: Text('onLoadStop $url'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); setState(() { this.url = url?.toString() ?? ''; }); }, ); } @override void dispose() { super.dispose(); headlessWebView?.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( "HeadlessInAppWebView Example", )), body: SafeArea( child: Column(children: [ Container( padding: EdgeInsets.all(20.0), child: Text( "URL: ${(url.length > 50) ? url.substring(0, 50) + "..." : url}"), ), Center( child: ElevatedButton( onPressed: () async { await headlessWebView?.dispose(); await headlessWebView?.run(); }, child: Text("Run HeadlessInAppWebView")), ), Center( child: ElevatedButton( onPressed: () async { if (headlessWebView?.isRunning() ?? false) { await headlessWebView?.webViewController.evaluateJavascript( source: "console.log('Here is the message!');"); } else { final snackBar = SnackBar( content: Text( 'HeadlessInAppWebView is not running. Click on \"Run HeadlessInAppWebView\"!'), duration: Duration(milliseconds: 1500), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); } }, child: Text("Send console.log message")), ), Center( child: ElevatedButton( onPressed: () { headlessWebView?.dispose(); setState(() { this.url = ''; }); }, child: Text("Dispose HeadlessInAppWebView")), ) ]))) } } ``` -------------------------------- ### Flutter InAppWebView Context Menu Customization Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/context-menu This Flutter example demonstrates how to customize the `WebView` context menu within an `InAppWebView`. It shows how to add a custom menu item (labeled 'Special'), and how to implement callbacks for `onCreateContextMenu` to display selected text and `onContextMenuActionItemClicked` to react to custom menu item selections. It also includes platform-specific setup for Android debugging and iOS link preview. ```dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { final GlobalKey webViewKey = GlobalKey(); InAppWebViewController? webViewController; InAppWebViewSettings settings = InAppWebViewSettings(isInspectable: kDebugMode); late ContextMenu contextMenu; @override void initState() { super.initState(); contextMenu = ContextMenu( menuItems: [ ContextMenuItem( id: 1, title: "Special", action: () async { const snackBar = SnackBar( content: Text("Special clicked!"), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }) ], onCreateContextMenu: (hitTestResult) async { String selectedText = await webViewController?.getSelectedText() ?? ""; final snackBar = SnackBar( content: Text( "Selected text: '$selectedText', of type: ${hitTestResult.type.toString()}"), duration: const Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onContextMenuActionItemClicked: (menuItem) { final snackBar = SnackBar( content: Text( "Menu item with ID ${menuItem.id} and title '${menuItem.title}' clicked!"), duration: const Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ContextMenu Example'), ), body: Column(children: [ Expanded( child: InAppWebView( key: webViewKey, initialUrlRequest: URLRequest(url: WebUri("https://flutter.dev/")), contextMenu: contextMenu, initialSettings: settings, onWebViewCreated: (InAppWebViewController controller) { webViewController = controller; }, )) ])); } } ``` -------------------------------- ### Full Flutter Example with WebViewAssetLoader and Custom Domain Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/webview-asset-loader This complete Flutter application demonstrates setting up `InAppWebView` with `WebViewAssetLoader` and a custom domain. It includes essential security settings for file access and shows how to load an initial URL from the custom domain, serving assets via the configured asset loader. ```Dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { final GlobalKey webViewKey = GlobalKey(); InAppWebViewSettings settings = InAppWebViewSettings( isInspectable: kDebugMode, // Setting this off for security. Off by default for SDK versions >= 16. allowFileAccessFromFileURLs: false, // Off by default, deprecated for SDK versions >= 30. allowUniversalAccessFromFileURLs: false, // Keeping these off is less critical but still a good idea, especially if your app is not // using file:// or content:// URLs. allowFileAccess: false, allowContentAccess: false, // Basic WebViewAssetLoader with custom domain webViewAssetLoader: WebViewAssetLoader( domain: "my.custom.domain.com", pathHandlers: [AssetsPathHandler(path: '/assets/')])); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('WebView Asset Loader'), ), body: Column(children: [ Expanded( child: InAppWebView( key: webViewKey, initialUrlRequest: URLRequest( url: WebUri( "https://my.custom.domain.com/assets/flutter_assets/assets/website/index.html")), ``` -------------------------------- ### Request Camera and Microphone Permissions in Flutter (Dart) Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro This Dart code snippet shows how to request camera and optional microphone permissions using the `permission_handler` plugin. Permissions are typically requested at application startup to enable features like taking images or recording audio through HTML inputs within an InAppWebView. ```Dart import 'package:permission_handler/permission_handler'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await Permission.camera.request(); await Permission.microphone.request(); // if you need microphone permission runApp(MyApp()); } ``` -------------------------------- ### Example HTML Asset for Flutter WebView Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/webview-asset-loader A complete HTML file ('assets/website/index.html') designed to be used as a local asset within a Flutter InAppWebView. It provides a basic structure with a title and a paragraph. ```HTML WebViewAssetLoader

WebViewAssetLoader

This is a test.

``` -------------------------------- ### Configure InAppWebView FileProvider in AndroidManifest.xml Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro This XML snippet shows how to add the `InAppWebViewFileProvider` configuration within the `` tag of `AndroidManifest.xml`. This provider is essential for `flutter_inappwebview` to handle file access, particularly for features like file uploads from HTML inputs, by granting necessary URI permissions. ```XML ``` -------------------------------- ### Evaluate JavaScript to Set Up and Dispatch Custom Events from Dart Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/webview/javascript/communication This example combines setting up a JavaScript event listener and then dispatching a custom event, all initiated from Dart using the `InAppWebViewController.evaluateJavascript` method. This allows dynamic interaction with the web content. ```Dart onLoadStop: (controller, url) async { await controller.evaluateJavascript(source: """ window.addEventListener("myCustomEvent", (event) => { console.log(JSON.stringify(event.detail)); }, false); """); await Future.delayed(Duration(seconds: 5)); controller.evaluateJavascript(source: """ const event = new CustomEvent("myCustomEvent", { detail: {foo: 1, bar: false} }); window.dispatchEvent(event); """); }, onConsoleMessage: (controller, consoleMessage) { print(consoleMessage); // it will print: {message: {"foo":1,"bar":false}, messageLevel: 1} } ``` -------------------------------- ### Configure InAppWebView FileProvider in AndroidManifest.xml Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/intro To allow the Flutter InAppWebView plugin to access and provide files securely on Android, you must declare the `InAppWebViewFileProvider` within the `` tag of your `AndroidManifest.xml` file. This provider facilitates secure file sharing by defining authorities and granting URI permissions, referencing a `provider_paths` XML resource for path configurations. ```XML ``` -------------------------------- ### Flutter InAppWebView Context Menu Customization Example Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/webview/context-menu This Dart code example demonstrates how to implement a custom context menu for `InAppWebView` in a Flutter application. It shows how to define custom `ContextMenuItem`s, handle the `onCreateContextMenu` event to retrieve selected text, and process clicks on both custom and default menu items using `onContextMenuActionItemClicked`. The example also includes necessary platform-specific initializations. ```Dart import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (Platform.isAndroid) { await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(MaterialApp(home: new MyApp())); } class MyApp extends StatefulWidget { @override _MyAppState createState() => new _MyAppState(); } class _MyAppState extends State { final GlobalKey webViewKey = GlobalKey(); InAppWebViewController? webViewController; InAppWebViewGroupOptions options = InAppWebViewGroupOptions( android: AndroidInAppWebViewOptions( useHybridComposition: true, ), ); late ContextMenu contextMenu; @override void initState() { super.initState(); contextMenu = ContextMenu( menuItems: [ ContextMenuItem( androidId: 1, iosId: "1", title: "Special", action: () async { final snackBar = SnackBar( content: Text("Special clicked!"), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }) ], onCreateContextMenu: (hitTestResult) async { String selectedText = await webViewController?.getSelectedText() ?? ""; final snackBar = SnackBar( content: Text( "Selected text: '$selectedText', of type: ${hitTestResult.type.toString()}"), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onContextMenuActionItemClicked: (menuItem) { var id = (Platform.isAndroid) ? menuItem.androidId : menuItem.iosId; final snackBar = SnackBar( content: Text( "Menu item with ID $id and title '${menuItem.title}' clicked!"), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ContextMenu Example'), ), body: Column(children: [ Expanded( child: InAppWebView( key: webViewKey, initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev/")), contextMenu: contextMenu, initialOptions: options, onWebViewCreated: (InAppWebViewController controller) { webViewController = controller; }, )), ])); } } ``` -------------------------------- ### Convert HeadlessInAppWebView to InAppWebView Widget in Flutter Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/headless-in-app-webview This Flutter example demonstrates how to initialize a HeadlessInAppWebView with specific settings, a URL request, and a PullToRefreshController. It then shows how to run the headless web view and subsequently convert it into a visible InAppWebView widget by setting a flag, illustrating the process of displaying a previously headless web view. ```Dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { HeadlessInAppWebView? headlessWebView; PullToRefreshController? pullToRefreshController; InAppWebViewController? webViewController; String url = ""; int progress = 0; bool convertFlag = false; @override void initState() { super.initState(); pullToRefreshController = kIsWeb || ![TargetPlatform.iOS, TargetPlatform.android] .contains(defaultTargetPlatform) ? null : PullToRefreshController( settings: PullToRefreshSettings( color: Colors.blue, ), onRefresh: () async { if (defaultTargetPlatform == TargetPlatform.android) { webViewController?.reload(); } else if (defaultTargetPlatform == TargetPlatform.iOS) { webViewController?.loadUrl( urlRequest: URLRequest(url: await webViewController?.getUrl())); } }, ); headlessWebView = HeadlessInAppWebView( initialUrlRequest: URLRequest(url: WebUri("https://flutter.dev")), initialSettings: InAppWebViewSettings(isInspectable: kDebugMode), pullToRefreshController: pullToRefreshController, onWebViewCreated: (controller) { webViewController = controller; const snackBar = SnackBar( content: Text('HeadlessInAppWebView created!'), duration: Duration(seconds: 1), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); }, onLoadStart: (controller, url) async { setState(() { this.url = url?.toString() ?? ''; }); }, onProgressChanged: (controller, progress) { setState(() { this.progress = progress; }); }, onLoadStop: (controller, url) async { setState(() { this.url = url?.toString() ?? ''; }); }, ); } @override void dispose() { super.dispose(); headlessWebView?.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "HeadlessInAppWebView to InAppWebView", textScaleFactor: .8, )), body: Column(children: [ Container( padding: const EdgeInsets.all(20.0), child: Text( "URL: ${(url.length > 40) ? "${url.substring(0, 40)}..." : url} - $progress%"), ), !convertFlag ? Center( child: ElevatedButton( onPressed: () async { var headlessWebView = this.headlessWebView; if (headlessWebView != null && !headlessWebView.isRunning()) { await headlessWebView.run(); } }, child: const Text("Run HeadlessInAppWebView")), ) : Container(), !convertFlag ? Center( child: ElevatedButton( onPressed: () { if (!convertFlag) { setState(() { convertFlag = true; }); } }, ``` -------------------------------- ### Additional iOS Info.plist App Transport Security Properties Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/intro This section documents additional useful properties for the `NSAppTransportSecurity` dictionary in the iOS `Info.plist` file. These keys control specific network behaviors related to local resource loading and web view content security. ```APIDOC NSAppTransportSecurity Properties: NSAllowsLocalNetworking: Type: Boolean Description: A Boolean value indicating whether to allow loading of local resources. NSAllowsArbitraryLoadsInWebContent: Type: Boolean Description: A Boolean value indicating whether all App Transport Security restrictions are disabled for requests made from web views. ``` -------------------------------- ### Example of Valid Custom Scheme URL in HTML Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/in-app-webview This HTML snippet demonstrates using a well-formed custom scheme URL (e.g., 'example-app:') instead of a simple string. This approach ensures consistent handling by WebView and allows for programmatic interception. ```HTML Show Profile ``` -------------------------------- ### Add Camera and Audio Permissions to AndroidManifest.xml Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/intro This XML snippet provides the necessary permissions to be added to the `AndroidManifest.xml` file on Android. These permissions are required for the application to access the device's camera and microphone for image and video capture, especially when using HTML input types that interact with these device features. ```XML ``` -------------------------------- ### Basic InAppWebView Usage in Flutter Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/5.x.x/webview/in-app-webview This example demonstrates the fundamental setup and control of an InAppWebView widget in a Flutter application. It includes initializing the WebView, handling URL loading, managing permissions, implementing pull-to-refresh, and integrating with the device's default browser for external URLs. It highlights the use of InAppWebViewController and InAppWebViewGroupOptions for cross-platform configuration. ```Dart import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:url_launcher/url_launcher.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (Platform.isAndroid) { await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(MaterialApp( home: new MyApp() )); } class MyApp extends StatefulWidget { @override _MyAppState createState() => new _MyAppState(); } class _MyAppState extends State { final GlobalKey webViewKey = GlobalKey(); InAppWebViewController? webViewController; InAppWebViewGroupOptions options = InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, mediaPlaybackRequiresUserGesture: false, ), android: AndroidInAppWebViewOptions( useHybridComposition: true, ), ios: IOSInAppWebViewOptions( allowsInlineMediaPlayback: true, )); late PullToRefreshController pullToRefreshController; String url = ""; double progress = 0; final urlController = TextEditingController(); @override void initState() { super.initState(); pullToRefreshController = PullToRefreshController( options: PullToRefreshOptions( color: Colors.blue, ), onRefresh: () async { if (Platform.isAndroid) { webViewController?.reload(); } else if (Platform.isIOS) { webViewController?.loadUrl( urlRequest: URLRequest(url: await webViewController?.getUrl())); } }, ); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Official InAppWebView website")), body: SafeArea( child: Column(children: [ TextField( decoration: InputDecoration( prefixIcon: Icon(Icons.search) ), controller: urlController, keyboardType: TextInputType.url, onSubmitted: (value) { var url = Uri.parse(value); if (url.scheme.isEmpty) { url = Uri.parse("https://www.google.com/search?q=" + value); } webViewController?.loadUrl( urlRequest: URLRequest(url: url)); }, ), Expanded( child: Stack( children: [ InAppWebView( key: webViewKey, initialUrlRequest: URLRequest(url: Uri.parse("https://inappwebview.dev/")), initialOptions: options, pullToRefreshController: pullToRefreshController, onWebViewCreated: (controller) { webViewController = controller; }, onLoadStart: (controller, url) { setState(() { this.url = url.toString(); urlController.text = this.url; }); }, androidOnPermissionRequest: (controller, origin, resources) async { return PermissionRequestResponse( resources: resources, action: PermissionRequestResponseAction.GRANT); }, shouldOverrideUrlLoading: (controller, navigationAction) async { var uri = navigationAction.request.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 NavigationActionPolicy.CANCEL; } } return NavigationActionPolicy.ALLOW; }, onLoadStop: (controller, url) async { pullToRefreshController.endRefreshing(); ``` -------------------------------- ### Full Flutter Example: Dart-JavaScript Web Message Channel Communication Source: https://inappwebview.dev/docs/in-app-browsers/chrome-safari-browser/webview/javascript/communication Provides a complete Flutter application demonstrating bidirectional communication using Web Message Channels. The Dart side creates the channel and transfers `port2` to the JavaScript context. The JavaScript side captures the port, sends messages to Dart, and listens for incoming messages. The example also shows how to set up the `InAppWebView` and handle message callbacks. ```Dart import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { await InAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(new MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => new _MyAppState(); } class _MyAppState extends State { InAppWebViewSettings settings = InAppWebViewSettings(); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("Web Message Channels")), body: SafeArea( child: Column(children: [ Expanded( child: InAppWebView( initialData: InAppWebViewInitialData(data: """ WebMessageChannel Test