diff --git a/.metadata b/.metadata
new file mode 100644
index 00000000..14879c61
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: c860cba910319332564e1e9d470a17074c1f2dfd
+ channel: stable
+
+project_type: plugin
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c28ba671..e65fd8c5 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## 6.0.0
- Deprecated old classes/properties/methods to make them eventually compatible with other operating systems and WebView engines.
+- Added Web support
- Added `pauseAllMediaPlayback`, `setAllMediaPlaybackSuspended`, `closeAllMediaPresentations`, `requestMediaPlaybackState` WebView controller methods
- Added `underPageBackgroundColor`, `isTextInteractionEnabled`, `isSiteSpecificQuirksModeEnabled`, `upgradeKnownHostsToHTTPS` WebView settings
- Added support for `onPermissionRequest` event on iOS 15.0+
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 00000000..a5744c1c
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml
new file mode 100644
index 00000000..61b6c4de
--- /dev/null
+++ b/example/analysis_options.yaml
@@ -0,0 +1,29 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at
+ # https://dart-lang.github.io/linter/lints/index.html.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/example/android/.gitignore b/example/android/.gitignore
new file mode 100644
index 00000000..6f568019
--- /dev/null
+++ b/example/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 00000000..7bb476c7
--- /dev/null
+++ b/example/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 00000000..f74085f3
--- /dev/null
+++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 00000000..3db14bb5
--- /dev/null
+++ b/example/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 00000000..7bb476c7
--- /dev/null
+++ b/example/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/example/ios/.gitignore b/example/ios/.gitignore
new file mode 100644
index 00000000..7a7f9873
--- /dev/null
+++ b/example/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 00000000..f9b0d7c5
--- /dev/null
+++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 00000000..f9b0d7c5
--- /dev/null
+++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/example/lib/generated_plugin_registrant.dart b/example/lib/generated_plugin_registrant.dart
new file mode 100644
index 00000000..8ec58033
--- /dev/null
+++ b/example/lib/generated_plugin_registrant.dart
@@ -0,0 +1,18 @@
+//
+// Generated file. Do not edit.
+//
+
+// ignore_for_file: directives_ordering
+// ignore_for_file: lines_longer_than_80_chars
+
+import 'package:flutter_inappwebview/flutter_inappwebview_web.dart';
+import 'package:url_launcher_web/url_launcher_web.dart';
+
+import 'package:flutter_web_plugins/flutter_web_plugins.dart';
+
+// ignore: public_member_api_docs
+void registerPlugins(Registrar registrar) {
+ FlutterInAppWebViewWebPlatform.registerWith(registrar);
+ UrlLauncherPlugin.registerWith(registrar);
+ registrar.registerMessageHandler();
+}
diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart
index f6b6a4d6..c8102994 100755
--- a/example/lib/in_app_webiew_example.screen.dart
+++ b/example/lib/in_app_webiew_example.screen.dart
@@ -3,6 +3,7 @@ import 'dart:collection';
import 'dart:io';
// import 'dart:typed_data';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
// import 'package:path_provider/path_provider.dart';
@@ -28,7 +29,7 @@ class _InAppWebViewExampleScreenState extends State {
allowsInlineMediaPlayback: true
);
- late PullToRefreshController pullToRefreshController;
+ PullToRefreshController? pullToRefreshController;
late ContextMenu contextMenu;
String url = "";
double progress = 0;
@@ -69,7 +70,7 @@ class _InAppWebViewExampleScreenState extends State {
contextMenuItemClicked.title);
});
- pullToRefreshController = PullToRefreshController(
+ pullToRefreshController = !kIsWeb ? PullToRefreshController(
settings: PullToRefreshSettings(
color: Colors.blue,
),
@@ -81,7 +82,7 @@ class _InAppWebViewExampleScreenState extends State {
urlRequest: URLRequest(url: await webViewController?.getUrl()));
}
},
- );
+ ) : null;
}
@override
@@ -118,7 +119,7 @@ class _InAppWebViewExampleScreenState extends State {
key: webViewKey,
// contextMenu: contextMenu,
initialUrlRequest:
- URLRequest(url: Uri.parse("http://github.com/flutter/")),
+ URLRequest(url: Uri.parse("http://flutter.dev/")),
// initialFile: "assets/index.html",
initialUserScripts: UnmodifiableListView([]),
initialSettings: settings,
@@ -162,18 +163,18 @@ class _InAppWebViewExampleScreenState extends State {
return NavigationActionPolicy.ALLOW;
},
onLoadStop: (controller, url) async {
- pullToRefreshController.endRefreshing();
+ pullToRefreshController?.endRefreshing();
setState(() {
this.url = url.toString();
urlController.text = this.url;
});
},
onLoadError: (controller, url, code, message) {
- pullToRefreshController.endRefreshing();
+ pullToRefreshController?.endRefreshing();
},
onProgressChanged: (controller, progress) {
if (progress == 100) {
- pullToRefreshController.endRefreshing();
+ pullToRefreshController?.endRefreshing();
}
setState(() {
this.progress = progress / 100;
@@ -190,7 +191,7 @@ class _InAppWebViewExampleScreenState extends State {
print(consoleMessage);
},
),
- progress < 1.0
+ !kIsWeb && progress < 1.0
? LinearProgressIndicator(value: progress)
: Container(),
],
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 7a7654a0..43d97e5f 100755
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,6 +1,6 @@
import 'dart:async';
-import 'dart:io';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@@ -19,7 +19,7 @@ Future main() async {
// await Permission.microphone.request();
// await Permission.storage.request();
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(true);
var swAvailable = await WebViewFeature.isFeatureSupported(
diff --git a/example/web/favicon.png b/example/web/favicon.png
new file mode 100644
index 00000000..8aaa46ac
Binary files /dev/null and b/example/web/favicon.png differ
diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png
new file mode 100644
index 00000000..b749bfef
Binary files /dev/null and b/example/web/icons/Icon-192.png differ
diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png
new file mode 100644
index 00000000..88cfd48d
Binary files /dev/null and b/example/web/icons/Icon-512.png differ
diff --git a/example/web/icons/Icon-maskable-192.png b/example/web/icons/Icon-maskable-192.png
new file mode 100644
index 00000000..eb9b4d76
Binary files /dev/null and b/example/web/icons/Icon-maskable-192.png differ
diff --git a/example/web/icons/Icon-maskable-512.png b/example/web/icons/Icon-maskable-512.png
new file mode 100644
index 00000000..d69c5669
Binary files /dev/null and b/example/web/icons/Icon-maskable-512.png differ
diff --git a/example/web/index.html b/example/web/index.html
new file mode 100644
index 00000000..f99fc531
--- /dev/null
+++ b/example/web/index.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ flutter_inappwebview_example
+
+
+
+
+
+
+
diff --git a/example/web/manifest.json b/example/web/manifest.json
new file mode 100644
index 00000000..13c8b581
--- /dev/null
+++ b/example/web/manifest.json
@@ -0,0 +1,35 @@
+{
+ "name": "flutter_inappwebview_example",
+ "short_name": "flutter_inappwebview_example",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#0175C2",
+ "theme_color": "#0175C2",
+ "description": "Demonstrates how to use the flutter_inappwebview plugin.",
+ "orientation": "portrait-primary",
+ "prefer_related_applications": false,
+ "icons": [
+ {
+ "src": "icons/Icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-maskable-192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "maskable"
+ },
+ {
+ "src": "icons/Icon-maskable-512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "maskable"
+ }
+ ]
+}
diff --git a/lib/flutter_inappwebview_web.dart b/lib/flutter_inappwebview_web.dart
new file mode 100755
index 00000000..06b6d905
--- /dev/null
+++ b/lib/flutter_inappwebview_web.dart
@@ -0,0 +1,25 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+library flutter_inappwebview;
+
+export 'src/main.dart';
+export 'src/web/main.dart';
\ No newline at end of file
diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart
index a9ccc7ff..345177b9 100755
--- a/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart
+++ b/lib/src/chrome_safari_browser/chrome_safari_browser_settings.dart
@@ -1,4 +1,3 @@
-import 'dart:io';
import 'dart:ui';
import 'package:flutter/foundation.dart';
@@ -227,7 +226,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions {
static ChromeSafariBrowserSettings fromMap(Map map) {
ChromeSafariBrowserSettings settings = new ChromeSafariBrowserSettings();
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
settings.shareState = map["shareState"];
settings.showTitle = map["showTitle"];
settings.toolbarBackgroundColor =
@@ -252,7 +251,7 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions {
}
settings.screenOrientation = map["screenOrientation"];
}
- if (Platform.isIOS || Platform.isMacOS) {
+ if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
settings.entersReaderIfAvailable = map["entersReaderIfAvailable"];
settings.barCollapsingEnabled = map["barCollapsingEnabled"];
settings.dismissButtonStyle =
diff --git a/lib/src/in_app_browser/in_app_browser_settings.dart b/lib/src/in_app_browser/in_app_browser_settings.dart
index 023829bd..9366f376 100755
--- a/lib/src/in_app_browser/in_app_browser_settings.dart
+++ b/lib/src/in_app_browser/in_app_browser_settings.dart
@@ -1,4 +1,3 @@
-import 'dart:io';
import 'dart:ui';
import 'package:flutter/foundation.dart';
@@ -281,7 +280,7 @@ class InAppBrowserSettings
UtilColor.fromHex(map["toolbarTopBackgroundColor"]);
settings.hideUrlBar = map["hideUrlBar"];
settings.hideProgressBar = map["hideProgressBar"];
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
settings.hideTitleBar = map["hideTitleBar"];
settings.toolbarTopFixedTitle = map["toolbarTopFixedTitle"];
settings.closeOnCannotGoBack = map["closeOnCannotGoBack"];
@@ -289,7 +288,7 @@ class InAppBrowserSettings
settings.shouldCloseOnBackButtonPressed =
map["shouldCloseOnBackButtonPressed"];
}
- if (Platform.isIOS || Platform.isMacOS) {
+ if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
settings.toolbarTopTranslucent = map["toolbarTopTranslucent"];
settings.toolbarTopTintColor =
UtilColor.fromHex(map["toolbarTopTintColor"]);
diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart
index 5a48f574..7a2c9902 100755
--- a/lib/src/in_app_webview/in_app_webview.dart
+++ b/lib/src/in_app_webview/in_app_webview.dart
@@ -9,6 +9,8 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
+import '../web/web_platform_manager.dart';
+
import '../context_menu.dart';
import '../types.dart';
@@ -29,6 +31,7 @@ class InAppWebView extends StatefulWidget implements WebView {
final Set>? gestureRecognizers;
///The window id of a [CreateWindowAction.windowId].
+ @override
final int? windowId;
const InAppWebView({
@@ -537,7 +540,21 @@ class _InAppWebViewState extends State {
widget.pullToRefreshController?.options.toMap() ??
PullToRefreshSettings(enabled: false).toMap();
- if (defaultTargetPlatform == TargetPlatform.android) {
+ if (kIsWeb) {
+ return HtmlElementView(
+ viewType: 'com.pichillilorenzo/flutter_inappwebview',
+ onPlatformViewCreated: (int viewId) {
+ var webViewHtmlElement = WebPlatformManager.webViews[viewId]!;
+ webViewHtmlElement.initialSettings = widget.initialSettings;
+ webViewHtmlElement.initialUrlRequest = widget.initialUrlRequest;
+ webViewHtmlElement.initialFile = widget.initialFile;
+ webViewHtmlElement.initialData = widget.initialData;
+ webViewHtmlElement.prepare();
+ webViewHtmlElement.makeInitialLoad();
+ _onPlatformViewCreated(viewId);
+ },
+ );
+ } else if (defaultTargetPlatform == TargetPlatform.android) {
var useHybridComposition = (widget.initialSettings != null
? widget.initialSettings?.useHybridComposition
:
@@ -642,6 +659,10 @@ class _InAppWebViewState extends State {
@override
void dispose() {
+ int viewId = _controller.getViewId();
+ if (kIsWeb && WebPlatformManager.webViews.containsKey(viewId)) {
+ WebPlatformManager.webViews.remove(viewId);
+ }
super.dispose();
}
diff --git a/lib/src/in_app_webview/in_app_webview_controller.dart b/lib/src/in_app_webview/in_app_webview_controller.dart
index 33dd0bb2..1d69ee2e 100644
--- a/lib/src/in_app_webview/in_app_webview_controller.dart
+++ b/lib/src/in_app_webview/in_app_webview_controller.dart
@@ -75,8 +75,7 @@ class InAppWebViewController
InAppWebViewController(dynamic id, WebView webview) {
this._id = id;
- this._channel =
- MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
+ this._channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
this._channel.setMethodCallHandler(handleMethod);
this._webview = webview;
this._userScripts =
@@ -2103,7 +2102,7 @@ class InAppWebViewController
}
///Gets the URL that was originally requested for the current page.
- ///This is not always the same as the URL passed to [InAppWebView.onLoadStarted] because although the load for that URL has begun,
+ ///This is not always the same as the URL passed to [InAppWebView.onLoadStart] because although the load for that URL has begun,
///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested.
///
///**Supported Platforms/Implementations**:
@@ -2781,7 +2780,7 @@ class InAppWebViewController
/// // Flutter App
/// child: InAppWebView(
/// onWebViewCreated: (controller) async {
- /// if (!Platform.isAndroid || await WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
+ /// if (defaultTargetPlatform != TargetPlatform.android || await WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
/// await controller.addWebMessageListener(WebMessageListener(
/// jsObjectName: "myObject",
/// onPostMessage: (message, sourceOrigin, isMainFrame, replyProxy) {
@@ -2834,6 +2833,15 @@ class InAppWebViewController
return await _channel.invokeMethod('canScrollHorizontally', args);
}
+ ///Returns the iframe `id` attribute used on the Web platform.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ Future getIFrameId() async {
+ Map args = {};
+ return await _channel.invokeMethod('getIFrameId', args);
+ }
+
///Gets the default user agent.
///
///**Supported Platforms/Implementations**:
@@ -2948,4 +2956,14 @@ class InAppWebViewController
args.putIfAbsent('urlScheme', () => urlScheme);
return await _staticChannel.invokeMethod('handlesURLScheme', args);
}
+
+ ///Used internally.
+ MethodChannel getChannel() {
+ return _channel;
+ }
+
+ ///Used internally.
+ int getViewId() {
+ return _id;
+ }
}
diff --git a/lib/src/in_app_webview/in_app_webview_settings.dart b/lib/src/in_app_webview/in_app_webview_settings.dart
index d5becaca..b4c1838a 100755
--- a/lib/src/in_app_webview/in_app_webview_settings.dart
+++ b/lib/src/in_app_webview/in_app_webview_settings.dart
@@ -1,4 +1,3 @@
-import 'dart:io';
import 'dart:ui';
import 'package:flutter/foundation.dart';
@@ -996,6 +995,56 @@ class InAppWebViewSettings
///- iOS
bool upgradeKnownHostsToHTTPS;
+ ///Specifies a feature policy for the iframe. A list of origins the frame is allowed to display content from.
+ ///This attribute also accepts the values `self` and `src` which represent the origin in the iframe's src attribute.
+ ///The default value is `src`.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeAllow;
+
+ ///A boolean value indicating whether the inline frame is willing to be placed into full screen mode.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ bool? iframeAllowFullscreen;
+
+ ///A DOMTokenList that reflects the sandbox HTML attribute, indicating extra restrictions on the behavior of the nested content.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeSandox;
+
+ ///A string that reflects the width HTML attribute, indicating the width of the frame.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeWidth;
+
+ ///A string that reflects the height HTML attribute, indicating the height of the frame.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeHeight;
+
+ ///A string that reflects the `referrerpolicy` HTML attribute indicating which referrer to use when fetching the linked resource.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeReferrerPolicy;
+
+ ///A string that reflects the `name` HTML attribute, containing a name by which to refer to the frame.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeName;
+
+ ///Specifies the Content Security Policy that an embedded document must agree to enforce upon itself.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Web
+ String? iframeCsp;
+
InAppWebViewSettings(
{this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false,
@@ -1115,7 +1164,15 @@ class InAppWebViewSettings
this.underPageBackgroundColor,
this.isTextInteractionEnabled = true,
this.isSiteSpecificQuirksModeEnabled = true,
- this.upgradeKnownHostsToHTTPS = true}) {
+ this.upgradeKnownHostsToHTTPS = true,
+ this.iframeAllow,
+ this.iframeAllowFullscreen,
+ this.iframeSandox,
+ this.iframeWidth,
+ this.iframeHeight,
+ this.iframeReferrerPolicy,
+ this.iframeName,
+ this.iframeCsp,}) {
if (this.minimumFontSize == null)
this.minimumFontSize =
defaultTargetPlatform == TargetPlatform.android ? 8 : 0;
@@ -1257,7 +1314,15 @@ class InAppWebViewSettings
"underPageBackgroundColor": underPageBackgroundColor?.toHex(),
"isTextInteractionEnabled": isTextInteractionEnabled,
"isSiteSpecificQuirksModeEnabled": isSiteSpecificQuirksModeEnabled,
- "upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS
+ "upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS,
+ "iframeAllow": iframeAllow,
+ "iframeAllowFullscreen": iframeAllowFullscreen,
+ "iframeSandox": iframeSandox,
+ "iframeWidth": iframeWidth,
+ "iframeHeight": iframeHeight,
+ "iframeReferrerPolicy": iframeReferrerPolicy,
+ "iframeName": iframeName,
+ "iframeCsp": iframeCsp,
};
}
@@ -1314,7 +1379,17 @@ class InAppWebViewSettings
settings.allowFileAccessFromFileURLs = map["allowFileAccessFromFileURLs"];
settings.allowUniversalAccessFromFileURLs =
map["allowUniversalAccessFromFileURLs"];
- if (Platform.isAndroid) {
+ if (kIsWeb) {
+ settings.iframeAllow = map["iframeAllow"];
+ settings.iframeAllowFullscreen = map["iframeAllowFullscreen"];
+ settings.iframeSandox = map["iframeSandox"];
+ settings.iframeWidth = map["iframeWidth"];
+ settings.iframeHeight = map["iframeHeight"];
+ settings.iframeReferrerPolicy = map["iframeReferrerPolicy"];
+ settings.iframeName = map["iframeName"];
+ settings.iframeCsp = map["iframeCsp"];
+ }
+ if (defaultTargetPlatform == TargetPlatform.android) {
settings.textZoom = map["textZoom"];
settings.clearSessionCache = map["clearSessionCache"];
settings.builtInZoomControls = map["builtInZoomControls"];
@@ -1382,7 +1457,7 @@ class InAppWebViewSettings
settings.horizontalScrollbarTrackColor =
UtilColor.fromHex(map["horizontalScrollbarTrackColor"]);
}
- if (Platform.isIOS || Platform.isMacOS) {
+ if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
settings.disallowOverScroll = map["disallowOverScroll"];
settings.enableViewportScale = map["enableViewportScale"];
settings.suppressesIncrementalRendering =
diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart
index af7036fa..e4f30d68 100644
--- a/lib/src/in_app_webview/webview.dart
+++ b/lib/src/in_app_webview/webview.dart
@@ -791,12 +791,27 @@ abstract class WebView {
///Initial url request that will be loaded.
///
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
+ ///- Web
final URLRequest? initialUrlRequest;
///Initial asset file that will be loaded. See [InAppWebViewController.loadFile] for explanation.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
+ ///- Web
final String? initialFile;
///Initial [InAppWebViewInitialData] that will be loaded.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
+ ///- Web
final InAppWebViewInitialData? initialData;
///Use [initialSettings] instead.
@@ -804,9 +819,18 @@ abstract class WebView {
final InAppWebViewGroupOptions? initialOptions;
///Initial settings that will be used.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
+ ///- Web
final InAppWebViewSettings? initialSettings;
///Context menu which contains custom menu items to be shown when [ContextMenu] is presented.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
final ContextMenu? contextMenu;
///Initial list of user scripts to be loaded at start or end of a page loading.
@@ -816,11 +840,19 @@ abstract class WebView {
///**NOTE for iOS**: this property will be ignored if the [WebView.windowId] has been set.
///There isn't any way to add/remove user scripts specific to iOS window WebViews.
///This is a limitation of the native iOS WebKit APIs.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
final UnmodifiableListView? initialUserScripts;
///Represents the pull-to-refresh feature controller.
///
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [InAppWebViewSettings.useHybridComposition] must be `true`.
+ ///
+ ///**Supported Platforms/Implementations**:
+ ///- Android native WebView
+ ///- iOS
final PullToRefreshController? pullToRefreshController;
///Represents the WebView native implementation to be used.
diff --git a/lib/src/types.dart b/lib/src/types.dart
index e9fa0c63..ec639ee1 100755
--- a/lib/src/types.dart
+++ b/lib/src/types.dart
@@ -1,5 +1,4 @@
import 'dart:collection';
-import 'dart:io';
import 'dart:typed_data';
import 'dart:convert';
import 'dart:ui';
@@ -4780,9 +4779,9 @@ class PermissionResourceType {
if (value != null) {
try {
Set valueList = [].toSet();
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
valueList = PermissionResourceType._androidValues;
- } else if (Platform.isIOS || Platform.isMacOS) {
+ } else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
valueList = PermissionResourceType._appleValues;
}
return valueList.firstWhere((element) => element.toValue() == value);
@@ -7360,9 +7359,9 @@ class SslErrorType {
if (value != null) {
try {
Set valueList = [].toSet();
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
valueList = SslErrorType._androidValues;
- } else if (Platform.isIOS || Platform.isMacOS) {
+ } else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
valueList = SslErrorType._appleValues;
}
return valueList.firstWhere((element) => element.toValue() == value);
@@ -7377,7 +7376,7 @@ class SslErrorType {
@override
String toString() {
- if (Platform.isAndroid) {
+ if (defaultTargetPlatform == TargetPlatform.android) {
switch (_value) {
case 1:
return "SSL_EXPIRED";
@@ -7393,7 +7392,7 @@ class SslErrorType {
default:
return "SSL_NOTYETVALID";
}
- } else if (Platform.isIOS || Platform.isMacOS) {
+ } else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) {
switch (_value) {
case 3:
return "DENY";
diff --git a/lib/src/web/in_app_web_view_web_element.dart b/lib/src/web/in_app_web_view_web_element.dart
new file mode 100644
index 00000000..44695f74
--- /dev/null
+++ b/lib/src/web/in_app_web_view_web_element.dart
@@ -0,0 +1,148 @@
+import 'dart:async';
+import 'package:flutter/services.dart';
+import 'dart:html';
+
+import '../in_app_webview/in_app_webview_settings.dart';
+import '../types.dart';
+
+class InAppWebViewWebElement {
+ late int _viewId;
+ late BinaryMessenger _messenger;
+ late IFrameElement iframe;
+ late MethodChannel _channel;
+ InAppWebViewSettings? initialSettings;
+ URLRequest? initialUrlRequest;
+ InAppWebViewInitialData? initialData;
+ String? initialFile;
+
+ late InAppWebViewSettings settings;
+
+ InAppWebViewWebElement({required int viewId, required BinaryMessenger messenger}) {
+ this._viewId = viewId;
+ this._messenger = messenger;
+ iframe = IFrameElement()
+ ..id = 'flutter_inappwebview-$_viewId'
+ ..style.border = 'none';
+
+ _channel = MethodChannel(
+ 'com.pichillilorenzo/flutter_inappwebview_$_viewId',
+ const StandardMethodCodec(),
+ _messenger,
+ );
+
+ this._channel.setMethodCallHandler(handleMethodCall);
+
+ iframe.addEventListener('load', (event) async {
+ var obj = {
+ "url": iframe.src
+ };
+ _channel.invokeMethod("onLoadStart", obj);
+ await Future.delayed(Duration(milliseconds: 100));
+ _channel.invokeMethod("onLoadStop", obj);
+ });
+ }
+
+ /// Handles method calls over the MethodChannel of this plugin.
+ Future handleMethodCall(MethodCall call) async {
+ switch (call.method) {
+ case "loadUrl":
+ URLRequest urlRequest = URLRequest.fromMap(call.arguments["urlRequest"].cast())!;
+ await _loadUrl(urlRequest: urlRequest);
+ break;
+ case "loadData":
+ String data = call.arguments["data"];
+ String mimeType = call.arguments["mimeType"];
+ await _loadData(data: data, mimeType: mimeType);
+ break;
+ case "loadFile":
+ String assetFilePath = call.arguments["assetFilePath"];
+ await _loadFile(assetFilePath: assetFilePath);
+ break;
+ case "reload":
+ await _reload();
+ break;
+ case "getIFrameId":
+ return iframe.id;
+ default:
+ throw PlatformException(
+ code: 'Unimplemented',
+ details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
+ );
+ }
+ }
+
+ void prepare() {
+ settings = initialSettings ?? InAppWebViewSettings();
+ iframe.allow = settings.iframeAllow ?? iframe.allow;
+ iframe.allowFullscreen = settings.iframeAllowFullscreen ?? iframe.allowFullscreen;
+ if (settings.iframeSandox != null) {
+ iframe.setAttribute("sandbox", settings.iframeSandox ?? "");
+ }
+ var width = settings.iframeWidth ?? iframe.width;
+ if (width == null || width.isEmpty) {
+ width = '100%';
+ }
+ var height = settings.iframeHeight ?? iframe.height;
+ if (height == null || height.isEmpty) {
+ height = '100%';
+ }
+ iframe.width = iframe.style.width = width;
+ iframe.height = iframe.style.height = height;
+ iframe.referrerPolicy = settings.iframeReferrerPolicy ?? iframe.referrerPolicy;
+ iframe.name = settings.iframeName ?? iframe.name;
+ iframe.csp = settings.iframeCsp ?? iframe.csp;
+ }
+
+ void makeInitialLoad() async {
+ if (initialUrlRequest != null) {
+ _loadUrl(urlRequest: initialUrlRequest!);
+ } else if (initialData != null) {
+ _loadData(data: initialData!.data, mimeType: initialData!.mimeType);
+ } else if (initialFile != null) {
+ _loadFile(assetFilePath: initialFile!);
+ }
+ }
+
+ Future _makeRequest(URLRequest urlRequest, {bool? withCredentials, String? responseType, String? mimeType, void onProgress(ProgressEvent e)?}) {
+ return HttpRequest.request(
+ urlRequest.url?.toString() ?? 'about:blank',
+ method: urlRequest.method,
+ requestHeaders: urlRequest.headers,
+ sendData: urlRequest.body,
+ withCredentials: withCredentials,
+ responseType: responseType,
+ mimeType: mimeType,
+ onProgress: onProgress
+ );
+ }
+
+ String _convertHttpResponseToData(HttpRequest httpRequest) {
+ final String contentType =
+ httpRequest.getResponseHeader('content-type') ?? 'text/html';
+ return 'data:$contentType,' + Uri.encodeFull(httpRequest.responseText ?? '');
+ }
+
+ Future _loadUrl({required URLRequest urlRequest}) async {
+ if ((urlRequest.method == null || urlRequest.method == "GET") &&
+ (urlRequest.headers == null || urlRequest.headers!.isEmpty)) {
+ iframe.src = urlRequest.url.toString();
+ } else {
+ iframe.src = _convertHttpResponseToData(await _makeRequest(urlRequest));
+ }
+ }
+
+ Future _loadData({required String data, String mimeType = "text/html"}) async {
+ iframe.src = 'data:$mimeType,' + Uri.encodeFull(data);
+ }
+
+ Future _loadFile({required String assetFilePath}) async {
+ iframe.src = assetFilePath;
+ }
+
+ Future _reload() async {
+ var src = iframe.src;
+ if (src != null) {
+ iframe.contentWindow?.location.href = src;
+ }
+ }
+}
diff --git a/lib/src/web/main.dart b/lib/src/web/main.dart
new file mode 100644
index 00000000..739ef7d9
--- /dev/null
+++ b/lib/src/web/main.dart
@@ -0,0 +1 @@
+export 'web_platform.dart';
\ No newline at end of file
diff --git a/lib/src/web/shims/dart_ui.dart b/lib/src/web/shims/dart_ui.dart
new file mode 100644
index 00000000..51b0d9c4
--- /dev/null
+++ b/lib/src/web/shims/dart_ui.dart
@@ -0,0 +1 @@
+export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart';
\ No newline at end of file
diff --git a/lib/src/web/shims/dart_ui_fake.dart b/lib/src/web/shims/dart_ui_fake.dart
new file mode 100644
index 00000000..46a4ac82
--- /dev/null
+++ b/lib/src/web/shims/dart_ui_fake.dart
@@ -0,0 +1,29 @@
+import 'dart:html' as html;
+
+// Fake interface for the logic that this package needs from (web-only) dart:ui.
+// This is conditionally exported so the analyzer sees these methods as available.
+
+// ignore_for_file: avoid_classes_with_only_static_members
+// ignore_for_file: camel_case_types
+
+/// Shim for web_ui engine.PlatformViewRegistry
+/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L62
+class platformViewRegistry {
+ /// Shim for registerViewFactory
+ /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/ui.dart#L72
+ static bool registerViewFactory(
+ String viewTypeId, html.Element Function(int viewId) viewFactory) {
+ return false;
+ }
+}
+
+/// Shim for web_ui engine.AssetManager.
+/// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L12
+class webOnlyAssetManager {
+ /// Shim for getAssetUrl.
+ /// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/assets.dart#L45
+ static String getAssetUrl(String asset) => '';
+}
+
+/// Signature of callbacks that have no arguments and return no data.
+typedef VoidCallback = void Function();
\ No newline at end of file
diff --git a/lib/src/web/shims/dart_ui_real.dart b/lib/src/web/shims/dart_ui_real.dart
new file mode 100644
index 00000000..b0e3b648
--- /dev/null
+++ b/lib/src/web/shims/dart_ui_real.dart
@@ -0,0 +1 @@
+export 'dart:ui';
\ No newline at end of file
diff --git a/lib/src/web/web_platform.dart b/lib/src/web/web_platform.dart
new file mode 100644
index 00000000..25b90e83
--- /dev/null
+++ b/lib/src/web/web_platform.dart
@@ -0,0 +1,39 @@
+import 'dart:async';
+import 'package:flutter/services.dart';
+import 'web_platform_manager.dart';
+import 'package:flutter_web_plugins/flutter_web_plugins.dart';
+import 'shims/dart_ui.dart' as ui;
+
+import 'in_app_web_view_web_element.dart';
+
+/// Builds an iframe based WebView.
+///
+/// This is used as the default implementation for [WebView] on web.
+class FlutterInAppWebViewWebPlatform {
+
+ /// Constructs a new instance of [FlutterInAppWebViewWebPlatform].
+ FlutterInAppWebViewWebPlatform(Registrar registrar) {
+ ui.platformViewRegistry.registerViewFactory(
+ 'com.pichillilorenzo/flutter_inappwebview',
+ (int viewId) {
+ var webView = InAppWebViewWebElement(viewId: viewId, messenger: registrar);
+ WebPlatformManager.webViews.putIfAbsent(viewId, () => webView);
+ return webView.iframe;
+ });
+ }
+
+ static void registerWith(Registrar registrar) {
+ final pluginInstance = FlutterInAppWebViewWebPlatform(registrar);
+ }
+
+ /// Handles method calls over the MethodChannel of this plugin.
+ Future handleMethodCall(MethodCall call) async {
+ switch (call.method) {
+ default:
+ throw PlatformException(
+ code: 'Unimplemented',
+ details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/src/web/web_platform_manager.dart b/lib/src/web/web_platform_manager.dart
new file mode 100644
index 00000000..f59aa09a
--- /dev/null
+++ b/lib/src/web/web_platform_manager.dart
@@ -0,0 +1,3 @@
+class WebPlatformManager {
+ static final Map webViews = {};
+}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index 8678b95e..27639ddb 100755
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -14,6 +14,8 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
+ flutter_web_plugins:
+ sdk: flutter
pedantic: ^1.11.1
# For information on the generic Dart part of this file, see the
@@ -28,6 +30,10 @@ flutter:
pluginClass: InAppWebViewFlutterPlugin
ios:
pluginClass: InAppWebViewFlutterPlugin
+ web:
+ pluginClass: FlutterInAppWebViewWebPlatform
+ fileName: flutter_inappwebview_web.dart
+
assets:
- packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html