merged web support, dartfmt

This commit is contained in:
Lorenzo Pichilli 2022-04-25 23:21:26 +02:00
parent 091415dafe
commit 03e74820df
23 changed files with 425 additions and 373 deletions

View File

@ -45,6 +45,18 @@ Send a submission request to the [Submit App](https://inappwebview.dev/submit-ap
Add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/). Add `flutter_inappwebview` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/).
### Installation - Web support
To make it work properly on the Web platformm, you need to add the `web_support.js` file inside the `<head>` of your `web/index.html` file:
```html
<head>
<!-- ... -->
<script src="/packages/flutter_inappwebview/assets/web/web_support.js" defer></script>
<!-- ... -->
</head>
```
## Main Classes Overview ## Main Classes Overview
* [InAppWebView](https://inappwebview.dev/docs/in-app-webview/basic-usage/): Flutter Widget for adding an inline native WebView integrated into the flutter widget tree. * [InAppWebView](https://inappwebview.dev/docs/in-app-webview/basic-usage/): Flutter Widget for adding an inline native WebView integrated into the flutter widget tree.

View File

@ -5498,7 +5498,7 @@ setTimeout(function() {
if (swAvailable && swInterceptAvailable) { if (swAvailable && swInterceptAvailable) {
AndroidServiceWorkerController serviceWorkerController = AndroidServiceWorkerController serviceWorkerController =
AndroidServiceWorkerController.instance(); AndroidServiceWorkerController.instance();
await serviceWorkerController.setServiceWorkerClient(null); await serviceWorkerController.setServiceWorkerClient(null);
} }
@ -5509,7 +5509,7 @@ setTimeout(function() {
child: InAppWebView( child: InAppWebView(
key: GlobalKey(), key: GlobalKey(),
initialUrlRequest: initialUrlRequest:
URLRequest(url: Uri.parse('https://mdn.github.io/sw-test/')), URLRequest(url: Uri.parse('https://mdn.github.io/sw-test/')),
onLoadStop: (controller, url) { onLoadStop: (controller, url) {
pageLoaded.complete(url!.toString()); pageLoaded.complete(url!.toString());
}, },
@ -5874,7 +5874,8 @@ setTimeout(function() {
group('Android Custom Tabs', () { group('Android Custom Tabs', () {
test('add custom action button', () async { test('add custom action button', () async {
var chromeSafariBrowser = new MyChromeSafariBrowser(); var chromeSafariBrowser = new MyChromeSafariBrowser();
var actionButtonIcon = await rootBundle.load('test_assets/images/flutter-logo.png'); var actionButtonIcon =
await rootBundle.load('test_assets/images/flutter-logo.png');
chromeSafariBrowser.setActionButton(ChromeSafariBrowserActionButton( chromeSafariBrowser.setActionButton(ChromeSafariBrowserActionButton(
id: 1, id: 1,
description: 'Action Button description', description: 'Action Button description',
@ -5892,7 +5893,8 @@ setTimeout(function() {
await chromeSafariBrowser.open(url: Uri.parse("https://flutter.dev")); await chromeSafariBrowser.open(url: Uri.parse("https://flutter.dev"));
}, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>())); }, throwsA(isInstanceOf<ChromeSafariBrowserAlreadyOpenedException>()));
await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await expectLater(
chromeSafariBrowser.firstPageLoaded.future, completes);
await chromeSafariBrowser.close(); await chromeSafariBrowser.close();
await chromeSafariBrowser.browserClosed.future; await chromeSafariBrowser.browserClosed.future;
expect(chromeSafariBrowser.isOpened(), false); expect(chromeSafariBrowser.isOpened(), false);

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@ -19,8 +20,12 @@ class _HeadlessInAppWebViewExampleScreenState
void initState() { void initState() {
super.initState(); super.initState();
var url = !kIsWeb
? Uri.parse("https://flutter.dev")
: Uri.parse("http://localhost:${Uri.base.port}/page.html");
headlessWebView = new HeadlessInAppWebView( headlessWebView = new HeadlessInAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")), initialUrlRequest: URLRequest(url: url),
initialSettings: InAppWebViewSettings(), initialSettings: InAppWebViewSettings(),
onWebViewCreated: (controller) { onWebViewCreated: (controller) {
print('HeadlessInAppWebView created!'); print('HeadlessInAppWebView created!');
@ -78,6 +83,9 @@ class _HeadlessInAppWebViewExampleScreenState
}, },
child: Text("Run HeadlessInAppWebView")), child: Text("Run HeadlessInAppWebView")),
), ),
Container(
height: 10,
),
Center( Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: () async { onPressed: () async {
@ -91,6 +99,9 @@ class _HeadlessInAppWebViewExampleScreenState
}, },
child: Text("Send console.log message")), child: Text("Send console.log message")),
), ),
Container(
height: 10,
),
Center( Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {

View File

@ -13,17 +13,16 @@ class InAppWebViewExampleScreen extends StatefulWidget {
} }
class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> { class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
final GlobalKey webViewKey = GlobalKey(); final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController; InAppWebViewController? webViewController;
InAppWebViewSettings settings = InAppWebViewSettings( InAppWebViewSettings settings = InAppWebViewSettings(
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
mediaPlaybackRequiresUserGesture: false, mediaPlaybackRequiresUserGesture: false,
useHybridComposition: true, useHybridComposition: true,
allowsInlineMediaPlayback: true, allowsInlineMediaPlayback: true,
iframeAllow: "camera; microphone", iframeAllow: "camera; microphone",
iframeAllowFullscreen: true, iframeAllowFullscreen: true,
); );
PullToRefreshController? pullToRefreshController; PullToRefreshController? pullToRefreshController;
@ -57,25 +56,30 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
print("onHideContextMenu"); print("onHideContextMenu");
}, },
onContextMenuActionItemClicked: (contextMenuItemClicked) async { onContextMenuActionItemClicked: (contextMenuItemClicked) async {
var id = contextMenuItemClicked.id;
print("onContextMenuActionItemClicked: " + print("onContextMenuActionItemClicked: " +
contextMenuItemClicked.id.toString() + id.toString() +
" " + " " +
contextMenuItemClicked.title); contextMenuItemClicked.title);
}); });
pullToRefreshController = !kIsWeb ? PullToRefreshController( pullToRefreshController = kIsWeb
settings: PullToRefreshSettings( ? null
color: Colors.blue, : PullToRefreshController(
), settings: PullToRefreshSettings(
onRefresh: () async { color: Colors.blue,
if (defaultTargetPlatform == TargetPlatform.android) { ),
webViewController?.reload(); onRefresh: () async {
} else if (defaultTargetPlatform == TargetPlatform.iOS) { if (defaultTargetPlatform == TargetPlatform.android) {
webViewController?.loadUrl( webViewController?.reload();
urlRequest: URLRequest(url: await webViewController?.getUrl())); } else if (defaultTargetPlatform == TargetPlatform.iOS ||
} defaultTargetPlatform == TargetPlatform.macOS) {
}, webViewController?.loadUrl(
) : null; urlRequest:
URLRequest(url: await webViewController?.getUrl()));
}
},
);
} }
@override @override
@ -91,108 +95,105 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
body: SafeArea( body: SafeArea(
child: Column(children: <Widget>[ child: Column(children: <Widget>[
TextField( TextField(
decoration: InputDecoration( decoration: InputDecoration(prefixIcon: Icon(Icons.search)),
prefixIcon: Icon(Icons.search)
),
controller: urlController, controller: urlController,
keyboardType: TextInputType.url, keyboardType: TextInputType.url,
onSubmitted: (value) { onSubmitted: (value) {
var url = Uri.parse(value); var url = Uri.parse(value);
if (url.scheme.isEmpty) { if (url.scheme.isEmpty) {
url = Uri.parse("https://www.google.com/search?q=" + value); url = Uri.parse((!kIsWeb
? "https://www.google.com/search?q="
: "https://www.bing.com/search?q=") +
value);
} }
webViewController?.loadUrl( webViewController?.loadUrl(urlRequest: URLRequest(url: url));
urlRequest: URLRequest(url: url));
}, },
), ),
Expanded( Expanded(
child: Stack( child: Stack(
children: [ children: [
InAppWebView( InAppWebView(
key: webViewKey, key: webViewKey,
// contextMenu: contextMenu, initialUrlRequest:
// initialUrlRequest: URLRequest(url: Uri.parse("https://flutter.dev")),
// URLRequest(url: Uri.parse("https://www.pubnub.com/developers/demos/webrtc/launch/")), // initialFile: "assets/index.html",
initialUrlRequest: initialUserScripts: UnmodifiableListView<UserScript>([]),
URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')), initialSettings: settings,
// initialUrlRequest: // contextMenu: contextMenu,
// URLRequest(url: Uri.parse('https://flutter.dev')), pullToRefreshController: pullToRefreshController,
// initialFile: "assets/index.html", onWebViewCreated: (controller) {
initialUserScripts: UnmodifiableListView<UserScript>([]), webViewController = controller;
initialSettings: settings, },
pullToRefreshController: pullToRefreshController, onLoadStart: (controller, url) async {
onWebViewCreated: (controller) async { setState(() {
webViewController = controller; this.url = url.toString();
}, urlController.text = this.url;
onLoadStart: (controller, url) async { });
setState(() { },
this.url = url.toString(); onPermissionRequest: (controller, request) async {
urlController.text = this.url; return PermissionResponse(
}); resources: request.resources,
}, action: PermissionResponseAction.GRANT);
onPermissionRequest: (controller, request) async { },
return PermissionResponse( shouldOverrideUrlLoading:
resources: request.resources, (controller, navigationAction) async {
action: PermissionResponseAction.GRANT); var uri = navigationAction.request.url!;
},
shouldOverrideUrlLoading: (controller, navigationAction) async {
var uri = navigationAction.request.url!;
if (![ if (![
"http", "http",
"https", "https",
"file", "file",
"chrome", "chrome",
"data", "data",
"javascript", "javascript",
"about" "about"
].contains(uri.scheme)) { ].contains(uri.scheme)) {
if (await canLaunch(url)) { if (await canLaunch(url)) {
// Launch the App // Launch the App
await launch( await launch(
url, url,
); );
// and cancel the request // and cancel the request
return NavigationActionPolicy.CANCEL; return NavigationActionPolicy.CANCEL;
}
} }
}
return NavigationActionPolicy.ALLOW; return NavigationActionPolicy.ALLOW;
}, },
onLoadStop: (controller, url) async { onLoadStop: (controller, url) async {
pullToRefreshController?.endRefreshing();
setState(() {
this.url = url.toString();
urlController.text = this.url;
});
},
onLoadError: (controller, url, code, message) {
pullToRefreshController?.endRefreshing();
},
onProgressChanged: (controller, progress) {
if (progress == 100) {
pullToRefreshController?.endRefreshing(); pullToRefreshController?.endRefreshing();
setState(() { }
this.url = url.toString(); setState(() {
urlController.text = this.url; this.progress = progress / 100;
}); urlController.text = this.url;
}, });
onLoadError: (controller, url, code, message) { },
pullToRefreshController?.endRefreshing(); onUpdateVisitedHistory: (controller, url, androidIsReload) {
}, setState(() {
onProgressChanged: (controller, progress) { this.url = url.toString();
if (progress == 100) { urlController.text = this.url;
pullToRefreshController?.endRefreshing(); });
} },
setState(() { onConsoleMessage: (controller, consoleMessage) {
this.progress = progress / 100; print(consoleMessage);
urlController.text = this.url; },
}); ),
}, progress < 1.0
onUpdateVisitedHistory: (controller, url, androidIsReload) { ? LinearProgressIndicator(value: progress)
setState(() { : Container(),
this.url = url.toString(); ],
urlController.text = this.url; ),
});
},
onConsoleMessage: (controller, consoleMessage) {
print(consoleMessage);
},
),
!kIsWeb && progress < 1.0
? LinearProgressIndicator(value: progress)
: Container(),
],
),
), ),
ButtonBar( ButtonBar(
alignment: MainAxisAlignment.center, alignment: MainAxisAlignment.center,
@ -215,12 +216,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
webViewController?.reload(); webViewController?.reload();
}, },
), ),
ElevatedButton(
child: Icon(Icons.cancel),
onPressed: () {
webViewController?.stopLoading();
},
),
], ],
), ),
]))); ])));

View File

@ -25,4 +25,4 @@ library flutter_inappwebview;
import 'package:js/js.dart'; import 'package:js/js.dart';
export 'src/main.dart'; export 'src/main.dart';
export 'src/web/main.dart'; export 'src/web/main.dart';

View File

@ -251,7 +251,8 @@ class ChromeSafariBrowserSettings implements ChromeSafariBrowserOptions {
} }
settings.screenOrientation = map["screenOrientation"]; settings.screenOrientation = map["screenOrientation"];
} }
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
settings.entersReaderIfAvailable = map["entersReaderIfAvailable"]; settings.entersReaderIfAvailable = map["entersReaderIfAvailable"];
settings.barCollapsingEnabled = map["barCollapsingEnabled"]; settings.barCollapsingEnabled = map["barCollapsingEnabled"];
settings.dismissButtonStyle = settings.dismissButtonStyle =

View File

@ -82,7 +82,8 @@ class CookieManager {
bool? isSecure, bool? isSecure,
bool? isHttpOnly, bool? isHttpOnly,
HTTPCookieSameSitePolicy? sameSite, HTTPCookieSameSitePolicy? sameSite,
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController, @Deprecated("Use webViewController instead")
InAppWebViewController? iosBelow11WebViewController,
InAppWebViewController? webViewController}) async { InAppWebViewController? webViewController}) async {
if (domain == null) domain = _getDomainName(url); if (domain == null) domain = _getDomainName(url);
@ -200,7 +201,8 @@ class CookieManager {
///- Web ///- Web
Future<List<Cookie>> getCookies( Future<List<Cookie>> getCookies(
{required Uri url, {required Uri url,
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController, @Deprecated("Use webViewController instead")
InAppWebViewController? iosBelow11WebViewController,
InAppWebViewController? webViewController}) async { InAppWebViewController? webViewController}) async {
assert(url.toString().isNotEmpty); assert(url.toString().isNotEmpty);
@ -318,7 +320,8 @@ class CookieManager {
Future<Cookie?> getCookie( Future<Cookie?> getCookie(
{required Uri url, {required Uri url,
required String name, required String name,
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController, @Deprecated("Use webViewController instead")
InAppWebViewController? iosBelow11WebViewController,
InAppWebViewController? webViewController}) async { InAppWebViewController? webViewController}) async {
assert(url.toString().isNotEmpty); assert(url.toString().isNotEmpty);
assert(name.isNotEmpty); assert(name.isNotEmpty);
@ -388,7 +391,8 @@ class CookieManager {
required String name, required String name,
String domain = "", String domain = "",
String path = "/", String path = "/",
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController, @Deprecated("Use webViewController instead")
InAppWebViewController? iosBelow11WebViewController,
InAppWebViewController? webViewController}) async { InAppWebViewController? webViewController}) async {
if (domain.isEmpty) domain = _getDomainName(url); if (domain.isEmpty) domain = _getDomainName(url);
@ -449,7 +453,8 @@ class CookieManager {
{required Uri url, {required Uri url,
String domain = "", String domain = "",
String path = "/", String path = "/",
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController, @Deprecated("Use webViewController instead")
InAppWebViewController? iosBelow11WebViewController,
InAppWebViewController? webViewController}) async { InAppWebViewController? webViewController}) async {
if (domain.isEmpty) domain = _getDomainName(url); if (domain.isEmpty) domain = _getDomainName(url);
@ -537,13 +542,13 @@ class CookieManager {
Future<String> _getCookieExpirationDate(int expiresDate) async { Future<String> _getCookieExpirationDate(int expiresDate) async {
var platformUtil = PlatformUtil.instance(); var platformUtil = PlatformUtil.instance();
var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc();
return !kIsWeb ? return !kIsWeb
await platformUtil.formatDate( ? await platformUtil.formatDate(
date: dateTime, date: dateTime,
format: 'EEE, dd MMM yyyy hh:mm:ss z', format: 'EEE, dd MMM yyyy hh:mm:ss z',
locale: 'en_US', locale: 'en_US',
timezone: 'GMT') : timezone: 'GMT')
await platformUtil.getWebCookieExpirationDate(date: dateTime); : await platformUtil.getWebCookieExpirationDate(date: dateTime);
} }
} }

View File

@ -288,7 +288,8 @@ class InAppBrowserSettings
settings.shouldCloseOnBackButtonPressed = settings.shouldCloseOnBackButtonPressed =
map["shouldCloseOnBackButtonPressed"]; map["shouldCloseOnBackButtonPressed"];
} }
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
settings.toolbarTopTranslucent = map["toolbarTopTranslucent"]; settings.toolbarTopTranslucent = map["toolbarTopTranslucent"];
settings.toolbarTopTintColor = settings.toolbarTopTintColor =
UtilColor.fromHex(map["toolbarTopTintColor"]); UtilColor.fromHex(map["toolbarTopTintColor"]);

View File

@ -75,7 +75,8 @@ class InAppWebViewController
InAppWebViewController(dynamic id, WebView webview) { InAppWebViewController(dynamic id, WebView webview) {
this._id = id; this._id = id;
this._channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); this._channel =
MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
this._channel.setMethodCallHandler(handleMethod); this._channel.setMethodCallHandler(handleMethod);
this._webview = webview; this._webview = webview;
this._userScripts = this._userScripts =
@ -1700,7 +1701,8 @@ class InAppWebViewController
args.putIfAbsent('source', () => source); args.putIfAbsent('source', () => source);
args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); args.putIfAbsent('contentWorld', () => contentWorld?.toMap());
var data = await _channel.invokeMethod('evaluateJavascript', args); var data = await _channel.invokeMethod('evaluateJavascript', args);
if (data != null && (defaultTargetPlatform == TargetPlatform.android || kIsWeb)) { if (data != null &&
(defaultTargetPlatform == TargetPlatform.android || kIsWeb)) {
try { try {
// try to json decode the data coming from JavaScript // try to json decode the data coming from JavaScript
// otherwise return it as it is. // otherwise return it as it is.

View File

@ -1053,132 +1053,133 @@ class InAppWebViewSettings
///- Web ///- Web
String? iframeCsp; String? iframeCsp;
InAppWebViewSettings( InAppWebViewSettings({
{this.useShouldOverrideUrlLoading = false, this.useShouldOverrideUrlLoading = false,
this.useOnLoadResource = false, this.useOnLoadResource = false,
this.useOnDownloadStart = false, this.useOnDownloadStart = false,
this.clearCache = false, this.clearCache = false,
this.userAgent = "", this.userAgent = "",
this.applicationNameForUserAgent = "", this.applicationNameForUserAgent = "",
this.javaScriptEnabled = true, this.javaScriptEnabled = true,
this.javaScriptCanOpenWindowsAutomatically = false, this.javaScriptCanOpenWindowsAutomatically = false,
this.mediaPlaybackRequiresUserGesture = true, this.mediaPlaybackRequiresUserGesture = true,
this.minimumFontSize, this.minimumFontSize,
this.verticalScrollBarEnabled = true, this.verticalScrollBarEnabled = true,
this.horizontalScrollBarEnabled = true, this.horizontalScrollBarEnabled = true,
this.resourceCustomSchemes = const [], this.resourceCustomSchemes = const [],
this.contentBlockers = const [], this.contentBlockers = const [],
this.preferredContentMode = UserPreferredContentMode.RECOMMENDED, this.preferredContentMode = UserPreferredContentMode.RECOMMENDED,
this.useShouldInterceptAjaxRequest = false, this.useShouldInterceptAjaxRequest = false,
this.useShouldInterceptFetchRequest = false, this.useShouldInterceptFetchRequest = false,
this.incognito = false, this.incognito = false,
this.cacheEnabled = true, this.cacheEnabled = true,
this.transparentBackground = false, this.transparentBackground = false,
this.disableVerticalScroll = false, this.disableVerticalScroll = false,
this.disableHorizontalScroll = false, this.disableHorizontalScroll = false,
this.disableContextMenu = false, this.disableContextMenu = false,
this.supportZoom = true, this.supportZoom = true,
this.allowFileAccessFromFileURLs = false, this.allowFileAccessFromFileURLs = false,
this.allowUniversalAccessFromFileURLs = false, this.allowUniversalAccessFromFileURLs = false,
this.textZoom = 100, this.textZoom = 100,
this.clearSessionCache = false, this.clearSessionCache = false,
this.builtInZoomControls = true, this.builtInZoomControls = true,
this.displayZoomControls = false, this.displayZoomControls = false,
this.databaseEnabled = true, this.databaseEnabled = true,
this.domStorageEnabled = true, this.domStorageEnabled = true,
this.useWideViewPort = true, this.useWideViewPort = true,
this.safeBrowsingEnabled = true, this.safeBrowsingEnabled = true,
this.mixedContentMode, this.mixedContentMode,
this.allowContentAccess = true, this.allowContentAccess = true,
this.allowFileAccess = true, this.allowFileAccess = true,
this.appCachePath, this.appCachePath,
this.blockNetworkImage = false, this.blockNetworkImage = false,
this.blockNetworkLoads = false, this.blockNetworkLoads = false,
this.cacheMode = CacheMode.LOAD_DEFAULT, this.cacheMode = CacheMode.LOAD_DEFAULT,
this.cursiveFontFamily = "cursive", this.cursiveFontFamily = "cursive",
this.defaultFixedFontSize = 16, this.defaultFixedFontSize = 16,
this.defaultFontSize = 16, this.defaultFontSize = 16,
this.defaultTextEncodingName = "UTF-8", this.defaultTextEncodingName = "UTF-8",
this.disabledActionModeMenuItems, this.disabledActionModeMenuItems,
this.fantasyFontFamily = "fantasy", this.fantasyFontFamily = "fantasy",
this.fixedFontFamily = "monospace", this.fixedFontFamily = "monospace",
this.forceDark = ForceDark.FORCE_DARK_OFF, this.forceDark = ForceDark.FORCE_DARK_OFF,
this.geolocationEnabled = true, this.geolocationEnabled = true,
this.layoutAlgorithm, this.layoutAlgorithm,
this.loadWithOverviewMode = true, this.loadWithOverviewMode = true,
this.loadsImagesAutomatically = true, this.loadsImagesAutomatically = true,
this.minimumLogicalFontSize = 8, this.minimumLogicalFontSize = 8,
this.needInitialFocus = true, this.needInitialFocus = true,
this.offscreenPreRaster = false, this.offscreenPreRaster = false,
this.sansSerifFontFamily = "sans-serif", this.sansSerifFontFamily = "sans-serif",
this.serifFontFamily = "sans-serif", this.serifFontFamily = "sans-serif",
this.standardFontFamily = "sans-serif", this.standardFontFamily = "sans-serif",
this.saveFormData = true, this.saveFormData = true,
this.thirdPartyCookiesEnabled = true, this.thirdPartyCookiesEnabled = true,
this.hardwareAcceleration = true, this.hardwareAcceleration = true,
this.initialScale = 0, this.initialScale = 0,
this.supportMultipleWindows = false, this.supportMultipleWindows = false,
this.regexToCancelSubFramesLoading, this.regexToCancelSubFramesLoading,
this.useHybridComposition = false, this.useHybridComposition = false,
this.useShouldInterceptRequest = false, this.useShouldInterceptRequest = false,
this.useOnRenderProcessGone = false, this.useOnRenderProcessGone = false,
this.overScrollMode = OverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS, this.overScrollMode = OverScrollMode.OVER_SCROLL_IF_CONTENT_SCROLLS,
this.networkAvailable, this.networkAvailable,
this.scrollBarStyle = ScrollBarStyle.SCROLLBARS_INSIDE_OVERLAY, this.scrollBarStyle = ScrollBarStyle.SCROLLBARS_INSIDE_OVERLAY,
this.verticalScrollbarPosition = this.verticalScrollbarPosition =
VerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT, VerticalScrollbarPosition.SCROLLBAR_POSITION_DEFAULT,
this.scrollBarDefaultDelayBeforeFade, this.scrollBarDefaultDelayBeforeFade,
this.scrollbarFadingEnabled = true, this.scrollbarFadingEnabled = true,
this.scrollBarFadeDuration, this.scrollBarFadeDuration,
this.rendererPriorityPolicy, this.rendererPriorityPolicy,
this.disableDefaultErrorPage = false, this.disableDefaultErrorPage = false,
this.verticalScrollbarThumbColor, this.verticalScrollbarThumbColor,
this.verticalScrollbarTrackColor, this.verticalScrollbarTrackColor,
this.horizontalScrollbarThumbColor, this.horizontalScrollbarThumbColor,
this.horizontalScrollbarTrackColor, this.horizontalScrollbarTrackColor,
this.disallowOverScroll = false, this.disallowOverScroll = false,
this.enableViewportScale = false, this.enableViewportScale = false,
this.suppressesIncrementalRendering = false, this.suppressesIncrementalRendering = false,
this.allowsAirPlayForMediaPlayback = true, this.allowsAirPlayForMediaPlayback = true,
this.allowsBackForwardNavigationGestures = true, this.allowsBackForwardNavigationGestures = true,
this.allowsLinkPreview = true, this.allowsLinkPreview = true,
this.ignoresViewportScaleLimits = false, this.ignoresViewportScaleLimits = false,
this.allowsInlineMediaPlayback = false, this.allowsInlineMediaPlayback = false,
this.allowsPictureInPictureMediaPlayback = true, this.allowsPictureInPictureMediaPlayback = true,
this.isFraudulentWebsiteWarningEnabled = true, this.isFraudulentWebsiteWarningEnabled = true,
this.selectionGranularity = SelectionGranularity.DYNAMIC, this.selectionGranularity = SelectionGranularity.DYNAMIC,
this.dataDetectorTypes = const [DataDetectorTypes.NONE], this.dataDetectorTypes = const [DataDetectorTypes.NONE],
this.sharedCookiesEnabled = false, this.sharedCookiesEnabled = false,
this.automaticallyAdjustsScrollIndicatorInsets = false, this.automaticallyAdjustsScrollIndicatorInsets = false,
this.accessibilityIgnoresInvertColors = false, this.accessibilityIgnoresInvertColors = false,
this.decelerationRate = ScrollViewDecelerationRate.NORMAL, this.decelerationRate = ScrollViewDecelerationRate.NORMAL,
this.alwaysBounceVertical = false, this.alwaysBounceVertical = false,
this.alwaysBounceHorizontal = false, this.alwaysBounceHorizontal = false,
this.scrollsToTop = true, this.scrollsToTop = true,
this.isPagingEnabled = false, this.isPagingEnabled = false,
this.maximumZoomScale = 1.0, this.maximumZoomScale = 1.0,
this.minimumZoomScale = 1.0, this.minimumZoomScale = 1.0,
this.contentInsetAdjustmentBehavior = this.contentInsetAdjustmentBehavior =
ScrollViewContentInsetAdjustmentBehavior.NEVER, ScrollViewContentInsetAdjustmentBehavior.NEVER,
this.isDirectionalLockEnabled = false, this.isDirectionalLockEnabled = false,
this.mediaType, this.mediaType,
this.pageZoom = 1.0, this.pageZoom = 1.0,
this.limitsNavigationsToAppBoundDomains = false, this.limitsNavigationsToAppBoundDomains = false,
this.useOnNavigationResponse = false, this.useOnNavigationResponse = false,
this.applePayAPIEnabled = false, this.applePayAPIEnabled = false,
this.allowingReadAccessTo, this.allowingReadAccessTo,
this.disableLongPressContextMenuOnLinks = false, this.disableLongPressContextMenuOnLinks = false,
this.disableInputAccessoryView = false, this.disableInputAccessoryView = false,
this.underPageBackgroundColor, this.underPageBackgroundColor,
this.isTextInteractionEnabled = true, this.isTextInteractionEnabled = true,
this.isSiteSpecificQuirksModeEnabled = true, this.isSiteSpecificQuirksModeEnabled = true,
this.upgradeKnownHostsToHTTPS = true, this.upgradeKnownHostsToHTTPS = true,
this.iframeAllow, this.iframeAllow,
this.iframeAllowFullscreen, this.iframeAllowFullscreen,
this.iframeSandbox, this.iframeSandbox,
this.iframeReferrerPolicy, this.iframeReferrerPolicy,
this.iframeName, this.iframeName,
this.iframeCsp,}) { this.iframeCsp,
}) {
if (this.minimumFontSize == null) if (this.minimumFontSize == null)
this.minimumFontSize = this.minimumFontSize =
defaultTargetPlatform == TargetPlatform.android ? 8 : 0; defaultTargetPlatform == TargetPlatform.android ? 8 : 0;
@ -1388,7 +1389,8 @@ class InAppWebViewSettings
settings.iframeAllowFullscreen = map["iframeAllowFullscreen"]; settings.iframeAllowFullscreen = map["iframeAllowFullscreen"];
settings.iframeSandbox = (map["iframeSandbox"] as List<String?>?) settings.iframeSandbox = (map["iframeSandbox"] as List<String?>?)
?.map((e) => Sandbox.fromValue(e)) as List<Sandbox>?; ?.map((e) => Sandbox.fromValue(e)) as List<Sandbox>?;
settings.iframeReferrerPolicy = ReferrerPolicy.fromValue(map["iframeReferrerPolicy"]); settings.iframeReferrerPolicy =
ReferrerPolicy.fromValue(map["iframeReferrerPolicy"]);
settings.iframeName = map["iframeName"]; settings.iframeName = map["iframeName"];
settings.iframeCsp = map["iframeCsp"]; settings.iframeCsp = map["iframeCsp"];
} }
@ -1460,7 +1462,8 @@ class InAppWebViewSettings
settings.horizontalScrollbarTrackColor = settings.horizontalScrollbarTrackColor =
UtilColor.fromHex(map["horizontalScrollbarTrackColor"]); UtilColor.fromHex(map["horizontalScrollbarTrackColor"]);
} }
if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
settings.disallowOverScroll = map["disallowOverScroll"]; settings.disallowOverScroll = map["disallowOverScroll"];
settings.enableViewportScale = map["enableViewportScale"]; settings.enableViewportScale = map["enableViewportScale"];
settings.suppressesIncrementalRendering = settings.suppressesIncrementalRendering =

View File

@ -27,6 +27,8 @@ abstract class WebView {
/// ///
///**NOTE for Web**: it will be dispatched at the same time of [onLoadStop] event ///**NOTE for Web**: it will be dispatched at the same time of [onLoadStop] event
///because there isn't any way to capture the real load start event from an iframe. ///because there isn't any way to capture the real load start event from an iframe.
///If `window.location.href` isn't accessible inside the iframe,
///the [url] parameter will have the current value of the `iframe.src` attribute.
/// ///
///**Supported Platforms/Implementations**: ///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebViewClient.onPageStarted](https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap))) ///- Android native WebView ([Official API - WebViewClient.onPageStarted](https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)))
@ -36,6 +38,9 @@ abstract class WebView {
///Event fired when the [WebView] finishes loading an [url]. ///Event fired when the [WebView] finishes loading an [url].
/// ///
///**NOTE for Web**: If `window.location.href` isn't accessible inside the iframe,
///the [url] parameter will have the current value of the `iframe.src` attribute.
///
///**Supported Platforms/Implementations**: ///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebViewClient.onPageFinished](https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String))) ///- Android native WebView ([Official API - WebViewClient.onPageFinished](https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String)))
///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview))

View File

@ -47,8 +47,7 @@ class PlatformUtil {
} }
///Get cookie expiration date used by Web platform. ///Get cookie expiration date used by Web platform.
Future<String> getWebCookieExpirationDate( Future<String> getWebCookieExpirationDate({required DateTime date}) async {
{required DateTime date}) async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('date', () => date.millisecondsSinceEpoch); args.putIfAbsent('date', () => date.millisecondsSinceEpoch);
return await _channel.invokeMethod('getWebCookieExpirationDate', args); return await _channel.invokeMethod('getWebCookieExpirationDate', args);

View File

@ -4795,14 +4795,15 @@ class PermissionResourceType {
PermissionResourceType.DEVICE_ORIENTATION_AND_MOTION, PermissionResourceType.DEVICE_ORIENTATION_AND_MOTION,
].toSet(); ].toSet();
static PermissionResourceType? fromValue(dynamic? value) { static PermissionResourceType? fromValue(dynamic value) {
if (value != null) { if (value != null) {
try { try {
Set<PermissionResourceType> valueList = Set<PermissionResourceType> valueList =
<PermissionResourceType>[].toSet(); <PermissionResourceType>[].toSet();
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
valueList = PermissionResourceType._androidValues; valueList = PermissionResourceType._androidValues;
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { } else if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
valueList = PermissionResourceType._appleValues; valueList = PermissionResourceType._appleValues;
} }
return valueList.firstWhere((element) => element.toValue() == value); return valueList.firstWhere((element) => element.toValue() == value);
@ -7395,7 +7396,8 @@ class SslErrorType {
Set<SslErrorType> valueList = <SslErrorType>[].toSet(); Set<SslErrorType> valueList = <SslErrorType>[].toSet();
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
valueList = SslErrorType._androidValues; valueList = SslErrorType._androidValues;
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { } else if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
valueList = SslErrorType._appleValues; valueList = SslErrorType._appleValues;
} }
return valueList.firstWhere((element) => element.toValue() == value); return valueList.firstWhere((element) => element.toValue() == value);
@ -7426,7 +7428,8 @@ class SslErrorType {
default: default:
return "SSL_NOTYETVALID"; return "SSL_NOTYETVALID";
} }
} else if (defaultTargetPlatform == TargetPlatform.iOS || defaultTargetPlatform == TargetPlatform.macOS) { } else if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
switch (_value) { switch (_value) {
case 3: case 3:
return "DENY"; return "DENY";
@ -10768,8 +10771,7 @@ class Sandbox {
return _NONE; return _NONE;
} }
try { try {
return Sandbox.values return Sandbox.values.firstWhere((element) => element.toValue() == value);
.firstWhere((element) => element.toValue() == value);
} catch (e) { } catch (e) {
return null; return null;
} }
@ -10778,7 +10780,8 @@ class Sandbox {
String? toValue() => _value; String? toValue() => _value;
@override @override
String toString() => _value == null ? "allow-all" : (_value == "" ? "allow-none" : ""); String toString() =>
_value == null ? "allow-all" : (_value == "" ? "allow-none" : "");
static const _ALL = const Sandbox._internal(null); static const _ALL = const Sandbox._internal(null);
static const _NONE = const Sandbox._internal(""); static const _NONE = const Sandbox._internal("");
@ -10799,10 +10802,12 @@ class Sandbox {
static const ALLOW_MODALS = const Sandbox._internal("allow-modals"); static const ALLOW_MODALS = const Sandbox._internal("allow-modals");
///Lets the resource lock the screen orientation. ///Lets the resource lock the screen orientation.
static const ALLOW_ORIENTATION_LOCK = const Sandbox._internal("allow-orientation-lock"); static const ALLOW_ORIENTATION_LOCK =
const Sandbox._internal("allow-orientation-lock");
///Lets the resource use the Pointer Lock API. ///Lets the resource use the Pointer Lock API.
static const ALLOW_POINTER_LOCK = const Sandbox._internal("allow-pointer-lock"); static const ALLOW_POINTER_LOCK =
const Sandbox._internal("allow-pointer-lock");
///Allows popups (such as `window.open()`, `target="_blank"`, or `showModalDialog()`). ///Allows popups (such as `window.open()`, `target="_blank"`, or `showModalDialog()`).
///If this keyword is not used, the popup will silently fail to open. ///If this keyword is not used, the popup will silently fail to open.
@ -10810,10 +10815,12 @@ class Sandbox {
///Lets the sandboxed document open new windows without those windows inheriting the sandboxing. ///Lets the sandboxed document open new windows without those windows inheriting the sandboxing.
///For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to. ///For example, this can safely sandbox an advertisement without forcing the same restrictions upon the page the ad links to.
static const ALLOW_POPUPS_TO_ESCAPE_SANDBOX = const Sandbox._internal("allow-popups-to-escape-sandbox"); static const ALLOW_POPUPS_TO_ESCAPE_SANDBOX =
const Sandbox._internal("allow-popups-to-escape-sandbox");
///Lets the resource start a presentation session. ///Lets the resource start a presentation session.
static const ALLOW_PRESENTATION = const Sandbox._internal("allow-presentation"); static const ALLOW_PRESENTATION =
const Sandbox._internal("allow-presentation");
///If this token is not used, the resource is treated as being from a special origin that always fails the ///If this token is not used, the resource is treated as being from a special origin that always fails the
///same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs). ///same-origin policy (potentially preventing access to data storage/cookies and some JavaScript APIs).
@ -10823,13 +10830,15 @@ class Sandbox {
static const ALLOW_SCRIPTS = const Sandbox._internal("allow-scripts"); static const ALLOW_SCRIPTS = const Sandbox._internal("allow-scripts");
///Lets the resource navigate the top-level browsing context (the one named `_top`). ///Lets the resource navigate the top-level browsing context (the one named `_top`).
static const ALLOW_TOP_NAVIGATION = const Sandbox._internal("allow-top-navigation"); static const ALLOW_TOP_NAVIGATION =
const Sandbox._internal("allow-top-navigation");
///Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture. ///Lets the resource navigate the top-level browsing context, but only if initiated by a user gesture.
static const ALLOW_TOP_NAVIGATION_BY_USER_ACTIVATION = const Sandbox._internal("allow-top-navigation-by-user-activation"); static const ALLOW_TOP_NAVIGATION_BY_USER_ACTIVATION =
const Sandbox._internal("allow-top-navigation-by-user-activation");
bool operator ==(value) => value == _value; bool operator ==(value) => value == _value;
@override @override
int get hashCode => _value.hashCode; int get hashCode => _value.hashCode;
} }

View File

@ -11,10 +11,12 @@ class HeadlessInAppWebViewWebElement {
InAppWebViewWebElement? webView; InAppWebViewWebElement? webView;
late MethodChannel? _channel; late MethodChannel? _channel;
HeadlessInAppWebViewWebElement({required this.id, required BinaryMessenger messenger, HeadlessInAppWebViewWebElement(
required this.webView}) { {required this.id,
required BinaryMessenger messenger,
required this.webView}) {
this._messenger = messenger; this._messenger = messenger;
_channel = MethodChannel( _channel = MethodChannel(
'com.pichillilorenzo/flutter_headless_inappwebview_${this.id}', 'com.pichillilorenzo/flutter_headless_inappwebview_${this.id}',
const StandardMethodCodec(), const StandardMethodCodec(),
@ -38,7 +40,8 @@ class HeadlessInAppWebViewWebElement {
default: default:
throw PlatformException( throw PlatformException(
code: 'Unimplemented', code: 'Unimplemented',
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'', details:
'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
); );
} }
} }
@ -54,7 +57,8 @@ class HeadlessInAppWebViewWebElement {
Size getSize() { Size getSize() {
var width = webView?.iframe.getBoundingClientRect().width.toDouble() ?? 0.0; var width = webView?.iframe.getBoundingClientRect().width.toDouble() ?? 0.0;
var height = webView?.iframe.getBoundingClientRect().height.toDouble() ?? 0.0; var height =
webView?.iframe.getBoundingClientRect().height.toDouble() ?? 0.0;
return Size(width, height); return Size(width, height);
} }
@ -64,4 +68,4 @@ class HeadlessInAppWebViewWebElement {
webView?.dispose(); webView?.dispose();
webView = null; webView = null;
} }
} }

View File

@ -20,14 +20,16 @@ class HeadlessInAppWebViewManager {
const StandardMethodCodec(), const StandardMethodCodec(),
_messenger, _messenger,
); );
HeadlessInAppWebViewManager._sharedChannel.setMethodCallHandler(handleMethod); HeadlessInAppWebViewManager._sharedChannel
.setMethodCallHandler(handleMethod);
} }
Future<dynamic> handleMethod(MethodCall call) async { Future<dynamic> handleMethod(MethodCall call) async {
switch (call.method) { switch (call.method) {
case "run": case "run":
String id = call.arguments["id"]; String id = call.arguments["id"];
Map<String, dynamic> params = call.arguments["params"].cast<String, dynamic>(); Map<String, dynamic> params =
call.arguments["params"].cast<String, dynamic>();
run(id, params); run(id, params);
break; break;
default: default:
@ -39,24 +41,24 @@ class HeadlessInAppWebViewManager {
void run(String id, Map<String, dynamic> params) { void run(String id, Map<String, dynamic> params) {
var webView = InAppWebViewWebElement(viewId: id, messenger: _messenger); var webView = InAppWebViewWebElement(viewId: id, messenger: _messenger);
var headlessWebView = HeadlessInAppWebViewWebElement( var headlessWebView = HeadlessInAppWebViewWebElement(
id: id, id: id, messenger: _messenger, webView: webView);
messenger: _messenger,
webView: webView
);
WebPlatformManager.webViews.putIfAbsent(id, () => webView); WebPlatformManager.webViews.putIfAbsent(id, () => webView);
webView.iframe.style.display = 'none'; webView.iframe.style.display = 'none';
Map<String, dynamic> initialSettings = params["initialSettings"].cast<String, dynamic>(); Map<String, dynamic> initialSettings =
params["initialSettings"].cast<String, dynamic>();
if (initialSettings.isEmpty) { if (initialSettings.isEmpty) {
webView.initialSettings = InAppWebViewSettings(); webView.initialSettings = InAppWebViewSettings();
} else { } else {
webView.initialSettings = InAppWebViewSettings.fromMap(initialSettings); webView.initialSettings = InAppWebViewSettings.fromMap(initialSettings);
} }
webView.initialUrlRequest = URLRequest.fromMap(params["initialUrlRequest"]?.cast<String, dynamic>()); webView.initialUrlRequest = URLRequest.fromMap(
params["initialUrlRequest"]?.cast<String, dynamic>());
webView.initialFile = params["initialFile"]; webView.initialFile = params["initialFile"];
webView.initialData = InAppWebViewInitialData.fromMap(params["initialData"]?.cast<String, dynamic>()); webView.initialData = InAppWebViewInitialData.fromMap(
params["initialData"]?.cast<String, dynamic>());
document.body?.append(webView.iframe); document.body?.append(webView.iframe);
webView.prepare(); webView.prepare();
headlessWebView.onWebViewCreated(); headlessWebView.onWebViewCreated();
webView.makeInitialLoad(); webView.makeInitialLoad();
} }
} }

View File

@ -21,7 +21,8 @@ class InAppWebViewWebElement {
late js.JsObject bridgeJsObject; late js.JsObject bridgeJsObject;
bool isLoading = false; bool isLoading = false;
InAppWebViewWebElement({required dynamic viewId, required BinaryMessenger messenger}) { InAppWebViewWebElement(
{required dynamic viewId, required BinaryMessenger messenger}) {
this._viewId = viewId; this._viewId = viewId;
this._messenger = messenger; this._messenger = messenger;
iframe = IFrameElement() iframe = IFrameElement()
@ -38,8 +39,10 @@ class InAppWebViewWebElement {
this._channel?.setMethodCallHandler(handleMethodCall); this._channel?.setMethodCallHandler(handleMethodCall);
bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]); bridgeJsObject = js.JsObject.fromBrowserObject(
bridgeJsObject['webViews'][_viewId] = bridgeJsObject.callMethod("createFlutterInAppWebView", [_viewId, iframe.id]); js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
bridgeJsObject['webViews'][_viewId] = bridgeJsObject
.callMethod("createFlutterInAppWebView", [_viewId, iframe.id]);
} }
/// Handles method calls over the MethodChannel of this plugin. /// Handles method calls over the MethodChannel of this plugin.
@ -48,7 +51,8 @@ class InAppWebViewWebElement {
case "getIFrameId": case "getIFrameId":
return iframe.id; return iframe.id;
case "loadUrl": case "loadUrl":
URLRequest urlRequest = URLRequest.fromMap(call.arguments["urlRequest"].cast<String, dynamic>())!; URLRequest urlRequest = URLRequest.fromMap(
call.arguments["urlRequest"].cast<String, dynamic>())!;
await loadUrl(urlRequest: urlRequest); await loadUrl(urlRequest: urlRequest);
break; break;
case "loadData": case "loadData":
@ -84,7 +88,8 @@ class InAppWebViewWebElement {
case "getSettings": case "getSettings":
return await settings.toMap(); return await settings.toMap();
case "setSettings": case "setSettings":
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(call.arguments["settings"].cast<String, dynamic>()); InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(
call.arguments["settings"].cast<String, dynamic>());
setSettings(newSettings); setSettings(newSettings);
break; break;
case "dispose": case "dispose":
@ -93,7 +98,8 @@ class InAppWebViewWebElement {
default: default:
throw PlatformException( throw PlatformException(
code: 'Unimplemented', code: 'Unimplemented',
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'', details:
'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
); );
} }
} }
@ -108,13 +114,17 @@ class InAppWebViewWebElement {
} }
iframe.allow = settings.iframeAllow ?? iframe.allow; iframe.allow = settings.iframeAllow ?? iframe.allow;
iframe.allowFullscreen = settings.iframeAllowFullscreen ?? iframe.allowFullscreen; iframe.allowFullscreen =
iframe.referrerPolicy = settings.iframeReferrerPolicy?.toValue() ?? iframe.referrerPolicy; settings.iframeAllowFullscreen ?? iframe.allowFullscreen;
iframe.referrerPolicy =
settings.iframeReferrerPolicy?.toValue() ?? iframe.referrerPolicy;
iframe.name = settings.iframeName ?? iframe.name; iframe.name = settings.iframeName ?? iframe.name;
iframe.csp = settings.iframeCsp ?? iframe.csp; iframe.csp = settings.iframeCsp ?? iframe.csp;
if (settings.iframeSandbox != null && settings.iframeSandbox != Sandbox.ALLOW_ALL) { if (settings.iframeSandbox != null &&
iframe.setAttribute("sandbox", settings.iframeSandbox!.map((e) => e.toValue()).join(" ")); settings.iframeSandbox != Sandbox.ALLOW_ALL) {
iframe.setAttribute(
"sandbox", settings.iframeSandbox!.map((e) => e.toValue()).join(" "));
} else if (settings.iframeSandbox == Sandbox.ALLOW_ALL) { } else if (settings.iframeSandbox == Sandbox.ALLOW_ALL) {
iframe.removeAttribute("sandbox"); iframe.removeAttribute("sandbox");
} else if (sandbox != Sandbox.values) { } else if (sandbox != Sandbox.values) {
@ -143,23 +153,26 @@ class InAppWebViewWebElement {
} }
} }
Future<HttpRequest> _makeRequest(URLRequest urlRequest, {bool? withCredentials, String? responseType, String? mimeType, void onProgress(ProgressEvent e)?}) { Future<HttpRequest> _makeRequest(URLRequest urlRequest,
return HttpRequest.request( {bool? withCredentials,
urlRequest.url?.toString() ?? 'about:blank', String? responseType,
String? mimeType,
void onProgress(ProgressEvent e)?}) {
return HttpRequest.request(urlRequest.url?.toString() ?? 'about:blank',
method: urlRequest.method, method: urlRequest.method,
requestHeaders: urlRequest.headers, requestHeaders: urlRequest.headers,
sendData: urlRequest.body, sendData: urlRequest.body,
withCredentials: withCredentials, withCredentials: withCredentials,
responseType: responseType, responseType: responseType,
mimeType: mimeType, mimeType: mimeType,
onProgress: onProgress onProgress: onProgress);
);
} }
String _convertHttpResponseToData(HttpRequest httpRequest) { String _convertHttpResponseToData(HttpRequest httpRequest) {
final String contentType = final String contentType =
httpRequest.getResponseHeader('content-type') ?? 'text/html'; httpRequest.getResponseHeader('content-type') ?? 'text/html';
return 'data:$contentType,' + Uri.encodeFull(httpRequest.responseText ?? ''); return 'data:$contentType,' +
Uri.encodeFull(httpRequest.responseText ?? '');
} }
Future<void> loadUrl({required URLRequest urlRequest}) async { Future<void> loadUrl({required URLRequest urlRequest}) async {
@ -171,7 +184,8 @@ class InAppWebViewWebElement {
} }
} }
Future<void> loadData({required String data, String mimeType = "text/html"}) async { Future<void> loadData(
{required String data, String mimeType = "text/html"}) async {
iframe.src = 'data:$mimeType,' + Uri.encodeFull(data); iframe.src = 'data:$mimeType,' + Uri.encodeFull(data);
} }
@ -247,7 +261,8 @@ class InAppWebViewWebElement {
if (settings.iframeSandbox != newSettings.iframeSandbox) { if (settings.iframeSandbox != newSettings.iframeSandbox) {
var sandbox = newSettings.iframeSandbox; var sandbox = newSettings.iframeSandbox;
if (sandbox != null && sandbox != Sandbox.ALLOW_ALL) { if (sandbox != null && sandbox != Sandbox.ALLOW_ALL) {
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" ")); iframe.setAttribute(
"sandbox", sandbox.map((e) => e.toValue()).join(" "));
} else if (sandbox == Sandbox.ALLOW_ALL) { } else if (sandbox == Sandbox.ALLOW_ALL) {
iframe.removeAttribute("sandbox"); iframe.removeAttribute("sandbox");
} }
@ -263,33 +278,24 @@ class InAppWebViewWebElement {
void onLoadStart(String url) async { void onLoadStart(String url) async {
isLoading = true; isLoading = true;
var obj = { var obj = {"url": url};
"url": url
};
await _channel?.invokeMethod("onLoadStart", obj); await _channel?.invokeMethod("onLoadStart", obj);
} }
void onLoadStop(String url) async { void onLoadStop(String url) async {
isLoading = false; isLoading = false;
var obj = { var obj = {"url": url};
"url": url
};
await _channel?.invokeMethod("onLoadStop", obj); await _channel?.invokeMethod("onLoadStop", obj);
} }
void onUpdateVisitedHistory(String url) async { void onUpdateVisitedHistory(String url) async {
var obj = { var obj = {"url": url};
"url": url
};
await _channel?.invokeMethod("onUpdateVisitedHistory", obj); await _channel?.invokeMethod("onUpdateVisitedHistory", obj);
} }
void onScrollChanged(int x, int y) async { void onScrollChanged(int x, int y) async {
var obj = { var obj = {"x": x, "y": y};
"x": x,
"y": y
};
await _channel?.invokeMethod("onScrollChanged", obj); await _channel?.invokeMethod("onScrollChanged", obj);
} }
@ -310,14 +316,12 @@ class InAppWebViewWebElement {
default: default:
messageLevel = 1; messageLevel = 1;
} }
var obj = { var obj = {"messageLevel": messageLevel, "message": message};
"messageLevel": messageLevel,
"message": message
};
await _channel?.invokeMethod("onConsoleMessage", obj); await _channel?.invokeMethod("onConsoleMessage", obj);
} }
Future<bool?> onCreateWindow(int windowId, String url, String? target, String? windowFeatures) async { Future<bool?> onCreateWindow(
int windowId, String url, String? target, String? windowFeatures) async {
Map<String, dynamic> windowFeaturesMap = {}; Map<String, dynamic> windowFeaturesMap = {};
List<String> features = windowFeatures?.split(",") ?? []; List<String> features = windowFeatures?.split(",") ?? [];
for (var feature in features) { for (var feature in features) {
@ -336,10 +340,7 @@ class InAppWebViewWebElement {
var obj = { var obj = {
"windowId": windowId, "windowId": windowId,
"isForMainFrame": true, "isForMainFrame": true,
"request": { "request": {"url": url, "method": "GET"},
"url": url,
"method": "GET"
},
"windowFeatures": windowFeaturesMap "windowFeatures": windowFeaturesMap
}; };
return await _channel?.invokeMethod("onCreateWindow", obj); return await _channel?.invokeMethod("onCreateWindow", obj);
@ -354,9 +355,7 @@ class InAppWebViewWebElement {
} }
void onPrint(String? url) async { void onPrint(String? url) async {
var obj = { var obj = {"url": url};
"url": url
};
await _channel?.invokeMethod("onPrint", obj); await _channel?.invokeMethod("onPrint", obj);
} }
@ -370,18 +369,13 @@ class InAppWebViewWebElement {
} }
void onTitleChanged(String? title) async { void onTitleChanged(String? title) async {
var obj = { var obj = {"title": title};
"title": title
};
await _channel?.invokeMethod("onTitleChanged", obj); await _channel?.invokeMethod("onTitleChanged", obj);
} }
void onZoomScaleChanged(double oldScale, double newScale) async { void onZoomScaleChanged(double oldScale, double newScale) async {
var obj = { var obj = {"oldScale": oldScale, "newScale": newScale};
"oldScale": oldScale,
"newScale": newScale
};
await _channel?.invokeMethod("onZoomScaleChanged", obj); await _channel?.invokeMethod("onZoomScaleChanged", obj);
} }
@ -393,10 +387,11 @@ class InAppWebViewWebElement {
if (WebPlatformManager.webViews.containsKey(_viewId)) { if (WebPlatformManager.webViews.containsKey(_viewId)) {
WebPlatformManager.webViews.remove(_viewId); WebPlatformManager.webViews.remove(_viewId);
} }
bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]); bridgeJsObject = js.JsObject.fromBrowserObject(
js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
var webViews = bridgeJsObject['webViews'] as js.JsObject; var webViews = bridgeJsObject['webViews'] as js.JsObject;
if (webViews.hasProperty(_viewId)) { if (webViews.hasProperty(_viewId)) {
webViews.deleteProperty(_viewId); webViews.deleteProperty(_viewId);
} }
} }
} }

View File

@ -1 +1 @@
export 'web_platform.dart'; export 'web_platform.dart';

View File

@ -11,7 +11,7 @@ class PlatformUtil {
PlatformUtil({required BinaryMessenger messenger}) { PlatformUtil({required BinaryMessenger messenger}) {
this._messenger = messenger; this._messenger = messenger;
_channel = MethodChannel( _channel = MethodChannel(
'com.pichillilorenzo/flutter_inappwebview_platformutil', 'com.pichillilorenzo/flutter_inappwebview_platformutil',
const StandardMethodCodec(), const StandardMethodCodec(),
@ -29,13 +29,15 @@ class PlatformUtil {
default: default:
throw PlatformException( throw PlatformException(
code: 'Unimplemented', code: 'Unimplemented',
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'', details:
'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
); );
} }
} }
String getWebCookieExpirationDate(int timestamp) { String getWebCookieExpirationDate(int timestamp) {
var bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]); var bridgeJsObject = js.JsObject.fromBrowserObject(
js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
return bridgeJsObject.callMethod("getCookieExpirationDate", [timestamp]); return bridgeJsObject.callMethod("getCookieExpirationDate", [timestamp]);
} }
@ -43,4 +45,4 @@ class PlatformUtil {
_channel?.setMethodCallHandler(null); _channel?.setMethodCallHandler(null);
_channel = null; _channel = null;
} }
} }

View File

@ -1 +1 @@
export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart'; export 'dart_ui_fake.dart' if (dart.library.html) 'dart_ui_real.dart';

View File

@ -26,4 +26,4 @@ class webOnlyAssetManager {
} }
/// Signature of callbacks that have no arguments and return no data. /// Signature of callbacks that have no arguments and return no data.
typedef VoidCallback = void Function(); typedef VoidCallback = void Function();

View File

@ -1 +1 @@
export 'dart:ui'; export 'dart:ui';

View File

@ -12,16 +12,15 @@ import 'package:js/js.dart';
/// ///
/// This is used as the default implementation for [WebView] on web. /// This is used as the default implementation for [WebView] on web.
class FlutterInAppWebViewWebPlatform { class FlutterInAppWebViewWebPlatform {
/// Constructs a new instance of [FlutterInAppWebViewWebPlatform]. /// Constructs a new instance of [FlutterInAppWebViewWebPlatform].
FlutterInAppWebViewWebPlatform(Registrar registrar) { FlutterInAppWebViewWebPlatform(Registrar registrar) {
ui.platformViewRegistry.registerViewFactory( ui.platformViewRegistry.registerViewFactory(
'com.pichillilorenzo/flutter_inappwebview', 'com.pichillilorenzo/flutter_inappwebview', (int viewId) {
(int viewId) { var webView =
var webView = InAppWebViewWebElement(viewId: viewId, messenger: registrar); InAppWebViewWebElement(viewId: viewId, messenger: registrar);
WebPlatformManager.webViews.putIfAbsent(viewId, () => webView); WebPlatformManager.webViews.putIfAbsent(viewId, () => webView);
return webView.iframe; return webView.iframe;
}); });
} }
static void registerWith(Registrar registrar) { static void registerWith(Registrar registrar) {
@ -34,15 +33,19 @@ class FlutterInAppWebViewWebPlatform {
/// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()` /// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()`
@JS('flutter_inappwebview.nativeCommunication') @JS('flutter_inappwebview.nativeCommunication')
external set _nativeCommunication(Future<dynamic> Function(String method, dynamic viewId, [List? args]) f); external set _nativeCommunication(
Future<dynamic> Function(String method, dynamic viewId, [List? args]) f);
/// Allows calling the assigned function from Dart as well. /// Allows calling the assigned function from Dart as well.
@JS() @JS()
external Future<dynamic> nativeCommunication(String method, dynamic viewId, [List? args]); external Future<dynamic> nativeCommunication(String method, dynamic viewId,
[List? args]);
Future<dynamic> _dartNativeCommunication(String method, dynamic viewId, [List? args]) async { Future<dynamic> _dartNativeCommunication(String method, dynamic viewId,
[List? args]) async {
if (WebPlatformManager.webViews.containsKey(viewId)) { if (WebPlatformManager.webViews.containsKey(viewId)) {
var webViewHtmlElement = WebPlatformManager.webViews[viewId] as InAppWebViewWebElement; var webViewHtmlElement =
WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
switch (method) { switch (method) {
case 'onLoadStart': case 'onLoadStart':
var url = args![0] as String; var url = args![0] as String;
@ -71,7 +74,8 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId, [List? a
var url = args[1] as String? ?? 'about:blank'; var url = args[1] as String? ?? 'about:blank';
var target = args[2] as String?; var target = args[2] as String?;
var windowFeatures = args[3] as String?; var windowFeatures = args[3] as String?;
return await webViewHtmlElement.onCreateWindow(windowId, url, target, windowFeatures); return await webViewHtmlElement.onCreateWindow(
windowId, url, target, windowFeatures);
case 'onWindowFocus': case 'onWindowFocus':
webViewHtmlElement.onWindowFocus(); webViewHtmlElement.onWindowFocus();
break; break;
@ -79,7 +83,7 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId, [List? a
webViewHtmlElement.onWindowBlur(); webViewHtmlElement.onWindowBlur();
break; break;
case 'onPrint': case 'onPrint':
var url = args![0] as String?; var url = args![0] as String?;
webViewHtmlElement.onPrint(url); webViewHtmlElement.onPrint(url);
break; break;
case 'onEnterFullscreen': case 'onEnterFullscreen':
@ -99,4 +103,4 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId, [List? a
break; break;
} }
} }
} }

View File

@ -1,4 +1,4 @@
abstract class WebPlatformManager { abstract class WebPlatformManager {
static final String BRIDGE_JS_OBJECT_NAME = "flutter_inappwebview"; static final String BRIDGE_JS_OBJECT_NAME = "flutter_inappwebview";
static final Map<dynamic, dynamic> webViews = {}; static final Map<dynamic, dynamic> webViews = {};
} }