From fcb965eac67485798008a45a4f0ef66d1648aff8 Mon Sep 17 00:00:00 2001 From: xuty Date: Fri, 27 Mar 2020 07:40:52 +0800 Subject: [PATCH 01/40] fix cookie .secure property --- ios/Classes/MyCookieManager.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/Classes/MyCookieManager.swift b/ios/Classes/MyCookieManager.swift index 5c44171f..289342a7 100755 --- a/ios/Classes/MyCookieManager.swift +++ b/ios/Classes/MyCookieManager.swift @@ -90,7 +90,9 @@ class MyCookieManager: NSObject, FlutterPlugin { if maxAge != nil { properties[.maximumAge] = String(maxAge!) } - properties[.secure] = (isSecure != nil && isSecure!) ? "TRUE" : "FALSE" + if isSecure != nil && isSecure! { + properties[.secure] = "TRUE" + } let cookie = HTTPCookie(properties: properties)! MyCookieManager.httpCookieStore!.setCookie(cookie, completionHandler: {() in From 6e18699dd517ad1d2b36840f64282f3bb8852553 Mon Sep 17 00:00:00 2001 From: savy91 Date: Mon, 19 Apr 2021 17:51:24 +0200 Subject: [PATCH 02/40] Make sure that when we want to open a new instance of a custom chrome tab, we are opening a new instance with the provided url and not an old instance. --- android/src/main/AndroidManifest.xml | 4 +++- .../ChromeSafariBrowserManager.java | 3 +++ .../android/chrome_custom_tabs_options.dart | 11 +++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 40dc1267..daff949a 100755 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -8,7 +8,9 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density" /> + android:name="com.pichillilorenzo.flutter_inappwebview.chrome_custom_tabs.ChromeCustomTabsActivity" + android:launchMode="singleInstance" + /> toMap() { @@ -53,7 +58,8 @@ class AndroidChromeCustomTabsOptions "enableUrlBarHiding": enableUrlBarHiding, "instantAppsEnabled": instantAppsEnabled, "packageName": packageName, - "keepAliveEnabled": keepAliveEnabled + "keepAliveEnabled": keepAliveEnabled, + "noHistory": noHistory }; } @@ -68,6 +74,7 @@ class AndroidChromeCustomTabsOptions options.instantAppsEnabled = map["instantAppsEnabled"]; options.packageName = map["packageName"]; options.keepAliveEnabled = map["keepAliveEnabled"]; + options.noHistory = map["noHistory"]; return options; } From 19ffe781e68dcc9fdd339bf0508642407a47ce11 Mon Sep 17 00:00:00 2001 From: Caleb Jones Date: Mon, 3 May 2021 10:31:54 -0400 Subject: [PATCH 03/40] Fix parsing crash on null value. --- ios/Classes/Options.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ios/Classes/Options.swift b/ios/Classes/Options.swift index 286a2f83..96ba50eb 100755 --- a/ios/Classes/Options.swift +++ b/ios/Classes/Options.swift @@ -16,8 +16,10 @@ public class Options: NSObject { func parse(options: [String: Any?]) -> Options { for (key, value) in options { - if value != nil, !(value is NSNull), self.responds(to: Selector(key)) { - self.setValue(value, forKey: key) + if !(value is NSNull) { + if self.responds(to: Selector(key)) { + self.setValue(value, forKey: key) + } } } return self From 397998788b258ca1a9d0407d2dd1bde683b4e50a Mon Sep 17 00:00:00 2001 From: aleksandrpaskevic Date: Mon, 31 May 2021 17:18:06 +0300 Subject: [PATCH 04/40] fix bug when in String[] array come null --- .../in_app_webview/InAppWebViewChromeClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java index 224d75cd..c4afd089 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java @@ -1004,7 +1004,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR private Boolean arrayContainsString(String[] array, String pattern) { for (String content : array) { - if (content.contains(pattern)) { + if (content != null && content.contains(pattern)) { return true; } } From bedceb0a14d499412eb616f54fe95efd1ad5b7e8 Mon Sep 17 00:00:00 2001 From: Christoph Eck Date: Mon, 14 Jun 2021 16:56:26 +0200 Subject: [PATCH 05/40] fix: use in NavigationAction request toMap method --- lib/src/types.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/types.dart b/lib/src/types.dart index eb9d1d68..e97f9ff8 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -4052,7 +4052,7 @@ class NavigationAction { Map toMap() { return { - "request": request.toString(), + "request": request.toMap(), "isForMainFrame": isForMainFrame, "androidHasGesture": androidHasGesture, "androidIsRedirect": androidIsRedirect, From 3c60c15a81e91b6d24c0fb85f00b3583afaec637 Mon Sep 17 00:00:00 2001 From: cloudygeek Date: Fri, 18 Jun 2021 09:27:27 +0100 Subject: [PATCH 06/40] Update Options.swift checking if object is null before checking if nil. causes to crash if null. --- ios/Classes/Options.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/Options.swift b/ios/Classes/Options.swift index 286a2f83..46ecf21c 100755 --- a/ios/Classes/Options.swift +++ b/ios/Classes/Options.swift @@ -16,7 +16,7 @@ public class Options: NSObject { func parse(options: [String: Any?]) -> Options { for (key, value) in options { - if value != nil, !(value is NSNull), self.responds(to: Selector(key)) { + if !(value is NSNull), value != nil, self.responds(to: Selector(key)) { self.setValue(value, forKey: key) } } From 66dca7b1365a7b253eee1323dc72aa6783115034 Mon Sep 17 00:00:00 2001 From: Randy Secrist Date: Thu, 19 Aug 2021 15:37:04 -0600 Subject: [PATCH 07/40] make mockserver a testImplementation dep --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index a5e831c4..77d0f41c 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -48,7 +48,7 @@ android { implementation 'androidx.webkit:webkit:1.4.0' implementation 'androidx.browser:browser:1.3.0' implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.squareup.okhttp3:mockwebserver:3.14.7' + testImplementation 'com.squareup.okhttp3:mockwebserver:3.14.7' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' } } From e29bc782d8608d66f2d5230815266bd3bcc4bb31 Mon Sep 17 00:00:00 2001 From: Randy Secrist Date: Thu, 19 Aug 2021 17:39:40 -0600 Subject: [PATCH 08/40] use okhttp instead of mockserver --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 77d0f41c..3bf9477b 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -48,7 +48,7 @@ android { implementation 'androidx.webkit:webkit:1.4.0' implementation 'androidx.browser:browser:1.3.0' implementation 'androidx.appcompat:appcompat:1.2.0' - testImplementation 'com.squareup.okhttp3:mockwebserver:3.14.7' + implementation 'com.squareup.okhttp3:okhttp:3.14.9' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' } } From 4e47efe111b6ca4eb5d562d28a92a07a663e0e67 Mon Sep 17 00:00:00 2001 From: Michael Kao Date: Tue, 28 Sep 2021 12:02:24 +0200 Subject: [PATCH 09/40] Adds missing body to URLRequest mapping. --- ios/Classes/Types/URLRequest.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/Classes/Types/URLRequest.swift b/ios/Classes/Types/URLRequest.swift index 336ea693..efaf3e3c 100644 --- a/ios/Classes/Types/URLRequest.swift +++ b/ios/Classes/Types/URLRequest.swift @@ -63,6 +63,7 @@ extension URLRequest { "url": url?.absoluteString, "method": httpMethod, "headers": allHTTPHeaderFields, + "body": httpBody.map(FlutterStandardTypedData.init(bytes:)), "iosAllowsCellularAccess": allowsCellularAccess, "iosAllowsConstrainedNetworkAccess": iosAllowsConstrainedNetworkAccess, "iosAllowsExpensiveNetworkAccess": iosAllowsExpensiveNetworkAccess, From 42743f23eb11191f07d36be3c2e0db2b7188559f Mon Sep 17 00:00:00 2001 From: Le Minh Hoang Date: Sun, 24 Oct 2021 23:11:21 +0700 Subject: [PATCH 10/40] fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS --- ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift index 6fb9a1be..4bfa9e75 100644 --- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift @@ -21,6 +21,10 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate { self.channel?.setMethodCallHandler(self.handle) } + deinit { + dispose() + } + public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { let arguments = call.arguments as? NSDictionary From f43c8c2c681506d590b181906b923b24e4d5032b Mon Sep 17 00:00:00 2001 From: rsydor <79581663+rsydor@users.noreply.github.com> Date: Mon, 6 Dec 2021 17:09:57 +0100 Subject: [PATCH 11/40] Update InAppWebView.java Fix crash --- .../flutter_inappwebview/in_app_webview/InAppWebView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java index dcde9159..63354eed 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java @@ -1302,7 +1302,7 @@ final public class InAppWebView extends InputAwareWebView { public void run() { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); - if (imm != null && !imm.isAcceptingText()) { + if (containerView!=null && imm != null && !imm.isAcceptingText()) { imm.hideSoftInputFromWindow( containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); From 3a36aec87e9e618ad1ff78a0e45646c1402a1f4a Mon Sep 17 00:00:00 2001 From: Adrien Jalabert Date: Mon, 13 Dec 2021 17:56:34 +0100 Subject: [PATCH 12/40] Add wasm mime type --- lib/src/mime_type_resolver.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/mime_type_resolver.dart b/lib/src/mime_type_resolver.dart index 00732168..a01fe4b1 100644 --- a/lib/src/mime_type_resolver.dart +++ b/lib/src/mime_type_resolver.dart @@ -580,6 +580,7 @@ class MimeTypeResolver { "zirz": "application/vnd.zul", "zaz": "application/vnd.zzazz.deck+xml", "vxml": "application/voicexml+xml", + "wasm": "application/wasm", "wgt": "application/widget", "hlp": "application/winhlp", "wsdl": "application/wsdl+xml", From 961065ef3a304a0a3770c144ccb953149df4c0b5 Mon Sep 17 00:00:00 2001 From: Adrien Jalabert Date: Tue, 14 Dec 2021 21:58:55 +0100 Subject: [PATCH 13/40] Remove charset of binary files --- lib/src/in_app_localhost_server.dart | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/src/in_app_localhost_server.dart b/lib/src/in_app_localhost_server.dart index 7bde49e6..2c7d2c5d 100755 --- a/lib/src/in_app_localhost_server.dart +++ b/lib/src/in_app_localhost_server.dart @@ -56,17 +56,16 @@ class InAppLocalhostServer { return; } - var contentType = ['text', 'html']; + var contentType = ContentType('text', 'html', charset: 'utf-8'); if (!request.requestedUri.path.endsWith('/') && request.requestedUri.pathSegments.isNotEmpty) { var mimeType = MimeTypeResolver.lookup(request.requestedUri.path); if (mimeType != null) { - contentType = mimeType.split('/'); + contentType = _getContentTypeFromMimeType(mimeType); } } - request.response.headers.contentType = - ContentType(contentType[0], contentType[1], charset: 'utf-8'); + request.response.headers.contentType = contentType; request.response.add(body); request.response.close(); }); @@ -93,4 +92,20 @@ class InAppLocalhostServer { bool isRunning() { return this._server != null; } + + ContentType _getContentTypeFromMimeType(String mimeType) { + final contentType = mimeType.split('/'); + String? charset; + + if (_isTextFile(mimeType)) { + charset = 'utf-8'; + } + + return ContentType(contentType[0], contentType[1], charset: charset); + } + + bool _isTextFile(String mimeType) { + final textFile = RegExp(r'^text\/|^application\/(javascript|json)'); + return textFile.hasMatch(mimeType); + } } From 440ff8180331b516f12fc0229ecec03529bf27e2 Mon Sep 17 00:00:00 2001 From: RodXander Date: Wed, 22 Dec 2021 16:51:38 -0600 Subject: [PATCH 14/40] Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null. --- lib/src/in_app_webview/headless_in_app_webview.dart | 4 +--- lib/src/in_app_webview/in_app_webview.dart | 12 +++--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index f19b5152..3185aa92 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -139,9 +139,7 @@ class HeadlessInAppWebView implements WebView { args.putIfAbsent( 'params', () => { - 'initialUrlRequest': (this.initialUrlRequest ?? - URLRequest(url: Uri.parse("about:blank"))) - .toMap(), + 'initialUrlRequest': this.initialUrlRequest?.toMap(), 'initialFile': this.initialFile, 'initialData': this.initialData?.toMap(), 'initialOptions': this.initialOptions?.toMap() ?? {}, diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index 7ef7ee2f..f16e5eb5 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -395,9 +395,7 @@ class _InAppWebViewState extends State { viewType: 'com.pichillilorenzo/flutter_inappwebview', layoutDirection: TextDirection.rtl, creationParams: { - 'initialUrlRequest': (widget.initialUrlRequest ?? - URLRequest(url: Uri.parse("about:blank"))) - .toMap(), + 'initialUrlRequest': widget.initialUrlRequest?.toMap(), 'initialFile': widget.initialFile, 'initialData': widget.initialData?.toMap(), 'initialOptions': widget.initialOptions?.toMap() ?? {}, @@ -425,9 +423,7 @@ class _InAppWebViewState extends State { gestureRecognizers: widget.gestureRecognizers, layoutDirection: TextDirection.rtl, creationParams: { - 'initialUrlRequest': (widget.initialUrlRequest ?? - URLRequest(url: Uri.parse("about:blank"))) - .toMap(), + 'initialUrlRequest': widget.initialUrlRequest?.toMap(), 'initialFile': widget.initialFile, 'initialData': widget.initialData?.toMap(), 'initialOptions': widget.initialOptions?.toMap() ?? {}, @@ -448,9 +444,7 @@ class _InAppWebViewState extends State { onPlatformViewCreated: _onPlatformViewCreated, gestureRecognizers: widget.gestureRecognizers, creationParams: { - 'initialUrlRequest': (widget.initialUrlRequest ?? - URLRequest(url: Uri.parse("about:blank"))) - .toMap(), + 'initialUrlRequest': widget.initialUrlRequest?.toMap(), 'initialFile': widget.initialFile, 'initialData': widget.initialData?.toMap(), 'initialOptions': widget.initialOptions?.toMap() ?? {}, From 0e7c2905e1016f4e2a91c2f919cd0b25fe390352 Mon Sep 17 00:00:00 2001 From: Michael Chow Date: Mon, 27 Dec 2021 18:17:58 -0500 Subject: [PATCH 15/40] fix build error https://github.com/pichillilorenzo/flutter_inappwebview/issues/728 --- android/build.gradle | 2 +- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a5e831c4..e1b67fe2 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.1.0' } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index fd50c3ca..e42931e3 100755 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip \ No newline at end of file From 8f43faf832ea63f2555ed9a4c5004227bd4d479b Mon Sep 17 00:00:00 2001 From: ashank96 Date: Thu, 17 Feb 2022 15:00:46 +0530 Subject: [PATCH 16/40] expose contentdisposition and contentlength from android --- .../in_app_webview/InAppWebView.java | 4 ++++ example/integration_test/webview_flutter_test.dart | 2 +- lib/src/in_app_browser/in_app_browser.dart | 2 +- lib/src/in_app_webview/headless_in_app_webview.dart | 8 +++++++- lib/src/in_app_webview/in_app_webview.dart | 2 +- lib/src/in_app_webview/in_app_webview_controller.dart | 9 +++++++-- lib/src/in_app_webview/webview.dart | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java index dcde9159..3af8104e 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java @@ -1184,6 +1184,10 @@ final public class InAppWebView extends InputAwareWebView { public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { Map obj = new HashMap<>(); obj.put("url", url); + obj.put("userAgent", userAgent); + obj.put("contentDisposition", contentDisposition); + obj.put("mimetype", mimetype); + obj.put("contentLength", contentLength); channel.invokeMethod("onDownloadStart", obj); } } diff --git a/example/integration_test/webview_flutter_test.dart b/example/integration_test/webview_flutter_test.dart index ac02f42f..3a79f1ca 100644 --- a/example/integration_test/webview_flutter_test.dart +++ b/example/integration_test/webview_flutter_test.dart @@ -2739,7 +2739,7 @@ void main() { onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, - onDownloadStart: (controller, url) { + onDownloadStart:(controller, url, userAgent, contentDisposition, mimeType, contentLength) { onDownloadStartCompleter.complete(url.toString()); }, ), diff --git a/lib/src/in_app_browser/in_app_browser.dart b/lib/src/in_app_browser/in_app_browser.dart index ff4e2877..3ac507cf 100755 --- a/lib/src/in_app_browser/in_app_browser.dart +++ b/lib/src/in_app_browser/in_app_browser.dart @@ -377,7 +377,7 @@ class InAppBrowser { ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener) /// ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview - void onDownloadStart(Uri url) {} + void onDownloadStart(Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength) {} ///Event fired when the [InAppBrowser] webview finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a [CustomSchemeResponse] to load a specific resource encoded to `base64`. /// diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index f19b5152..e6939550 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -299,7 +299,13 @@ class HeadlessInAppWebView implements WebView { void Function(InAppWebViewController controller)? onWindowBlur; @override - void Function(InAppWebViewController controller, Uri url)? onDownloadStart; + void Function( + InAppWebViewController controller, + Uri url, + String userAgent, + String contentDisposition, + String mimeType, + int contentLength)? onDownloadStart; @override void Function(InAppWebViewController controller, int activeMatchOrdinal, diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index 7ef7ee2f..4926f9d0 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -208,7 +208,7 @@ class InAppWebView extends StatefulWidget implements WebView { androidOnReceivedTouchIconUrl; @override - final void Function(InAppWebViewController controller, Uri url)? + final void Function(InAppWebViewController controller, Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength)? onDownloadStart; @override 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 d34072bb..fc8090c3 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -205,11 +205,16 @@ class InAppWebViewController { if ((_webview != null && _webview!.onDownloadStart != null) || _inAppBrowser != null) { String url = call.arguments["url"]; + String userAgent = call.arguments["userAgent"]; + String contentDisposition = call.arguments["contentDisposition"]; + String mimeType = call.arguments["mimetype"]; + int contentLength = call.arguments["contentLength"] as int; Uri uri = Uri.parse(url); + if (_webview != null && _webview!.onDownloadStart != null) - _webview!.onDownloadStart!(this, uri); + _webview!.onDownloadStart!(this, uri, userAgent, contentDisposition, mimeType, contentLength); else - _inAppBrowser!.onDownloadStart(uri); + _inAppBrowser!.onDownloadStart(uri, userAgent, contentDisposition, mimeType, contentLength); } break; case "onLoadResourceCustomScheme": diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart index c483acf1..710da3c3 100644 --- a/lib/src/in_app_webview/webview.dart +++ b/lib/src/in_app_webview/webview.dart @@ -120,7 +120,7 @@ abstract class WebView { ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener) /// ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview - final void Function(InAppWebViewController controller, Uri url)? + final void Function(InAppWebViewController controller, Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength)? onDownloadStart; ///Event fired when the [WebView] finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a [CustomSchemeResponse] to load a specific resource encoded to `base64`. From 93187105f4398e66e390d6b17607c66bec1ef14f Mon Sep 17 00:00:00 2001 From: "gitlab.scripts" Date: Thu, 24 Feb 2022 13:38:13 +0100 Subject: [PATCH 17/40] fix persistance --- ios/Classes/InAppWebView/InAppWebView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f49fcef7..28e5e6b2 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -528,7 +528,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi // See also https://forums.developer.apple.com/thread/97194 // check if websiteDataStore has not been initialized before if(!options.incognito && options.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() + configuration.websiteDataStore = WKWebsiteDataStore.default() } for cookie in HTTPCookieStorage.shared.cookies ?? [] { configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) From d8d84053bc1727269a4f8be9b4b38485dc111c0d Mon Sep 17 00:00:00 2001 From: sunalwaysknows <86180691+sunalwaysknows@users.noreply.github.com> Date: Sat, 26 Feb 2022 11:06:25 +0800 Subject: [PATCH 18/40] Update: Append optional applicationNameForUserAgent to configrational applicationNameForUserAgent --- ios/Classes/InAppWebView/InAppWebView.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f49fcef7..8ad01295 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -499,6 +499,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } else if options.cacheEnabled { configuration.websiteDataStore = WKWebsiteDataStore.default() } + if !options.applicationNameForUserAgent.isEmpty { + if let applicationNameForUserAgent = configuration.applicationNameForUserAgent { + configuration.applicationNameForUserAgent = applicationNameForUserAgent + " " + options.applicationNameForUserAgent + } + } } if #available(iOS 10.0, *) { From d2730d75bcaa8e8a86d6148b2eb36a610bcd6683 Mon Sep 17 00:00:00 2001 From: Manuito83 Date: Sun, 6 Mar 2022 14:59:14 +0100 Subject: [PATCH 19/40] Fixes zoomBy with floats --- ios/Classes/InAppWebViewMethodHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/InAppWebViewMethodHandler.swift b/ios/Classes/InAppWebViewMethodHandler.swift index 58092f63..b8ec2723 100644 --- a/ios/Classes/InAppWebViewMethodHandler.swift +++ b/ios/Classes/InAppWebViewMethodHandler.swift @@ -289,7 +289,7 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate { result(webView?.getContentHeight()) break case "zoomBy": - let zoomFactor = arguments!["zoomFactor"] as! Float + let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue let animated = arguments!["iosAnimated"] as! Bool webView?.zoomBy(zoomFactor: zoomFactor, animated: animated) result(true) From f074b7a011ceae60b9d602c4e58b0e20bc75d605 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 15 Apr 2022 19:20:35 +0200 Subject: [PATCH 20/40] created android InAppWebViewInterface to implement other android webview engines, getOriginalUrl method is cross-platform now, Fixed requestImageRef method always null on iOS --- .idea/libraries/Dart_Packages.xml | 420 ------------------ .idea/libraries/Dart_SDK.xml | 40 +- .idea/libraries/Flutter_Plugins.xml | 4 +- .idea/misc.xml | 3 + CHANGELOG.md | 5 + .../FlutterWebViewFactory.java | 18 +- .../InAppWebViewFlutterPlugin.java | 1 - .../InAppWebViewMethodHandler.java | 122 +++-- .../InAppWebViewStatic.java | 6 +- .../flutter_inappwebview/Util.java | 32 +- .../in_app_webview/FlutterWebView.java | 4 +- .../in_app_webview/InAppWebView.java | 163 +++++-- .../in_app_webview/InAppWebViewOptions.java | 8 +- .../plugin_scripts_js/JavaScriptBridgeJS.java | 5 +- .../types/HitTestResult.java | 79 ++++ .../types/InAppWebViewInterface.java | 101 +++++ .../types/PlatformWebView.java | 9 + .../types/UserContentController.java | 8 +- .../types/WebMessage.java | 23 + .../types/WebMessageChannel.java | 171 ++++--- .../types/WebMessageListener.java | 185 +++++++- .../types/WebMessagePort.java | 130 ++++++ .../types/WebViewImplementation.java | 32 ++ example/.flutter-plugins-dependencies | 2 +- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Flutter/Flutter.podspec | 2 +- .../ios/Flutter/flutter_export_environment.sh | 8 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 +- flutter_inappwebview.iml | 1 - ios/Classes/InAppWebView/InAppWebView.swift | 14 +- ios/Classes/InAppWebViewMethodHandler.swift | 5 +- .../LastTouchedAnchorOrImageJS.swift | 4 +- .../WebMessageListenerJS.swift | 6 +- ios/Classes/Types/WebMessageListener.swift | 3 +- lib/{ => assets}/t_rex_runner/t-rex.css | 0 lib/{ => assets}/t_rex_runner/t-rex.html | 0 lib/src/in_app_browser/in_app_browser.dart | 35 +- .../android/in_app_webview_controller.dart | 10 +- .../headless_in_app_webview.dart | 5 + lib/src/in_app_webview/in_app_webview.dart | 9 +- .../in_app_webview_controller.dart | 355 ++++++++++----- lib/src/in_app_webview/webview.dart | 35 +- lib/src/types.dart | 48 ++ pubspec.yaml | 6 +- 44 files changed, 1320 insertions(+), 803 deletions(-) delete mode 100644 .idea/libraries/Dart_Packages.xml rename android/src/main/java/com/pichillilorenzo/flutter_inappwebview/{in_app_webview => }/FlutterWebViewFactory.java (54%) create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/HitTestResult.java create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppWebViewInterface.java create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/PlatformWebView.java create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessage.java create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebMessagePort.java create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/WebViewImplementation.java rename lib/{ => assets}/t_rex_runner/t-rex.css (100%) rename lib/{ => assets}/t_rex_runner/t-rex.html (100%) diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml deleted file mode 100644 index 3b0b4626..00000000 --- a/.idea/libraries/Dart_Packages.xml +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml index 62be7eab..1889af48 100755 --- a/.idea/libraries/Dart_SDK.xml +++ b/.idea/libraries/Dart_SDK.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 31799730..65bb3679 100755 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,6 +1,8 @@ - + + + diff --git a/.idea/misc.xml b/.idea/misc.xml index eac9d8a9..5d05d05d 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,8 @@ + + + \ No newline at end of file diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f49fcef7..07b6d293 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -19,6 +19,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi var pullToRefreshControl: PullToRefreshControl? var webMessageChannels: [String:WebMessageChannel] = [:] var webMessageListeners: [WebMessageListener] = [] + var currentOriginalUrl: URL? static var sslCertificatesMap: [String: SslCertificate] = [:] // [URL host name : SslCertificate] static var credentialsProposed: [URLCredential] = [] @@ -26,6 +27,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi var lastScrollX: CGFloat = 0 var lastScrollY: CGFloat = 0 + // Used to manage pauseTimers() and resumeTimers() var isPausedTimers = false var isPausedTimersCompletionHandler: (() -> Void)? @@ -1557,6 +1559,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { + currentOriginalUrl = url + lastTouchPoint = nil + disposeWebMessageChannels() initializeWindowIdJS() @@ -2723,6 +2728,10 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { scrollView.setZoomScale(currentZoomScale * CGFloat(zoomFactor), animated: animated) } + public func getOriginalUrl() -> URL? { + return currentOriginalUrl + } + public func getZoomScale() -> Float { return Float(scrollView.zoomScale) } @@ -2883,10 +2892,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } public func dispose() { - if isPausedTimers, let completionHandler = isPausedTimersCompletionHandler { - isPausedTimersCompletionHandler = nil - completionHandler() - } + resumeTimers() stopLoading() disposeWebMessageChannels() for webMessageListener in webMessageListeners { diff --git a/ios/Classes/InAppWebViewMethodHandler.swift b/ios/Classes/InAppWebViewMethodHandler.swift index 58092f63..7216bc09 100644 --- a/ios/Classes/InAppWebViewMethodHandler.swift +++ b/ios/Classes/InAppWebViewMethodHandler.swift @@ -290,7 +290,7 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate { break case "zoomBy": let zoomFactor = arguments!["zoomFactor"] as! Float - let animated = arguments!["iosAnimated"] as! Bool + let animated = arguments!["animated"] as! Bool webView?.zoomBy(zoomFactor: zoomFactor, animated: animated) result(true) break @@ -298,6 +298,9 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate { webView?.reloadFromOrigin() result(true) break + case "getOriginalUrl": + result(webView?.getOriginalUrl()?.absoluteString) + break case "getZoomScale": result(webView?.getZoomScale()) break diff --git a/ios/Classes/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift b/ios/Classes/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift index 4f3442f9..ef2e7d67 100644 --- a/ios/Classes/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift +++ b/ios/Classes/PluginScriptsJS/LastTouchedAnchorOrImageJS.swift @@ -27,7 +27,7 @@ window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched = null; if (target.tagName === 'IMG') { var img = target; window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched = { - src: img.src + url: img.src }; var parent = img.parentNode; while (parent) { @@ -47,7 +47,7 @@ window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched = null; var images = link.getElementsByTagName('img'); var img = (images.length > 0) ? images[0] : null; var imgSrc = (img != null) ? img.src : null; - window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched = (img != null) ? {src: img.src} : window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched; + window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched = (img != null) ? {url: imgSrc} : window.\(JAVASCRIPT_BRIDGE_NAME)._lastImageTouched; window.\(JAVASCRIPT_BRIDGE_NAME)._lastAnchorOrImageTouched = { title: link.textContent, url: link.href, diff --git a/ios/Classes/PluginScriptsJS/WebMessageListenerJS.swift b/ios/Classes/PluginScriptsJS/WebMessageListenerJS.swift index 91ff57ea..9d9fc60d 100644 --- a/ios/Classes/PluginScriptsJS/WebMessageListenerJS.swift +++ b/ios/Classes/PluginScriptsJS/WebMessageListenerJS.swift @@ -36,7 +36,7 @@ window.\(JAVASCRIPT_BRIDGE_NAME)._normalizeIPv6 = function(ip_string) { // replace ipv4 address if any var ipv4 = ip_string.match(/(.*:)([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$)/); if (ipv4) { - var ip_string = ipv4[1]; + ip_string = ipv4[1]; ipv4 = ipv4[2].match(/[0-9]+/g); for (var i = 0;i < 4;i ++) { var byte = parseInt(ipv4[i],10); @@ -85,12 +85,12 @@ window.\(JAVASCRIPT_BRIDGE_NAME)._isOriginAllowed = function(allowedOriginRules, var IPv6 = null; if (rule.host != null && rule.host[0] === "[") { try { - IPv6 = normalizeIPv6(rule.host.substring(1, rule.host.length - 1)); + IPv6 = window.\(JAVASCRIPT_BRIDGE_NAME)._normalizeIPv6(rule.host.substring(1, rule.host.length - 1)); } catch {} } var hostIPv6 = null; try { - hostIPv6 = normalizeIPv6(host); + hostIPv6 = window.\(JAVASCRIPT_BRIDGE_NAME)._normalizeIPv6(host); } catch {} var schemeAllowed = scheme == rule.scheme; diff --git a/ios/Classes/Types/WebMessageListener.swift b/ios/Classes/Types/WebMessageListener.swift index 6e283741..0d85c331 100644 --- a/ios/Classes/Types/WebMessageListener.swift +++ b/ios/Classes/Types/WebMessageListener.swift @@ -83,8 +83,9 @@ public class WebMessageListener : FlutterMethodCallDelegate { return "'*'" } let rule = URL(string: allowedOriginRule)! + let host = rule.host != nil ? "'" + rule.host!.replacingOccurrences(of: "\'", with: "\\'") + "'" : "null" return """ - {scheme: '\(rule.scheme!)', host: '\(rule.host?.replacingOccurrences(of: "\'", with: "\\'") ?? "null")', port: \(rule.port != nil ? String(rule.port!) : "null")} + {scheme: '\(rule.scheme!)', host: \(host), port: \(rule.port != nil ? String(rule.port!) : "null")} """ }.joined(separator: ", ") let source = """ diff --git a/lib/t_rex_runner/t-rex.css b/lib/assets/t_rex_runner/t-rex.css similarity index 100% rename from lib/t_rex_runner/t-rex.css rename to lib/assets/t_rex_runner/t-rex.css diff --git a/lib/t_rex_runner/t-rex.html b/lib/assets/t_rex_runner/t-rex.html similarity index 100% rename from lib/t_rex_runner/t-rex.html rename to lib/assets/t_rex_runner/t-rex.html diff --git a/lib/src/in_app_browser/in_app_browser.dart b/lib/src/in_app_browser/in_app_browser.dart index ff4e2877..727582ae 100755 --- a/lib/src/in_app_browser/in_app_browser.dart +++ b/lib/src/in_app_browser/in_app_browser.dart @@ -64,8 +64,12 @@ class InAppBrowser { ///The window id of a [CreateWindowAction.windowId]. final int? windowId; + ///Represents the WebView native implementation to be used. + ///The default value is [WebViewImplementation.NATIVE]. + final WebViewImplementation implementation; + /// - InAppBrowser({this.windowId, this.initialUserScripts}) { + InAppBrowser({this.windowId, this.initialUserScripts, this.implementation = WebViewImplementation.NATIVE}) { id = IdGenerator.generate(); this._channel = MethodChannel('com.pichillilorenzo/flutter_inappbrowser_$id'); @@ -109,6 +113,7 @@ class InAppBrowser { () => options?.toMap() ?? InAppBrowserClassOptions().toMap()); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('windowId', () => windowId); + args.putIfAbsent('implementation', () => implementation.toValue()); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent( @@ -167,6 +172,7 @@ class InAppBrowser { () => options?.toMap() ?? InAppBrowserClassOptions().toMap()); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('windowId', () => windowId); + args.putIfAbsent('implementation', () => implementation.toValue()); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent( @@ -207,6 +213,7 @@ class InAppBrowser { 'historyUrl', () => androidHistoryUrl?.toString() ?? "about:blank"); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('windowId', () => windowId); + args.putIfAbsent('implementation', () => implementation.toValue()); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent( @@ -290,16 +297,16 @@ class InAppBrowser { ///Event fired when the [InAppBrowser] starts to load an [url]. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview + ///**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))) + ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) void onLoadStart(Uri? url) {} ///Event fired when the [InAppBrowser] finishes loading an [url]. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview + ///**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))) + ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) void onLoadStop(Uri? url) {} ///Event fired when the [InAppBrowser] encounters an error loading an [url]. @@ -326,7 +333,9 @@ class InAppBrowser { ///Event fired when the current [progress] (range 0-100) of loading a page is changed. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onProgressChanged](https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int))) + ///- iOS void onProgressChanged(int progress) {} ///Event fired when the [InAppBrowser] webview receives a [ConsoleMessage]. @@ -501,7 +510,7 @@ class InAppBrowser { URLAuthenticationChallenge challenge) {} ///Event fired as find-on-page operations progress. - ///The listener may be notified multiple times while the operation is underway, and the numberOfMatches value should not be considered final unless [isDoneCounting] is true. + ///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true. /// ///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match. /// @@ -509,7 +518,9 @@ class InAppBrowser { /// ///[isDoneCounting] whether the find operation has actually completed. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setFindListener(android.webkit.WebView.FindListener) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean))) + ///- iOS void onFindResultReceived( int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting) {} @@ -562,7 +573,9 @@ class InAppBrowser { /// ///[url] represents the url on which is called. /// - ///**NOTE**: available on Android 21+. + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS void onPrint(Uri? url) {} ///Event fired when an HTML element of the webview has been clicked and held. diff --git a/lib/src/in_app_webview/android/in_app_webview_controller.dart b/lib/src/in_app_webview/android/in_app_webview_controller.dart index 0e3c8e22..3c0805bc 100644 --- a/lib/src/in_app_webview/android/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/android/in_app_webview_controller.dart @@ -59,11 +59,8 @@ class AndroidInAppWebViewController { await _channel.invokeMethod('resume', args); } - ///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, - ///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested. - /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getOriginalUrl() + ///Use [InAppWebViewController.getOriginalUrl] instead. + @Deprecated('Use `InAppWebViewController.getOriginalUrl` instead') Future getOriginalUrl() async { Map args = {}; String? url = await _channel.invokeMethod('getOriginalUrl', args); @@ -114,7 +111,8 @@ class AndroidInAppWebViewController { ///Clears the internal back/forward list. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#clearHistory() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.clearHistory](https://developer.android.com/reference/android/webkit/WebView#clearHistory())). Future clearHistory() async { Map args = {}; return await _channel.invokeMethod('clearHistory', args); diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index f19b5152..232d4e6d 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -53,6 +53,7 @@ class HeadlessInAppWebView implements WebView { this.contextMenu, this.initialUserScripts, this.pullToRefreshController, + this.implementation = WebViewImplementation.NATIVE, this.onWebViewCreated, this.onLoadStart, this.onLoadStop, @@ -147,6 +148,7 @@ class HeadlessInAppWebView implements WebView { 'initialOptions': this.initialOptions?.toMap() ?? {}, 'contextMenu': this.contextMenu?.toMap() ?? {}, 'windowId': this.windowId, + 'implementation': this.implementation, 'initialUserScripts': this.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], 'pullToRefreshOptions': @@ -227,6 +229,9 @@ class HeadlessInAppWebView implements WebView { @override final PullToRefreshController? pullToRefreshController; + @override + final WebViewImplementation implementation; + @override void Function(InAppWebViewController controller)? androidOnGeolocationPermissionsHidePrompt; diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index 7ef7ee2f..f60f956f 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -41,6 +41,7 @@ class InAppWebView extends StatefulWidget implements WebView { this.initialOptions, this.initialUserScripts, this.pullToRefreshController, + this.implementation = WebViewImplementation.NATIVE, this.contextMenu, this.onWebViewCreated, this.onLoadStart, @@ -135,6 +136,9 @@ class InAppWebView extends StatefulWidget implements WebView { @override final URLRequest? initialUrlRequest; + @override + final WebViewImplementation implementation; + @override final UnmodifiableListView? initialUserScripts; @@ -403,6 +407,7 @@ class _InAppWebViewState extends State { 'initialOptions': widget.initialOptions?.toMap() ?? {}, 'contextMenu': widget.contextMenu?.toMap() ?? {}, 'windowId': widget.windowId, + 'implementation': widget.implementation.toValue(), 'initialUserScripts': widget.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], @@ -423,7 +428,7 @@ class _InAppWebViewState extends State { viewType: 'com.pichillilorenzo/flutter_inappwebview', onPlatformViewCreated: _onPlatformViewCreated, gestureRecognizers: widget.gestureRecognizers, - layoutDirection: TextDirection.rtl, + layoutDirection: Directionality.maybeOf(context) ?? TextDirection.rtl, creationParams: { 'initialUrlRequest': (widget.initialUrlRequest ?? URLRequest(url: Uri.parse("about:blank"))) @@ -433,6 +438,7 @@ class _InAppWebViewState extends State { 'initialOptions': widget.initialOptions?.toMap() ?? {}, 'contextMenu': widget.contextMenu?.toMap() ?? {}, 'windowId': widget.windowId, + 'implementation': widget.implementation.toValue(), 'initialUserScripts': widget.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], 'pullToRefreshOptions': @@ -456,6 +462,7 @@ class _InAppWebViewState extends State { 'initialOptions': widget.initialOptions?.toMap() ?? {}, 'contextMenu': widget.contextMenu?.toMap() ?? {}, 'windowId': widget.windowId, + 'implementation': widget.implementation.toValue(), 'initialUserScripts': widget.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], 'pullToRefreshOptions': 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 d34072bb..e6bb9048 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -904,9 +904,9 @@ class InAppWebViewController { ///Gets the URL for the current page. ///This is not always the same as the URL passed to [WebView.onLoadStart] because although the load for that URL has begun, the current page may not have changed. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getUrl() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1415005-url + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getUrl](https://developer.android.com/reference/android/webkit/WebView#getUrl())) + ///- iOS ([Official API - WKWebView.url](https://developer.apple.com/documentation/webkit/wkwebview/1415005-url)) Future getUrl() async { Map args = {}; String? url = await _channel.invokeMethod('getUrl', args); @@ -915,9 +915,9 @@ class InAppWebViewController { ///Gets the title for the current page. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getTitle() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1415015-title + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getTitle](https://developer.android.com/reference/android/webkit/WebView#getTitle())) + ///- iOS ([Official API - WKWebView.title](https://developer.apple.com/documentation/webkit/wkwebview/1415015-title)) Future getTitle() async { Map args = {}; return await _channel.invokeMethod('getTitle', args); @@ -925,9 +925,9 @@ class InAppWebViewController { ///Gets the progress for the current page. The progress value is between 0 and 100. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getProgress() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1415007-estimatedprogress + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getProgress](https://developer.android.com/reference/android/webkit/WebView#getProgress())) + ///- iOS ([Official API - WKWebView.estimatedProgress](https://developer.apple.com/documentation/webkit/wkwebview/1415007-estimatedprogress)) Future getProgress() async { Map args = {}; return await _channel.invokeMethod('getProgress', args); @@ -1138,21 +1138,20 @@ class InAppWebViewController { ///Loads the given [urlRequest]. /// - ///[iosAllowingReadAccessTo], used in combination with [urlRequest] (using the `file://` scheme), - ///is an iOS-specific argument that represents the URL from which to read the web content. + ///- [allowingReadAccessTo], used in combination with [urlRequest] (using the `file://` scheme), + ///it represents the URL from which to read the web content. ///This URL must be a file-based URL (using the `file://` scheme). ///Specify the same value as the URL parameter to prevent WebView from reading any other content. ///Specify a directory to give WebView permission to read additional files in the specified directory. + ///**NOTE**: available only on iOS. /// ///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String) - /// - ///**Official iOS API**: - ///- https://developer.apple.com/documentation/webkit/wkwebview/1414954-load - ///- if [iosAllowingReadAccessTo] is used, https://developer.apple.com/documentation/webkit/wkwebview/1414973-loadfileurl + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.loadUrl](https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String))). If method is "POST", [Official API - WebView.postUrl](https://developer.android.com/reference/android/webkit/WebView#postUrl(java.lang.String,%20byte[])) + ///- iOS ([Official API - WKWebView.load](https://developer.apple.com/documentation/webkit/wkwebview/1414954-load). If [allowingReadAccessTo] is used, [Official API - WKWebView.loadFileURL](https://developer.apple.com/documentation/webkit/wkwebview/1414973-loadfileurl)) Future loadUrl( - {required URLRequest urlRequest, Uri? iosAllowingReadAccessTo}) async { + {required URLRequest urlRequest, @Deprecated('Use `allowingReadAccessTo` instead') Uri? iosAllowingReadAccessTo, Uri? allowingReadAccessTo}) async { assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); assert(iosAllowingReadAccessTo == null || iosAllowingReadAccessTo.isScheme("file")); @@ -1160,19 +1159,21 @@ class InAppWebViewController { Map args = {}; args.putIfAbsent('urlRequest', () => urlRequest.toMap()); args.putIfAbsent( - 'allowingReadAccessTo', () => iosAllowingReadAccessTo?.toString()); + 'allowingReadAccessTo', () => allowingReadAccessTo?.toString() ?? iosAllowingReadAccessTo?.toString()); await _channel.invokeMethod('loadUrl', args); } ///Loads the given [url] with [postData] (x-www-form-urlencoded) using `POST` method into this WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#postUrl(java.lang.String,%20byte[]) - /// ///Example ///```dart ///var postData = Uint8List.fromList(utf8.encode("firstname=Foo&surname=Bar")); ///controller.postUrl(url: Uri.parse("https://www.example.com/"), postData: postData); ///``` + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.postUrl](https://developer.android.com/reference/android/webkit/WebView#postUrl(java.lang.String,%20byte[]))) + ///- iOS Future postUrl({required Uri url, required Uint8List postData}) async { assert(url.toString().isNotEmpty); Map args = {}; @@ -1183,27 +1184,30 @@ class InAppWebViewController { ///Loads the given [data] into this WebView, using [baseUrl] as the base URL for the content. /// - ///- [mimeType] parameter specifies the format of the data. The default value is `"text/html"`. - ///- [encoding] parameter specifies the encoding of the data. The default value is `"utf8"`. - ///- [androidHistoryUrl] parameter is the URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL. This parameter is used only on Android. - ///- [iosAllowingReadAccessTo], used in combination with [baseUrl] (using the `file://` scheme), - ///is an iOS-specific argument that represents the URL from which to read the web content. + ///- [mimeType] argument specifies the format of the data. The default value is `"text/html"`. + ///- [encoding] argument specifies the encoding of the data. The default value is `"utf8"`. + ///- [historyUrl] is an Android-specific argument that represents the URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL. + ///- [allowingReadAccessTo], used in combination with [baseUrl] (using the `file://` scheme), + ///it represents the URL from which to read the web content. ///This [baseUrl] must be a file-based URL (using the `file://` scheme). ///Specify the same value as the [baseUrl] parameter to prevent WebView from reading any other content. ///Specify a directory to give WebView permission to read additional files in the specified directory. + ///**NOTE**: available only on iOS. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#loadDataWithBaseURL(java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String) - /// - ///**Official iOS API**: - ///- https://developer.apple.com/documentation/webkit/wkwebview/1415004-loadhtmlstring - ///- https://developer.apple.com/documentation/webkit/wkwebview/1415011-load + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.loadDataWithBaseURL](https://developer.android.com/reference/android/webkit/WebView#loadDataWithBaseURL(java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String))) + ///- iOS ([Official API - WKWebView.loadHTMLString](https://developer.apple.com/documentation/webkit/wkwebview/1415004-loadhtmlstring) or [Official API - WKWebView.load](https://developer.apple.com/documentation/webkit/wkwebview/1415011-load)) Future loadData( {required String data, String mimeType = "text/html", String encoding = "utf8", Uri? baseUrl, + @Deprecated('Use `historyUrl` instead') Uri? androidHistoryUrl, - Uri? iosAllowingReadAccessTo}) async { + Uri? historyUrl, + @Deprecated('Use `allowingReadAccessTo` instead') + Uri? iosAllowingReadAccessTo, + Uri? allowingReadAccessTo}) async { assert(iosAllowingReadAccessTo == null || iosAllowingReadAccessTo.isScheme("file")); @@ -1213,9 +1217,9 @@ class InAppWebViewController { args.putIfAbsent('encoding', () => encoding); args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); args.putIfAbsent( - 'historyUrl', () => androidHistoryUrl?.toString() ?? "about:blank"); + 'historyUrl', () => historyUrl?.toString() ?? androidHistoryUrl?.toString() ?? "about:blank"); args.putIfAbsent( - 'allowingReadAccessTo', () => iosAllowingReadAccessTo?.toString()); + 'allowingReadAccessTo', () => allowingReadAccessTo?.toString() ?? iosAllowingReadAccessTo?.toString()); await _channel.invokeMethod('loadData', args); } @@ -1248,6 +1252,10 @@ class InAppWebViewController { ///controller.loadFile(assetFilePath: "assets/index.html"); ///... ///``` + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.loadUrl](https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String))) + ///- iOS ([Official API - WKWebView.load](https://developer.apple.com/documentation/webkit/wkwebview/1414954-load)) Future loadFile({required String assetFilePath}) async { assert(assetFilePath.isNotEmpty); Map args = {}; @@ -1257,9 +1265,9 @@ class InAppWebViewController { ///Reloads the WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#reload() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414969-reload + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.reload](https://developer.android.com/reference/android/webkit/WebView#reload())) + ///- iOS ([Official API - WKWebView.reload](https://developer.apple.com/documentation/webkit/wkwebview/1414969-reload)) Future reload() async { Map args = {}; await _channel.invokeMethod('reload', args); @@ -1267,9 +1275,9 @@ class InAppWebViewController { ///Goes back in the history of the WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#goBack() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414952-goback + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.goBack](https://developer.android.com/reference/android/webkit/WebView#goBack())) + ///- iOS ([Official API - WKWebView.goBack](https://developer.apple.com/documentation/webkit/wkwebview/1414952-goback)) Future goBack() async { Map args = {}; await _channel.invokeMethod('goBack', args); @@ -1277,9 +1285,9 @@ class InAppWebViewController { ///Returns a boolean value indicating whether the WebView can move backward. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#canGoBack() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414966-cangoback + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.canGoBack](https://developer.android.com/reference/android/webkit/WebView#canGoBack())) + ///- iOS ([Official API - WKWebView.canGoBack](https://developer.apple.com/documentation/webkit/wkwebview/1414966-cangoback)) Future canGoBack() async { Map args = {}; return await _channel.invokeMethod('canGoBack', args); @@ -1287,9 +1295,9 @@ class InAppWebViewController { ///Goes forward in the history of the WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#goForward() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414993-goforward + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.goForward](https://developer.android.com/reference/android/webkit/WebView#goForward())) + ///- iOS ([Official API - WKWebView.goForward](https://developer.apple.com/documentation/webkit/wkwebview/1414993-goforward)) Future goForward() async { Map args = {}; await _channel.invokeMethod('goForward', args); @@ -1297,9 +1305,9 @@ class InAppWebViewController { ///Returns a boolean value indicating whether the WebView can move forward. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#canGoForward() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414962-cangoforward + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.canGoForward](https://developer.android.com/reference/android/webkit/WebView#canGoForward())) + ///- iOS ([Official API - WKWebView.canGoForward](https://developer.apple.com/documentation/webkit/wkwebview/1414962-cangoforward)) Future canGoForward() async { Map args = {}; return await _channel.invokeMethod('canGoForward', args); @@ -1307,9 +1315,9 @@ class InAppWebViewController { ///Goes to the history item that is the number of steps away from the current item. Steps is negative if backward and positive if forward. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#goBackOrForward(int) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414991-go + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.goBackOrForward](https://developer.android.com/reference/android/webkit/WebView#goBackOrForward(int))) + ///- iOS ([Official API - WKWebView.go](https://developer.apple.com/documentation/webkit/wkwebview/1414991-go)) Future goBackOrForward({required int steps}) async { Map args = {}; args.putIfAbsent('steps', () => steps); @@ -1318,7 +1326,9 @@ class InAppWebViewController { ///Returns a boolean value indicating whether the WebView can go back or forward the given number of steps. Steps is negative if backward and positive if forward. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#canGoBackOrForward(int) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.canGoBackOrForward](https://developer.android.com/reference/android/webkit/WebView#canGoBackOrForward(int))) + ///- iOS Future canGoBackOrForward({required int steps}) async { Map args = {}; args.putIfAbsent('steps', () => steps); @@ -1326,13 +1336,22 @@ class InAppWebViewController { } ///Navigates to a [WebHistoryItem] from the back-forward [WebHistory.list] and sets it as the current item. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future goTo({required WebHistoryItem historyItem}) async { - if (historyItem.offset != null) { - await goBackOrForward(steps: historyItem.offset!); + var steps = historyItem.offset; + if (steps != null) { + await goBackOrForward(steps: steps); } } ///Check if the WebView instance is in a loading state. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future isLoading() async { Map args = {}; return await _channel.invokeMethod('isLoading', args); @@ -1340,9 +1359,9 @@ class InAppWebViewController { ///Stops the WebView from loading. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#stopLoading() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414981-stoploading + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.stopLoading](https://developer.android.com/reference/android/webkit/WebView#stopLoading())) + ///- iOS ([Official API - WKWebView.stopLoading](https://developer.apple.com/documentation/webkit/wkwebview/1414981-stoploading)) Future stopLoading() async { Map args = {}; await _channel.invokeMethod('stopLoading', args); @@ -1362,19 +1381,22 @@ class InAppWebViewController { ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#evaluateJavascript(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.String%3E) - /// - ///**Official iOS API**: - ///- https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript - ///- https://developer.apple.com/documentation/webkit/wkwebview/3656442-evaluatejavascript + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.evaluateJavascript](https://developer.android.com/reference/android/webkit/WebView#evaluateJavascript(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.String%3E))) + ///- iOS ([Official API - WKWebView.evaluateJavascript](https://developer.apple.com/documentation/webkit/wkwebview/3656442-evaluatejavascript)) Future evaluateJavascript( {required String source, ContentWorld? contentWorld}) async { Map args = {}; args.putIfAbsent('source', () => source); args.putIfAbsent('contentWorld', () => contentWorld?.toMap()); var data = await _channel.invokeMethod('evaluateJavascript', args); - if (data != null && defaultTargetPlatform == TargetPlatform.android) - data = json.decode(data); + if (data != null && defaultTargetPlatform == TargetPlatform.android) { + try { + // try to json decode the data coming from JavaScript + // otherwise return it as it is. + data = json.decode(data); + } catch (e) {} + } return data; } @@ -1386,6 +1408,10 @@ class InAppWebViewController { ///because, in these events, the [WebView] is not ready to handle it yet. ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future injectJavascriptFileFromUrl( {required Uri urlFile, ScriptHtmlTagAttributes? scriptHtmlTagAttributes}) async { @@ -1407,6 +1433,10 @@ class InAppWebViewController { ///because, in these events, the [WebView] is not ready to handle it yet. ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future injectJavascriptFileFromAsset( {required String assetFilePath}) async { String source = await rootBundle.loadString(assetFilePath); @@ -1419,6 +1449,10 @@ class InAppWebViewController { ///because, in these events, the [WebView] is not ready to handle it yet. ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future injectCSSCode({required String source}) async { Map args = {}; args.putIfAbsent('source', () => source); @@ -1433,6 +1467,10 @@ class InAppWebViewController { ///because, in these events, the [WebView] is not ready to handle it yet. ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future injectCSSFileFromUrl( {required Uri urlFile, CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes}) async { @@ -1450,6 +1488,10 @@ class InAppWebViewController { ///because, in these events, the [WebView] is not ready to handle it yet. ///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events ///where you know the page is ready "enough". + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future injectCSSFileFromAsset({required String assetFilePath}) async { String source = await rootBundle.loadString(assetFilePath); await injectCSSCode(source: source); @@ -1505,6 +1547,10 @@ class InAppWebViewController { ///**NOTE**: This method should be called, for example, in the [WebView.onWebViewCreated] or [WebView.onLoadStart] events or, at least, ///before you know that your JavaScript code will call the `window.flutter_inappwebview.callHandler` method, ///otherwise you won't be able to intercept the JavaScript message. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS void addJavaScriptHandler( {required String handlerName, required JavaScriptHandlerCallback callback}) { @@ -1516,6 +1562,10 @@ class InAppWebViewController { ///Removes a JavaScript message handler previously added with the [addJavaScriptHandler()] associated to [handlerName] key. ///Returns the value associated with [handlerName] before it was removed. ///Returns `null` if [handlerName] was not found. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS JavaScriptHandlerCallback? removeJavaScriptHandler( {required String handlerName}) { return this.javaScriptHandlersMap.remove(handlerName); @@ -1527,7 +1577,9 @@ class InAppWebViewController { /// ///**NOTE for iOS**: available on iOS 11.0+. /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS ([Official API - WKWebView.takeSnapshot](https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot)) Future takeScreenshot( {ScreenshotConfiguration? screenshotConfiguration}) async { Map args = {}; @@ -1537,6 +1589,10 @@ class InAppWebViewController { } ///Sets the WebView options with the new [options] and evaluates them. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future setOptions({required InAppWebViewGroupOptions options}) async { Map args = {}; @@ -1545,6 +1601,10 @@ class InAppWebViewController { } ///Gets the current WebView options. Returns `null` if it wasn't able to get them. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future getOptions() async { Map args = {}; @@ -1563,9 +1623,9 @@ class InAppWebViewController { ///Multiple calls to this method may return different objects. ///The object returned from this method will not be updated to reflect any new state. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#copyBackForwardList() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.copyBackForwardList](https://developer.android.com/reference/android/webkit/WebView#copyBackForwardList())) + ///- iOS ([Official API - WKWebView.backForwardList](https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist)) Future getCopyBackForwardList() async { Map args = {}; Map? result = @@ -1574,7 +1634,11 @@ class InAppWebViewController { return WebHistory.fromMap(result); } - ///Clears all the webview's cache. + ///Clears all the WebView's cache. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future clearCache() async { Map args = {}; await _channel.invokeMethod('clearCache', args); @@ -1584,24 +1648,28 @@ class InAppWebViewController { /// ///[find] represents the string to find. /// - ///**NOTE**: on Android, it finds all instances asynchronously. Successive calls to this will cancel any pending searches. + ///**NOTE**: on Android native WebView, it finds all instances asynchronously. Successive calls to this will cancel any pending searches. /// ///**NOTE**: on iOS, this is implemented using CSS and Javascript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.findAllAsync](https://developer.android.com/reference/android/webkit/WebView#findAllAsync(java.lang.String))) + ///- iOS Future findAllAsync({required String find}) async { Map args = {}; args.putIfAbsent('find', () => find); await _channel.invokeMethod('findAllAsync', args); } - ///Highlights and scrolls to the next match found by [findAllAsync()]. Notifies [WebView.onFindResultReceived] listener. + ///Highlights and scrolls to the next match found by [findAllAsync]. Notifies [WebView.onFindResultReceived] listener. /// ///[forward] represents the direction to search. /// ///**NOTE**: on iOS, this is implemented using CSS and Javascript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#findNext(boolean) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.findNext](https://developer.android.com/reference/android/webkit/WebView#findNext(boolean))) + ///- iOS Future findNext({required bool forward}) async { Map args = {}; args.putIfAbsent('forward', () => forward); @@ -1612,22 +1680,32 @@ class InAppWebViewController { /// ///**NOTE**: on iOS, this is implemented using CSS and Javascript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#clearMatches() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.clearMatches](https://developer.android.com/reference/android/webkit/WebView#clearMatches())) + ///- iOS Future clearMatches() async { Map args = {}; await _channel.invokeMethod('clearMatches', args); } - ///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerCss()]. + ///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerCss]. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future getTRexRunnerHtml() async { return await rootBundle - .loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.html"); + .loadString("packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html"); } - ///Gets the css of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerHtml()]. + ///Gets the css of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerHtml]. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future getTRexRunnerCss() async { return await rootBundle - .loadString("packages/flutter_inappwebview/t_rex_runner/t-rex.css"); + .loadString("packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css"); } ///Scrolls the WebView to the position. @@ -1638,9 +1716,9 @@ class InAppWebViewController { /// ///[animated] `true` to animate the scroll transition, `false` to make the scoll transition immediate. /// - ///**Official Android API**: https://developer.android.com/reference/android/view/View#scrollTo(int,%20int) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - View.scrollTo](https://developer.android.com/reference/android/view/View#scrollTo(int,%20int))) + ///- iOS ([Official API - UIScrollView.setContentOffset](https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset)) Future scrollTo( {required int x, required int y, bool animated = false}) async { Map args = {}; @@ -1658,9 +1736,9 @@ class InAppWebViewController { /// ///[animated] `true` to animate the scroll transition, `false` to make the scoll transition immediate. /// - ///**Official Android API**: https://developer.android.com/reference/android/view/View#scrollBy(int,%20int) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - View.scrollBy](https://developer.android.com/reference/android/view/View#scrollBy(int,%20int))) + ///- iOS ([Official API - UIScrollView.setContentOffset](https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset)) Future scrollBy( {required int x, required int y, bool animated = false}) async { Map args = {}; @@ -1670,12 +1748,14 @@ class InAppWebViewController { await _channel.invokeMethod('scrollBy', args); } - ///On Android, it pauses all layout, parsing, and JavaScript timers for all WebViews. + ///On Android native WebView, it pauses all layout, parsing, and JavaScript timers for all WebViews. ///This is a global requests, not restricted to just this WebView. This can be useful if the application has been paused. /// - ///On iOS, it is restricted to just this WebView. + ///On iOS, it is implemented using JavaScript and it is restricted to just this WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#pauseTimers() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.pauseTimers](https://developer.android.com/reference/android/webkit/WebView#pauseTimers())) + ///- iOS Future pauseTimers() async { Map args = {}; await _channel.invokeMethod('pauseTimers', args); @@ -1683,9 +1763,11 @@ class InAppWebViewController { ///On Android, it resumes all layout, parsing, and JavaScript timers for all WebViews. This will resume dispatching all timers. /// - ///On iOS, it resumes all layout, parsing, and JavaScript timers to just this WebView. + ///On iOS, it is implemented using JavaScript and it resumes all layout, parsing, and JavaScript timers to just this WebView. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#resumeTimers() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.resumeTimers](https://developer.android.com/reference/android/webkit/WebView#resumeTimers())) + ///- iOS Future resumeTimers() async { Map args = {}; await _channel.invokeMethod('resumeTimers', args); @@ -1695,9 +1777,9 @@ class InAppWebViewController { /// ///**NOTE**: available on Android 21+. /// - ///**Official Android API**: https://developer.android.com/reference/android/print/PrintManager - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiprintinteractioncontroller + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - PrintManager](https://developer.android.com/reference/android/print/PrintManager)) + ///- iOS ([Official API - UIPrintInteractionController](https://developer.apple.com/documentation/uikit/uiprintinteractioncontroller)) Future printCurrentPage() async { Map args = {}; await _channel.invokeMethod('printCurrentPage', args); @@ -1705,9 +1787,9 @@ class InAppWebViewController { ///Gets the height of the HTML content. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getContentHeight() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollview/1619399-contentsize + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getContentHeight](https://developer.android.com/reference/android/webkit/WebView#getContentHeight())) + ///- iOS ([Official API - UIScrollView.contentSize](https://developer.apple.com/documentation/uikit/uiscrollview/1619399-contentsize)) Future getContentHeight() async { Map args = {}; return await _channel.invokeMethod('getContentHeight', args); @@ -1717,16 +1799,16 @@ class InAppWebViewController { /// ///[zoomFactor] represents the zoom factor to apply. On Android, the zoom factor will be clamped to the Webview's zoom limits and, also, this value must be in the range 0.01 (excluded) to 100.0 (included). /// - ///[iosAnimated] `true` to animate the transition to the new scale, `false` to make the transition immediate. + ///[animated] `true` to animate the transition to the new scale, `false` to make the transition immediate. ///**NOTE**: available only on iOS. /// ///**NOTE**: available on Android 21+. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#zoomBy(float) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollview/1619412-setzoomscale + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.zoomBy](https://developer.android.com/reference/android/webkit/WebView#zoomBy(float))) + ///- iOS ([Official API - UIScrollView.setZoomScale](https://developer.apple.com/documentation/uikit/uiscrollview/1619412-setzoomscale)) Future zoomBy( - {required double zoomFactor, bool iosAnimated = false}) async { + {required double zoomFactor, @Deprecated('Use `animated` instead') bool? iosAnimated, bool animated = false}) async { assert(defaultTargetPlatform != TargetPlatform.android || (defaultTargetPlatform == TargetPlatform.android && zoomFactor > 0.01 && @@ -1734,13 +1816,28 @@ class InAppWebViewController { Map args = {}; args.putIfAbsent('zoomFactor', () => zoomFactor); - args.putIfAbsent('iosAnimated', () => iosAnimated); + args.putIfAbsent('animated', () => iosAnimated ?? animated); return await _channel.invokeMethod('zoomBy', args); } + ///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, + ///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**: + ///- Android native WebView ([Official API - WebView.getOriginalUrl](https://developer.android.com/reference/android/webkit/WebView#getOriginalUrl())) + ///- iOS + Future getOriginalUrl() async { + Map args = {}; + String? url = await _channel.invokeMethod('getOriginalUrl', args); + return url != null ? Uri.parse(url) : null; + } + ///Gets the current zoom scale of the WebView. /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollview/1619419-zoomscale + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS ([Official API - UIScrollView.zoomScale](https://developer.apple.com/documentation/uikit/uiscrollview/1619419-zoomscale)) Future getZoomScale() async { Map args = {}; return await _channel.invokeMethod('getZoomScale', args); @@ -1754,9 +1851,13 @@ class InAppWebViewController { ///Gets the selected text. /// - ///**NOTE**: This method is implemented with using JavaScript. + ///**NOTE**: this method is implemented with using JavaScript. /// - ///**NOTE for Android**: available only on Android 19+. + ///**NOTE for Android native WebView**: available only on Android 19+. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future getSelectedText() async { Map args = {}; return await _channel.invokeMethod('getSelectedText', args); @@ -1764,9 +1865,11 @@ class InAppWebViewController { ///Gets the hit result for hitting an HTML elements. /// - ///**NOTE**: On iOS it is implemented using JavaScript. + ///**NOTE**: On iOS, it is implemented using JavaScript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getHitTestResult() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getHitTestResult](https://developer.android.com/reference/android/webkit/WebView#getHitTestResult())) + ///- iOS Future getHitTestResult() async { Map args = {}; Map? hitTestResultMap = @@ -1785,11 +1888,11 @@ class InAppWebViewController { return InAppWebViewHitTestResult(type: type, extra: extra); } - ///Clears the current focus. It will clear also, for example, the current text selection. + ///Clears the current focus. On iOS and Android native WebView, it will clear also, for example, the current text selection. /// - ///**Official Android API**: https://developer.android.com/reference/android/view/ViewGroup#clearFocus() - /// - ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - ViewGroup.clearFocus](https://developer.android.com/reference/android/view/ViewGroup#clearFocus())) + ///- iOS ([Official API - UIResponder.resignFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder)) Future clearFocus() async { Map args = {}; return await _channel.invokeMethod('clearFocus', args); @@ -1805,9 +1908,11 @@ class InAppWebViewController { ///Requests the anchor or image element URL at the last tapped point. /// - ///**NOTE**: On iOS it is implemented using JavaScript. + ///**NOTE**: On iOS, it is implemented using JavaScript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#requestFocusNodeHref(android.os.Message) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.requestFocusNodeHref](https://developer.android.com/reference/android/webkit/WebView#requestFocusNodeHref(android.os.Message))). + ///- iOS. Future requestFocusNodeHref() async { Map args = {}; Map? result = @@ -1823,9 +1928,11 @@ class InAppWebViewController { ///Requests the URL of the image last touched by the user. /// - ///**NOTE**: On iOS it is implemented using JavaScript. + ///**NOTE**: On iOS, it is implemented using JavaScript. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#requestImageRef(android.os.Message) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.requestImageRef](https://developer.android.com/reference/android/webkit/WebView#requestImageRef(android.os.Message))). + ///- iOS. Future requestImageRef() async { Map args = {}; Map? result = @@ -1947,7 +2054,9 @@ class InAppWebViewController { ///Gets the SSL certificate for the main top-level page or null if there is no certificate (the site is not secure). /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#getCertificate() + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getCertificate](https://developer.android.com/reference/android/webkit/WebView#getCertificate())). + ///- iOS. Future getCertificate() async { Map args = {}; Map? sslCertificateMap = @@ -2155,11 +2264,13 @@ class InAppWebViewController { /// ///This method should be called when the page is loaded, for example, when the [WebView.onLoadStop] is fired, otherwise the [WebMessageChannel] won't work. /// - ///**NOTE for Android**: This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.CREATE_WEB_MESSAGE_CHANNEL]. + ///**NOTE for Android native WebView**: This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.CREATE_WEB_MESSAGE_CHANNEL]. /// - ///**NOTE for iOS**: This is implemented using Javascript. + ///**NOTE**: On iOS, it is implemented using JavaScript. /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewCompat#createWebMessageChannel(android.webkit.WebView) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebViewCompat.createWebMessageChannel](https://developer.android.com/reference/androidx/webkit/WebViewCompat#createWebMessageChannel(android.webkit.WebView))). + ///- iOS. Future createWebMessageChannel() async { Map args = {}; Map? result = @@ -2173,11 +2284,13 @@ class InAppWebViewController { /// ///A target origin can be set as a wildcard ("*"). However this is not recommended. /// - ///**NOTE for Android**: This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.POST_WEB_MESSAGE]. + ///**NOTE for Android native WebView**: This method should only be called if [AndroidWebViewFeature.isFeatureSupported] returns `true` for [AndroidWebViewFeature.POST_WEB_MESSAGE]. /// - ///**NOTE for iOS**: This is implemented using Javascript. + ///**NOTE**: On iOS, it is implemented using JavaScript. /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewCompat#postWebMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebViewCompat.postWebMessage](https://developer.android.com/reference/androidx/webkit/WebViewCompat#postWebMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri))). + ///- iOS. Future postWebMessage( {required WebMessage message, Uri? targetOrigin}) async { if (targetOrigin == null) { diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart index c483acf1..3a1fa650 100644 --- a/lib/src/in_app_webview/webview.dart +++ b/lib/src/in_app_webview/webview.dart @@ -22,16 +22,16 @@ abstract class WebView { ///Event fired when the [WebView] starts to load an [url]. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview + ///**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))) + ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) final void Function(InAppWebViewController controller, Uri? url)? onLoadStart; ///Event fired when the [WebView] finishes loading an [url]. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebViewClient#onPageFinished(android.webkit.WebView,%20java.lang.String) - /// - ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview + ///**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))) + ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) final void Function(InAppWebViewController controller, Uri? url)? onLoadStop; ///Event fired when the [WebView] encounters an error loading an [url]. @@ -60,7 +60,9 @@ abstract class WebView { ///Event fired when the current [progress] of loading a page is changed. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebChromeClient.onProgressChanged](https://developer.android.com/reference/android/webkit/WebChromeClient#onProgressChanged(android.webkit.WebView,%20int))) + ///- iOS final void Function(InAppWebViewController controller, int progress)? onProgressChanged; @@ -254,7 +256,7 @@ abstract class WebView { onReceivedClientCertRequest; ///Event fired as find-on-page operations progress. - ///The listener may be notified multiple times while the operation is underway, and the numberOfMatches value should not be considered final unless [isDoneCounting] is true. + ///The listener may be notified multiple times while the operation is underway, and the [numberOfMatches] value should not be considered final unless [isDoneCounting] is true. /// ///[activeMatchOrdinal] represents the zero-based ordinal of the currently selected match. /// @@ -262,7 +264,9 @@ abstract class WebView { /// ///[isDoneCounting] whether the find operation has actually completed. /// - ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setFindListener(android.webkit.WebView.FindListener) + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.FindListener.onFindResultReceived](https://developer.android.com/reference/android/webkit/WebView.FindListener#onFindResultReceived(int,%20int,%20boolean))) + ///- iOS final void Function(InAppWebViewController controller, int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting)? onFindResultReceived; @@ -340,7 +344,9 @@ abstract class WebView { /// ///[url] represents the url on which is called. /// - ///**NOTE**: available on Android 21+. + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS final void Function(InAppWebViewController controller, Uri? url)? onPrint; ///Event fired when an HTML element of the webview has been clicked and held. @@ -674,6 +680,10 @@ abstract class WebView { ///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [AndroidInAppWebViewOptions.useHybridComposition] must be `true`. final PullToRefreshController? pullToRefreshController; + ///Represents the WebView native implementation to be used. + ///The default value is [WebViewImplementation.NATIVE]. + final WebViewImplementation implementation; + WebView( {this.windowId, this.onWebViewCreated, @@ -722,7 +732,7 @@ abstract class WebView { this.androidOnRenderProcessUnresponsive, this.androidOnFormResubmission, @Deprecated('Use `onZoomScaleChanged` instead') - this.androidOnScaleChanged, + this.androidOnScaleChanged, this.androidOnReceivedIcon, this.androidOnReceivedTouchIconUrl, this.androidOnJsBeforeUnload, @@ -737,5 +747,6 @@ abstract class WebView { this.initialOptions, this.contextMenu, this.initialUserScripts, - this.pullToRefreshController}); + this.pullToRefreshController, + this.implementation = WebViewImplementation.NATIVE}); } diff --git a/lib/src/types.dart b/lib/src/types.dart index eb9d1d68..12ecc54d 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -6850,3 +6850,51 @@ class AndroidPullToRefreshSize { @override int get hashCode => _value.hashCode; } + +///Class that represents the [WebView] native implementation to be used. +class WebViewImplementation { + final int _value; + + const WebViewImplementation._internal(this._value); + + static final Set values = [ + WebViewImplementation.NATIVE, + WebViewImplementation.GECKO, + ].toSet(); + + static WebViewImplementation? fromValue(int? value) { + if (value != null) { + try { + return WebViewImplementation.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + int toValue() => _value; + + @override + String toString() { + switch (_value) { + case 1: + return "GECKO"; + case 0: + default: + return "NATIVE"; + } + } + + ///Default native implementation, such as `WKWebView` for iOS and `android.webkit.WebView` for Android. + static const NATIVE = const WebViewImplementation._internal(0); + + ///Android-only WebView implementation using the Mozilla's Gecko browser engine. + static const GECKO = const WebViewImplementation._internal(1); + + bool operator ==(value) => value == _value; + + @override + int get hashCode => _value.hashCode; +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index f810981b..45162ede 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 5.3.2 +version: 5.3.3 homepage: https://github.com/pichillilorenzo/flutter_inappwebview environment: @@ -30,8 +30,8 @@ flutter: pluginClass: InAppWebViewFlutterPlugin assets: - - packages/flutter_inappwebview/t_rex_runner/t-rex.html - - packages/flutter_inappwebview/t_rex_runner/t-rex.css + - packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html + - packages/flutter_inappwebview/assets/t_rex_runner/t-rex.css # To add assets to your plugin package, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg From 099223a24e8ba15248376b4eba6613b2f455f3f2 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 15 Apr 2022 20:16:10 +0200 Subject: [PATCH 21/40] Update Options.swift --- ios/Classes/Options.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/Options.swift b/ios/Classes/Options.swift index 96ba50eb..08f4976e 100755 --- a/ios/Classes/Options.swift +++ b/ios/Classes/Options.swift @@ -16,7 +16,7 @@ public class Options: NSObject { func parse(options: [String: Any?]) -> Options { for (key, value) in options { - if !(value is NSNull) { + if value != nil, !(value is NSNull) { if self.responds(to: Selector(key)) { self.setValue(value, forKey: key) } From af460d674659157acbdcbb8d5d0859b98f31d749 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 15 Apr 2022 20:35:23 +0200 Subject: [PATCH 22/40] Update InAppWebView.swift removed setting `applicationNameForUserAgent` property from `prepare` method. --- ios/Classes/InAppWebView/InAppWebView.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index 8ad01295..23f2fcda 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -405,9 +405,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi if #available(iOS 9.0, *) { configuration.allowsAirPlayForMediaPlayback = options.allowsAirPlayForMediaPlayback configuration.allowsPictureInPictureMediaPlayback = options.allowsPictureInPictureMediaPlayback - if !options.applicationNameForUserAgent.isEmpty { - configuration.applicationNameForUserAgent = options.applicationNameForUserAgent - } } configuration.preferences.javaScriptCanOpenWindowsAutomatically = options.javaScriptCanOpenWindowsAutomatically From 710fc1e02156c76163217d2c5bf9a2e10f74e722 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 15 Apr 2022 23:18:54 +0200 Subject: [PATCH 23/40] Added singleInstance option for Android ChromeSafariBrowser implementation, updated android compileSdkVersion to 31 --- .fvm/flutter_sdk | 1 + .fvm/fvm_config.json | 4 +++ CHANGELOG.md | 5 +++ android/build.gradle | 2 +- android/src/main/AndroidManifest.xml | 4 +++ .../flutter_inappwebview/Util.java | 4 +++ ...hromeCustomTabsActivitySingleInstance.java | 7 ++++ .../ChromeSafariBrowserManager.java | 4 ++- example/.flutter-plugins-dependencies | 2 +- example/android/app/build.gradle | 4 +-- .../android/app/src/main/AndroidManifest.xml | 33 +++++++++---------- .../ios/Flutter/flutter_export_environment.sh | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 +-- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../chrome_safari_browser_example.screen.dart | 1 + example/lib/in_app_webiew_example.screen.dart | 2 +- flutter_inappwebview.iml | 6 ++++ .../android/chrome_custom_tabs_options.dart | 10 ++++-- lib/src/types.dart | 8 +---- 19 files changed, 69 insertions(+), 36 deletions(-) create mode 120000 .fvm/flutter_sdk create mode 100644 .fvm/fvm_config.json create mode 100755 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeCustomTabsActivitySingleInstance.java diff --git a/.fvm/flutter_sdk b/.fvm/flutter_sdk new file mode 120000 index 00000000..c6e3b15b --- /dev/null +++ b/.fvm/flutter_sdk @@ -0,0 +1 @@ +/Users/lorenzopichilli/fvm/versions/2.10.4 \ No newline at end of file diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json new file mode 100644 index 00000000..d2faf497 --- /dev/null +++ b/.fvm/fvm_config.json @@ -0,0 +1,4 @@ +{ + "flutterSdkVersion": "2.10.4", + "flavors": {} +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c2d8c81b..c49890d4 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ## 5.3.3 - `getOriginalUrl` method is cross-platform now +- Updated Android `compileSdkVersion` to 31 +- Added `singleInstance` option for Android `ChromeSafariBrowser` implementation - Fixed `requestImageRef` method always `null` on iOS +- Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525) +- Merge "Fix parsing crash on null value." [#828](https://github.com/pichillilorenzo/flutter_inappwebview/pull/828) (thanks to [ItsCalebJones](https://github.com/ItsCalebJones)) +- Merge "fix: ApplicationNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) ## 5.3.2 diff --git a/android/build.gradle b/android/build.gradle index a5e831c4..443ec147 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 30 + compileSdkVersion 31 defaultConfig { minSdkVersion 17 diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 40dc1267..c6ffe08e 100755 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -9,6 +9,10 @@ + @@ -36,22 +35,22 @@ - - - - + + + + + + + + + + + + + + + + { InAppWebViewGroupOptions options = InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, - mediaPlaybackRequiresUserGesture: false, + mediaPlaybackRequiresUserGesture: false ), android: AndroidInAppWebViewOptions( useHybridComposition: true, diff --git a/flutter_inappwebview.iml b/flutter_inappwebview.iml index 0adae5aa..4f3a5faa 100755 --- a/flutter_inappwebview.iml +++ b/flutter_inappwebview.iml @@ -5,6 +5,12 @@ + + + + + + diff --git a/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart b/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart index d6901bb8..1fb97365 100755 --- a/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart +++ b/lib/src/chrome_safari_browser/android/chrome_custom_tabs_options.dart @@ -35,6 +35,9 @@ class AndroidChromeCustomTabsOptions ///Set to `true` to enable Keep Alive. The default value is `false`. bool keepAliveEnabled; + ///Set to `true` to launch the Android activity in `singleInstance` mode. The default value is `false`. + bool singleInstance; + AndroidChromeCustomTabsOptions( {this.addDefaultShareMenuItem = true, this.showTitle = true, @@ -42,7 +45,8 @@ class AndroidChromeCustomTabsOptions this.enableUrlBarHiding = false, this.instantAppsEnabled = false, this.packageName, - this.keepAliveEnabled = false}); + this.keepAliveEnabled = false, + this.singleInstance = false}); @override Map toMap() { @@ -53,7 +57,8 @@ class AndroidChromeCustomTabsOptions "enableUrlBarHiding": enableUrlBarHiding, "instantAppsEnabled": instantAppsEnabled, "packageName": packageName, - "keepAliveEnabled": keepAliveEnabled + "keepAliveEnabled": keepAliveEnabled, + "singleInstance": singleInstance }; } @@ -68,6 +73,7 @@ class AndroidChromeCustomTabsOptions options.instantAppsEnabled = map["instantAppsEnabled"]; options.packageName = map["packageName"]; options.keepAliveEnabled = map["keepAliveEnabled"]; + options.singleInstance = map["singleInstance"]; return options; } diff --git a/lib/src/types.dart b/lib/src/types.dart index 12ecc54d..96bf9d7e 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -6858,8 +6858,7 @@ class WebViewImplementation { const WebViewImplementation._internal(this._value); static final Set values = [ - WebViewImplementation.NATIVE, - WebViewImplementation.GECKO, + WebViewImplementation.NATIVE ].toSet(); static WebViewImplementation? fromValue(int? value) { @@ -6879,8 +6878,6 @@ class WebViewImplementation { @override String toString() { switch (_value) { - case 1: - return "GECKO"; case 0: default: return "NATIVE"; @@ -6890,9 +6887,6 @@ class WebViewImplementation { ///Default native implementation, such as `WKWebView` for iOS and `android.webkit.WebView` for Android. static const NATIVE = const WebViewImplementation._internal(0); - ///Android-only WebView implementation using the Mozilla's Gecko browser engine. - static const GECKO = const WebViewImplementation._internal(1); - bool operator ==(value) => value == _value; @override From 6e5669fb6848331d85a88816744381688201ac8e Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 15 Apr 2022 23:45:17 +0200 Subject: [PATCH 24/40] updated changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c49890d4..f1698933 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,13 @@ - Added `singleInstance` option for Android `ChromeSafariBrowser` implementation - Fixed `requestImageRef` method always `null` on iOS - Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525) +- Fixed "Crash when try select file from webview input on Android" [#867](https://github.com/pichillilorenzo/flutter_inappwebview/issues/867) +- Fixed "NavigationAction.request should use toMap method" [#878](https://github.com/pichillilorenzo/flutter_inappwebview/issues/878) - Merge "Fix parsing crash on null value." [#828](https://github.com/pichillilorenzo/flutter_inappwebview/pull/828) (thanks to [ItsCalebJones](https://github.com/ItsCalebJones)) - Merge "fix: ApplicationNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) +- Merge "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) +- Merge "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) +- Merge "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) ## 5.3.2 From 6635a7e8dfbe60da943c792c53972e4d87d9b816 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 00:24:16 +0200 Subject: [PATCH 25/40] Update HeadlessInAppWebView.swift --- .../HeadlessInAppWebView/HeadlessInAppWebView.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift index 4bfa9e75..b5f2ef62 100644 --- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift @@ -21,10 +21,6 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate { self.channel?.setMethodCallHandler(self.handle) } - deinit { - dispose() - } - public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { let arguments = call.arguments as? NSDictionary @@ -96,4 +92,9 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate { HeadlessInAppWebViewManager.webViews.removeValue(forKey: id) flutterWebView = nil } + + deinit { + print("HeadlessInAppWebView - dealloc") + dispose() + } } From 85e45ca00aeac1e10bd724ab9c5660e628847347 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 00:30:28 +0200 Subject: [PATCH 26/40] updated changelog, fixed implementation param when creating headless webview --- CHANGELOG.md | 9 ++++++++- example/.flutter-plugins-dependencies | 2 +- lib/src/in_app_webview/headless_in_app_webview.dart | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1698933..9735628c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,18 @@ - Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525) - Fixed "Crash when try select file from webview input on Android" [#867](https://github.com/pichillilorenzo/flutter_inappwebview/issues/867) - Fixed "NavigationAction.request should use toMap method" [#878](https://github.com/pichillilorenzo/flutter_inappwebview/issues/878) -- Merge "Fix parsing crash on null value." [#828](https://github.com/pichillilorenzo/flutter_inappwebview/pull/828) (thanks to [ItsCalebJones](https://github.com/ItsCalebJones)) +- Fixed "Missing body field in URLRequest toMap method" [#990](https://github.com/pichillilorenzo/flutter_inappwebview/issues/990) +- Fixed "iOS : createWindowAction.request.body in onCreateWindow() is NULL" [#994](https://github.com/pichillilorenzo/flutter_inappwebview/issues/994) +- Fixed "Crash at HeadlessInAppWebView dispose" [#881](https://github.com/pichillilorenzo/flutter_inappwebview/issues/881) +- Fixed "Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#972](https://github.com/pichillilorenzo/flutter_inappwebview/issues/972) +- Merge "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) - Merge "fix: ApplicationNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) - Merge "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) - Merge "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) - Merge "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) +- Merge "switch android mockserver dependency with okhttp" [#946](https://github.com/pichillilorenzo/flutter_inappwebview/pull/946) (thanks to [randysecrist](https://github.com/randysecrist)) +- Merge "Adds missing body to URLRequest mapping." [#991](https://github.com/pichillilorenzo/flutter_inappwebview/pull/991) (thanks to [Miiha](https://github.com/Miiha)) +- Merge "fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#1017](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1017) (thanks to [hoanglm4](https://github.com/hoanglm4)) ## 5.3.2 diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index bd134671..3a7b421e 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-15 23:09:44.904185","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 00:12:14.766086","version":"2.10.4"} \ No newline at end of file diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index 232d4e6d..4e1460a1 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -148,7 +148,7 @@ class HeadlessInAppWebView implements WebView { 'initialOptions': this.initialOptions?.toMap() ?? {}, 'contextMenu': this.contextMenu?.toMap() ?? {}, 'windowId': this.windowId, - 'implementation': this.implementation, + 'implementation': this.implementation.toValue(), 'initialUserScripts': this.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], 'pullToRefreshOptions': From 7d6772450be31a19c1563dbdc2dc2025eecfd6fc Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 00:52:57 +0200 Subject: [PATCH 27/40] merge --- .../in_app_webview/InAppWebViewChromeClient.java | 14 ++++++++++++++ example/.flutter-plugins-dependencies | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java index c4afd089..b49f07f1 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebViewChromeClient.java @@ -11,6 +11,7 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.os.Environment; import android.os.Message; import android.os.Parcelable; @@ -573,6 +574,19 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR WebView.HitTestResult result = view.getHitTestResult(); String url = result.getExtra(); + // Ensure that images with hyperlink return the correct URL, not the image source + if(result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { + Message href = view.getHandler().obtainMessage(); + view.requestFocusNodeHref(href); + Bundle data = href.getData(); + if (data != null) { + String imageUrl = data.getString("url"); + if(imageUrl != null && !imageUrl.isEmpty()) { + url = imageUrl; + } + } + } + URLRequest request = new URLRequest(url, "GET", null, null); CreateWindowAction createWindowAction = new CreateWindowAction( request, diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 3a7b421e..e5f22107 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 00:12:14.766086","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 00:42:19.758209","version":"2.10.4"} \ No newline at end of file From 96b6525781d1896c866738eb7f81ef4c1ba1fbc5 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 00:59:44 +0200 Subject: [PATCH 28/40] Update InAppWebView.java --- .../flutter_inappwebview/in_app_webview/InAppWebView.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java index 63354eed..890761f9 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java @@ -1302,8 +1302,7 @@ final public class InAppWebView extends InputAwareWebView { public void run() { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE); - if (containerView!=null && imm != null && !imm.isAcceptingText()) { - + if (containerView != null && imm != null && !imm.isAcceptingText()) { imm.hideSoftInputFromWindow( containerView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } From 5666c685b25a54029b03e075f61d67984d9a3ec3 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 11:28:55 +0200 Subject: [PATCH 29/40] updated changelog --- .idea/vcs.xml | 1 + CHANGELOG.md | 1 + example/.flutter-plugins-dependencies | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 46ea4792..9507e436 100755 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,7 @@ + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f018ed2f..b24eaad2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Merge "fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#1017](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1017) (thanks to [hoanglm4](https://github.com/hoanglm4)) - Merge "Fixes URL returned when taping image with href in onCreateWindow [Android]" [#1042](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1042) (thanks to [Manuito83](https://github.com/Manuito83)) - Merge "Fix Android Sometimes crash after close webpage and return to platform code." [#1050](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1050) (thanks to [rsydor](https://github.com/rsydor)) +- Merge "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) ## 5.3.2 diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index ede22c82..854d4b20 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 01:08:39.809089","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 11:23:41.893007","version":"2.10.4"} \ No newline at end of file From be1ffd1342d96a75624521ad7bddf303740a5976 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 11:41:15 +0200 Subject: [PATCH 30/40] updated android gitignore --- CHANGELOG.md | 2 ++ android/.gitignore | 7 ++++++- android/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 ----- 4 files changed, 8 insertions(+), 6 deletions(-) delete mode 100755 android/gradle/wrapper/gradle-wrapper.jar delete mode 100755 android/gradle/wrapper/gradle-wrapper.properties diff --git a/CHANGELOG.md b/CHANGELOG.md index b24eaad2..a54635e1 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Fixed "Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#972](https://github.com/pichillilorenzo/flutter_inappwebview/issues/972) - Fixed "In android, when click a href with img returns img src on onCreateWindow" [#951](https://github.com/pichillilorenzo/flutter_inappwebview/issues/951) - Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) +- Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) - Merge "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) - Merge "fix: ApplicationNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) - Merge "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) @@ -24,6 +25,7 @@ - Merge "Fixes URL returned when taping image with href in onCreateWindow [Android]" [#1042](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1042) (thanks to [Manuito83](https://github.com/Manuito83)) - Merge "Fix Android Sometimes crash after close webpage and return to platform code." [#1050](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1050) (thanks to [rsydor](https://github.com/rsydor)) - Merge "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) +- Merge "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) ## 5.3.2 diff --git a/android/.gitignore b/android/.gitignore index c6cbe562..7b942669 100755 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,8 +1,13 @@ *.iml -.gradle +.gradle/ +gradlew +gradlew.bat +gradle-wrapper.jar /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures +local.properties +keystore.properties \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100755 index f6b961fd5a86aa5fbfe90f707c3138408be7c718..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100755 index fd50c3ca..00000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip \ No newline at end of file From 407529519981d0fbaf5def78fb00ad1d97e5e351 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 12:17:06 +0200 Subject: [PATCH 31/40] Delete gradle-wrapper.properties --- android/gradle/wrapper/gradle-wrapper.properties | 5 ----- 1 file changed, 5 deletions(-) delete mode 100755 android/gradle/wrapper/gradle-wrapper.properties diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100755 index e42931e3..00000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip \ No newline at end of file From c55e468c7edcbc9326e827024d7a84403bc0b0bc Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 12:17:50 +0200 Subject: [PATCH 32/40] updated some .gitignore files, deleted gradle wrapper android plugin directory --- .gitignore | 32 +++++++++++++++---- CHANGELOG.md | 2 +- android/.gitignore | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +-- ios/.gitignore | 2 ++ 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index eb487e55..9be145fd 100755 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,29 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp .DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ .dart_tool/ - -.vscode/ .packages -.pub/ -pubspec.lock - build/ - -.idea/workspace.xml \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a54635e1..26053885 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ - Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) - Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) - Merge "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) -- Merge "fix: ApplicationNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) +- Merge "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) - Merge "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) - Merge "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) - Merge "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) diff --git a/android/.gitignore b/android/.gitignore index 7b942669..4b97ae3e 100755 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,5 +1,5 @@ *.iml -.gradle/ +.gradle gradlew gradlew.bat gradle-wrapper.jar diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2678abc6..bc6a58af 100755 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Sep 26 11:13:08 CEST 2020 +#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/ios/.gitignore b/ios/.gitignore index 710ec6cf..0c885071 100755 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -34,3 +34,5 @@ Icon? .tags* /Flutter/Generated.xcconfig +/Flutter/ephemeral/ +/Flutter/flutter_export_environment.sh \ No newline at end of file From 5c9e1216d201028f37011016682cdab2aac8c763 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 16 Apr 2022 12:32:17 +0200 Subject: [PATCH 33/40] removed .idea folder from repo, updated build.gradle example --- .idea/codeStyles/Project.xml | 122 ------------------ .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/encodings.xml | 4 - .idea/libraries/Dart_SDK.xml | 28 ---- .idea/libraries/Flutter_Plugins.xml | 9 -- .idea/libraries/Flutter_for_Android.xml | 9 -- .idea/markdown-navigator-enh.xml | 29 ----- .idea/markdown-navigator.xml | 57 -------- .idea/misc.xml | 45 ------- .idea/modules.xml | 9 -- .../example_lib_main_dart.xml | 6 - .idea/vcs.xml | 8 -- CHANGELOG.md | 107 +++++++-------- example/.flutter-plugins-dependencies | 2 +- example/android/build.gradle | 4 +- 15 files changed, 58 insertions(+), 386 deletions(-) delete mode 100755 .idea/codeStyles/Project.xml delete mode 100755 .idea/codeStyles/codeStyleConfig.xml delete mode 100755 .idea/encodings.xml delete mode 100755 .idea/libraries/Dart_SDK.xml delete mode 100755 .idea/libraries/Flutter_Plugins.xml delete mode 100755 .idea/libraries/Flutter_for_Android.xml delete mode 100644 .idea/markdown-navigator-enh.xml delete mode 100755 .idea/markdown-navigator.xml delete mode 100755 .idea/misc.xml delete mode 100755 .idea/modules.xml delete mode 100755 .idea/runConfigurations/example_lib_main_dart.xml delete mode 100755 .idea/vcs.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100755 index 6bbadb56..00000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - -

- - - - xmlns:android - - ^$ - - - -
-
- - - - xmlns:.* - - ^$ - - - BY_NAME - -
-
- - - - .*:id - - http://schemas.android.com/apk/res/android - - - -
-
- - - - .*:name - - http://schemas.android.com/apk/res/android - - - -
-
- - - - name - - ^$ - - - -
-
- - - - style - - ^$ - - - -
-
- - - - .* - - ^$ - - - BY_NAME - -
-
- - - - .* - - http://schemas.android.com/apk/res/android - - - ANDROID_ATTRIBUTE_ORDER - -
-
- - - - .* - - .* - - - BY_NAME - -
- - - - -
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100755 index 79ee123c..00000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100755 index 15a15b21..00000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml deleted file mode 100755 index 1889af48..00000000 --- a/.idea/libraries/Dart_SDK.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml deleted file mode 100755 index 65bb3679..00000000 --- a/.idea/libraries/Flutter_Plugins.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Flutter_for_Android.xml b/.idea/libraries/Flutter_for_Android.xml deleted file mode 100755 index 282dba69..00000000 --- a/.idea/libraries/Flutter_for_Android.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml deleted file mode 100644 index 12fb99d1..00000000 --- a/.idea/markdown-navigator-enh.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml deleted file mode 100755 index 097c2565..00000000 --- a/.idea/markdown-navigator.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100755 index 5d05d05d..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100755 index dea0765f..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_lib_main_dart.xml b/.idea/runConfigurations/example_lib_main_dart.xml deleted file mode 100755 index bac2c8a7..00000000 --- a/.idea/runConfigurations/example_lib_main_dart.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100755 index 9507e436..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 26053885..1394a28f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,18 +14,19 @@ - Fixed "In android, when click a href with img returns img src on onCreateWindow" [#951](https://github.com/pichillilorenzo/flutter_inappwebview/issues/951) - Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) - Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) -- Merge "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) -- Merge "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) -- Merge "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) -- Merge "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) -- Merge "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) -- Merge "switch android mockserver dependency with okhttp" [#946](https://github.com/pichillilorenzo/flutter_inappwebview/pull/946) (thanks to [randysecrist](https://github.com/randysecrist)) -- Merge "Adds missing body to URLRequest mapping." [#991](https://github.com/pichillilorenzo/flutter_inappwebview/pull/991) (thanks to [Miiha](https://github.com/Miiha)) -- Merge "fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#1017](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1017) (thanks to [hoanglm4](https://github.com/hoanglm4)) -- Merge "Fixes URL returned when taping image with href in onCreateWindow [Android]" [#1042](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1042) (thanks to [Manuito83](https://github.com/Manuito83)) -- Merge "Fix Android Sometimes crash after close webpage and return to platform code." [#1050](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1050) (thanks to [rsydor](https://github.com/rsydor)) -- Merge "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) -- Merge "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) +- Merged "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) +- Merged "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) +- Merged "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) +- Merged "fix bug when in String[] array come null" [#868](https://github.com/pichillilorenzo/flutter_inappwebview/pull/868) (thanks to [Ser1ous](https://github.com/Ser1ous)) +- Merged "fix: use in NavigationAction request toMap method" [#879](https://github.com/pichillilorenzo/flutter_inappwebview/pull/879) (thanks to [chreck](https://github.com/chreck)) +- Merged "switch android mockserver dependency with okhttp" [#946](https://github.com/pichillilorenzo/flutter_inappwebview/pull/946) (thanks to [randysecrist](https://github.com/randysecrist)) +- Merged "Adds missing body to URLRequest mapping." [#991](https://github.com/pichillilorenzo/flutter_inappwebview/pull/991) (thanks to [Miiha](https://github.com/Miiha)) +- Merged "fix. Crash happens when HeadlessInAppWebView's dispose function is called in iOS" [#1017](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1017) (thanks to [hoanglm4](https://github.com/hoanglm4)) +- Merged "Fixes URL returned when taping image with href in onCreateWindow [Android]" [#1042](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1042) (thanks to [Manuito83](https://github.com/Manuito83)) +- Merged "Fix Android Sometimes crash after close webpage and return to platform code." [#1050](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1050) (thanks to [rsydor](https://github.com/rsydor)) +- Merged "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) +- Merged "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) +- Merged "updated com.android.tools.build:gradle" [#1066](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1066) (thanks to [chownation](https://github.com/chownation)) ## 5.3.2 @@ -92,7 +93,7 @@ - Fixed iOS sometimes `scrollView.contentSize` doesn't fit all the `frame.size` available - Fixed ajax and fetch interceptor when the data/body sent is not a string - Fixed "InAppLocalhostServer - Error: type 'List' is not a subtype of type 'List' in type cast" [#724](https://github.com/pichillilorenzo/flutter_inappwebview/issues/724) -- Merge "fix proguard" [#737](https://github.com/pichillilorenzo/flutter_inappwebview/pull/737) (thanks to [myroid](https://github.com/myroid)) +- Merged "fix proguard" [#737](https://github.com/pichillilorenzo/flutter_inappwebview/pull/737) (thanks to [myroid](https://github.com/myroid)) ### BREAKING CHANGES @@ -178,19 +179,19 @@ - Added new iOS-specific attributes to `ShouldOverrideUrlLoadingRequest` and `CreateWindowRequest` classes - Added `toolbarTopTranslucent`, `toolbarTopTintColor`, `toolbarBottomTintColor`, `toolbarTopBarTintColor` ios-specific InAppBrowser options - Updated integration tests -- Merge "Upgraded appcompat to 1.2.0-rc-02" [#465](https://github.com/pichillilorenzo/flutter_inappwebview/pull/465) (thanks to [andreidiaconu](https://github.com/andreidiaconu)) -- Merge "Added missing field 'headers' which returned by WebResourceResponse.toMap()" [#490](https://github.com/pichillilorenzo/flutter_inappwebview/pull/490) (thanks to [Doflatango](https://github.com/Doflatango)) -- Merge "Fix: added iOS fallback module import" [#466](https://github.com/pichillilorenzo/flutter_inappwebview/pull/466) (thanks to [Eddayy](https://github.com/Eddayy)) -- Merge "Fix NullPointerException after taking a photo by a camera app on Android" [#492](https://github.com/pichillilorenzo/flutter_inappwebview/pull/492) (thanks to [AAkira](https://github.com/AAkira)) -- Merge "iOS CookieManager.getCookies - Check that URL has suffix of cookie do…" [#658](https://github.com/pichillilorenzo/flutter_inappwebview/pull/658) (thanks to [arneke](https://github.com/arneke)) -- Merge "Add NTLM Auth" [#634](https://github.com/pichillilorenzo/flutter_inappwebview/pull/634) (thanks to [albatrosify](https://github.com/albatrosify)) -- Merge "iOS ChromeSafariBrowserManager - Fixing unnecessary casting of rootViewController to FlutterViewController" [#567](https://github.com/pichillilorenzo/flutter_inappwebview/pull/567) (thanks to [gunantosteven](https://github.com/gunantosteven)) -- Merge "Fix _channel.invokeMethod name for injectCSSFileFromUrl method" [#645](https://github.com/pichillilorenzo/flutter_inappwebview/pull/645) (thanks to [omralcrt](https://github.com/omralcrt)) -- Merge "Add android media intents on wildcard input accept" [#620](https://github.com/pichillilorenzo/flutter_inappwebview/pull/620) (thanks to [cbodin](https://github.com/cbodin)) -- Merge "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi)) -- Merge "fix(iOS): missing implementation of method zoomBy" [#670](https://github.com/pichillilorenzo/flutter_inappwebview/pull/670) (thanks to [pcqpcq](https://github.com/pcqpcq)) -- Merge "[mod] Fix all issues relate to long click in Android version 7.0 (#657, #527)" [#671](https://github.com/pichillilorenzo/flutter_inappwebview/pull/671) (thanks to [MrNinja](https://github.com/MrNinja)) -- Merge "Fix ViewGroup.removeView NullPointerException (#450)" [#683](https://github.com/pichillilorenzo/flutter_inappwebview/pull/683) (thanks to [toda-bps](https://github.com/toda-bps)) +- Merged "Upgraded appcompat to 1.2.0-rc-02" [#465](https://github.com/pichillilorenzo/flutter_inappwebview/pull/465) (thanks to [andreidiaconu](https://github.com/andreidiaconu)) +- Merged "Added missing field 'headers' which returned by WebResourceResponse.toMap()" [#490](https://github.com/pichillilorenzo/flutter_inappwebview/pull/490) (thanks to [Doflatango](https://github.com/Doflatango)) +- Merged "Fix: added iOS fallback module import" [#466](https://github.com/pichillilorenzo/flutter_inappwebview/pull/466) (thanks to [Eddayy](https://github.com/Eddayy)) +- Merged "Fix NullPointerException after taking a photo by a camera app on Android" [#492](https://github.com/pichillilorenzo/flutter_inappwebview/pull/492) (thanks to [AAkira](https://github.com/AAkira)) +- Merged "iOS CookieManager.getCookies - Check that URL has suffix of cookie do…" [#658](https://github.com/pichillilorenzo/flutter_inappwebview/pull/658) (thanks to [arneke](https://github.com/arneke)) +- Merged "Add NTLM Auth" [#634](https://github.com/pichillilorenzo/flutter_inappwebview/pull/634) (thanks to [albatrosify](https://github.com/albatrosify)) +- Merged "iOS ChromeSafariBrowserManager - Fixing unnecessary casting of rootViewController to FlutterViewController" [#567](https://github.com/pichillilorenzo/flutter_inappwebview/pull/567) (thanks to [gunantosteven](https://github.com/gunantosteven)) +- Merged "Fix _channel.invokeMethod name for injectCSSFileFromUrl method" [#645](https://github.com/pichillilorenzo/flutter_inappwebview/pull/645) (thanks to [omralcrt](https://github.com/omralcrt)) +- Merged "Add android media intents on wildcard input accept" [#620](https://github.com/pichillilorenzo/flutter_inappwebview/pull/620) (thanks to [cbodin](https://github.com/cbodin)) +- Merged "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi)) +- Merged "fix(iOS): missing implementation of method zoomBy" [#670](https://github.com/pichillilorenzo/flutter_inappwebview/pull/670) (thanks to [pcqpcq](https://github.com/pcqpcq)) +- Merged "[mod] Fix all issues relate to long click in Android version 7.0 (#657, #527)" [#671](https://github.com/pichillilorenzo/flutter_inappwebview/pull/671) (thanks to [MrNinja](https://github.com/MrNinja)) +- Merged "Fix ViewGroup.removeView NullPointerException (#450)" [#683](https://github.com/pichillilorenzo/flutter_inappwebview/pull/683) (thanks to [toda-bps](https://github.com/toda-bps)) - Fixed missing properties initialization when using InAppWebViewController.fromInAppBrowser - Fixed "Issue in Flutter web: 'Unsupported operation: Platform._operatingSystem'" [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507) - Fixed "window.flutter_inappwebview.callHandler is not a function" [#218](https://github.com/pichillilorenzo/flutter_inappwebview/issues/218) @@ -392,13 +393,13 @@ - Updated for Flutter 1.12 new Java Embedding API (Android) - Updated `clearCache` for Android - Updated default value for `domStorageEnabled` and `databaseEnabled` options to `true` for Android -- Merge "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo)) -- Merge "Fixes crash onConsoleMessage iOS forced unwrapping" [#228](https://github.com/pichillilorenzo/flutter_inappwebview/pull/228) (thanks to [tokonu](https://github.com/tokonu)) -- Merge "Fix HTTPCookie.secure" [#311](https://github.com/pichillilorenzo/flutter_inappwebview/pull/311) (thanks to [xtyxtyx](https://github.com/xtyxtyx)) -- Merge "Fix config options for Android release builds" [#295](https://github.com/pichillilorenzo/flutter_inappwebview/pull/295) (thanks to [wwwdata](https://github.com/wwwdata)) -- Merge "fix scrollbar on iOS always show if not disable scroll" [#256](https://github.com/pichillilorenzo/flutter_inappwebview/pull/256) (thanks to [phamnhuvu-dev](https://github.com/phamnhuvu-dev)) -- Merge "Fix crash on nil/invalid URL (iOS)" [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/262) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) -- Merge "Fix crash when `prompt` was called on Android Q." [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/263) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) +- Merged "Fixes null error when calling getOptions for InAppBrowser class" [#214](https://github.com/pichillilorenzo/flutter_inappwebview/pull/214) (thanks to [panndoraBoo](https://github.com/panndoraBoo)) +- Merged "Fixes crash onConsoleMessage iOS forced unwrapping" [#228](https://github.com/pichillilorenzo/flutter_inappwebview/pull/228) (thanks to [tokonu](https://github.com/tokonu)) +- Merged "Fix HTTPCookie.secure" [#311](https://github.com/pichillilorenzo/flutter_inappwebview/pull/311) (thanks to [xtyxtyx](https://github.com/xtyxtyx)) +- Merged "Fix config options for Android release builds" [#295](https://github.com/pichillilorenzo/flutter_inappwebview/pull/295) (thanks to [wwwdata](https://github.com/wwwdata)) +- Merged "fix scrollbar on iOS always show if not disable scroll" [#256](https://github.com/pichillilorenzo/flutter_inappwebview/pull/256) (thanks to [phamnhuvu-dev](https://github.com/phamnhuvu-dev)) +- Merged "Fix crash on nil/invalid URL (iOS)" [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/262) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) +- Merged "Fix crash when `prompt` was called on Android Q." [#262](https://github.com/pichillilorenzo/flutter_inappwebview/pull/263) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) - Fix for Android and iOS `InAppBrowser` for some controller methods not exposed. - Fixed "App Crashes after clicking on dropdown (Using inappwebview)" [#182](https://github.com/pichillilorenzo/flutter_inappwebview/issues/182) - Fixed "webview can not be released when in ios" [#225](https://github.com/pichillilorenzo/flutter_inappwebview/issues/225). Now the iOS WebView is released from memory when it is disposed from Flutter. @@ -445,16 +446,16 @@ ## 2.0.0 -- Merge "Avoid null pointer exception after webview is disposed" [#116](https://github.com/pichillilorenzo/flutter_inappwebview/pull/116) (thanks to [robsonfingo](https://github.com/robsonfingo)) -- Merge "Remove async call in close" [#119](https://github.com/pichillilorenzo/flutter_inappwebview/pull/119) (thanks to [benfingo](https://github.com/benfingo)) -- Merge "Android takeScreenshot does not work properly." [#122](https://github.com/pichillilorenzo/flutter_inappwebview/pull/122) (thanks to [PauloMelo](https://github.com/PauloMelo)) -- Merge "Resolving gradle error." [#144](https://github.com/pichillilorenzo/flutter_inappwebview/pull/144) (thanks to [Klingens13](https://github.com/Klingens13)) -- Merge "Create issue and pull request templates" [#150](https://github.com/pichillilorenzo/flutter_inappwebview/pull/150) (thanks to [deandreamatias](https://github.com/deandreamatias)) -- Merge "Fix abstract method error && swift version error" [#155](https://github.com/pichillilorenzo/flutter_inappwebview/pull/155) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) -- Merge "migrating to swift 5.0" [#162](https://github.com/pichillilorenzo/flutter_inappwebview/pull/162) (thanks to [fattiger00](https://github.com/fattiger00)) -- Merge "Update readme example" [#178](https://github.com/pichillilorenzo/flutter_inappwebview/pull/178) (thanks to [SebastienBtr](https://github.com/SebastienBtr)) -- Merge "handle choose file callback in android" [#183](https://github.com/pichillilorenzo/flutter_inappwebview/pull/183) (thanks to [crazecoder](https://github.com/crazecoder)) -- Merge "add initialScale in android" [#186](https://github.com/pichillilorenzo/flutter_inappwebview/pull/186) (thanks to [crazecoder](https://github.com/crazecoder)) +- Merged "Avoid null pointer exception after webview is disposed" [#116](https://github.com/pichillilorenzo/flutter_inappwebview/pull/116) (thanks to [robsonfingo](https://github.com/robsonfingo)) +- Merged "Remove async call in close" [#119](https://github.com/pichillilorenzo/flutter_inappwebview/pull/119) (thanks to [benfingo](https://github.com/benfingo)) +- Merged "Android takeScreenshot does not work properly." [#122](https://github.com/pichillilorenzo/flutter_inappwebview/pull/122) (thanks to [PauloMelo](https://github.com/PauloMelo)) +- Merged "Resolving gradle error." [#144](https://github.com/pichillilorenzo/flutter_inappwebview/pull/144) (thanks to [Klingens13](https://github.com/Klingens13)) +- Merged "Create issue and pull request templates" [#150](https://github.com/pichillilorenzo/flutter_inappwebview/pull/150) (thanks to [deandreamatias](https://github.com/deandreamatias)) +- Merged "Fix abstract method error && swift version error" [#155](https://github.com/pichillilorenzo/flutter_inappwebview/pull/155) (thanks to [AlexVincent525](https://github.com/AlexVincent525)) +- Merged "migrating to swift 5.0" [#162](https://github.com/pichillilorenzo/flutter_inappwebview/pull/162) (thanks to [fattiger00](https://github.com/fattiger00)) +- Merged "Update readme example" [#178](https://github.com/pichillilorenzo/flutter_inappwebview/pull/178) (thanks to [SebastienBtr](https://github.com/SebastienBtr)) +- Merged "handle choose file callback in android" [#183](https://github.com/pichillilorenzo/flutter_inappwebview/pull/183) (thanks to [crazecoder](https://github.com/crazecoder)) +- Merged "add initialScale in android" [#186](https://github.com/pichillilorenzo/flutter_inappwebview/pull/186) (thanks to [crazecoder](https://github.com/crazecoder)) - Added `horizontalScrollBarEnabled` and `verticalScrollBarEnabled` options to enable/disable the corresponding scrollbar of the WebView [#165](https://github.com/pichillilorenzo/flutter_inappwebview/issues/165) - Added `onDownloadStart` event and `useOnDownloadStart` option: event fires when the WebView recognizes and starts a downloadable file. - Added `onLoadResourceCustomScheme` event and `resourceCustomSchemes` option to set custom schemes that WebView must handle to load resources @@ -493,22 +494,22 @@ ## 1.2.2 -- Merge "added a shared WKProcessPool for webview instances" [#198](https://github.com/pichillilorenzo/flutter_inappwebview/pull/198) (thanks to [robertcnst](https://github.com/robertcnst)) +- Merged "added a shared WKProcessPool for webview instances" [#198](https://github.com/pichillilorenzo/flutter_inappwebview/pull/198) (thanks to [robertcnst](https://github.com/robertcnst)) - Fixed iOS setCookie. ## 1.2.1 -- Merge "Add new option to control the contentMode in Android platform" [#101](https://github.com/pichillilorenzo/flutter_inappwebview/pull/101) (thanks to [DreamBuddy](https://github.com/DreamBuddy)) -- Merge "Fix crash on xcode 10.2" [#107](https://github.com/pichillilorenzo/flutter_inappwebview/pull/107) (thanks to [robsonfingo](https://github.com/robsonfingo)) -- Merge "Remove headers_build_phase from example's Podfile" [#108](https://github.com/pichillilorenzo/flutter_inappwebview/pull/108) (thanks to [robsonfingo](https://github.com/robsonfingo)) +- Merged "Add new option to control the contentMode in Android platform" [#101](https://github.com/pichillilorenzo/flutter_inappwebview/pull/101) (thanks to [DreamBuddy](https://github.com/DreamBuddy)) +- Merged "Fix crash on xcode 10.2" [#107](https://github.com/pichillilorenzo/flutter_inappwebview/pull/107) (thanks to [robsonfingo](https://github.com/robsonfingo)) +- Merged "Remove headers_build_phase from example's Podfile" [#108](https://github.com/pichillilorenzo/flutter_inappwebview/pull/108) (thanks to [robsonfingo](https://github.com/robsonfingo)) - Fixed "Make html5 video fullscreen" for Android [#43](https://github.com/pichillilorenzo/flutter_inappwebview/issues/43) - Fixed "AllowsInlineMediaPlayback not working" for iOS [#73](https://github.com/pichillilorenzo/flutter_inappwebview/issues/73) ## 1.2.0 -- Merge "Adds a transparentBackground option for iOS and Android" [#86](https://github.com/pichillilorenzo/flutter_inappwebview/pull/86) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) -- Merge "The 'open' method requires an options dictionary" [#87](https://github.com/pichillilorenzo/flutter_inappwebview/pull/87) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) -- Merge "iOS: Call setNeedsLayout() in scrollViewDidScroll()" [#88](https://github.com/pichillilorenzo/flutter_inappwebview/pull/88) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) +- Merged "Adds a transparentBackground option for iOS and Android" [#86](https://github.com/pichillilorenzo/flutter_inappwebview/pull/86) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) +- Merged "The 'open' method requires an options dictionary" [#87](https://github.com/pichillilorenzo/flutter_inappwebview/pull/87) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) +- Merged "iOS: Call setNeedsLayout() in scrollViewDidScroll()" [#88](https://github.com/pichillilorenzo/flutter_inappwebview/pull/88) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) - Fixed "java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread." [#98](https://github.com/pichillilorenzo/flutter_inappwebview/issues/98) (thanks to [DreamBuddy](https://github.com/DreamBuddy)) - Fixed "app force close/crash when enabling zoom and repeatedly changing orientation and zoomin zoomout" [#93](https://github.com/pichillilorenzo/flutter_inappwebview/issues/93) - Added `displayZoomControls` webview option for Android @@ -516,14 +517,14 @@ ## 1.1.3 -- Merge "Add null checks around calls to InAppWebView callbacks" [#85](https://github.com/pichillilorenzo/flutter_inappwebview/pull/85) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) +- Merged "Add null checks around calls to InAppWebView callbacks" [#85](https://github.com/pichillilorenzo/flutter_inappwebview/pull/85) (thanks to [matthewlloyd](https://github.com/matthewlloyd)) ## 1.1.2 - Fix InAppBrowser crashes the app when i change the page "Lost connection" [#74](https://github.com/pichillilorenzo/flutter_inappwebview/issues/74) - Fix javascript `...args` parameter of `window.flutter_inappwebview.callHandler()` -- Merge Enable setTextZoom function of Android WebViewSetting [#81](https://github.com/pichillilorenzo/flutter_inappwebview/pull/81) (thanks to [YouCii](https://github.com/YouCii)) -- Merge bug fix for android build: Android dependency 'androidx.core:core' has different version for the compile (1.0.0) and runtime (1.0.1) classpath [#83](https://github.com/pichillilorenzo/flutter_inappwebview/pull/83) (thanks to [cinos1](https://github.com/cinos1)) +- Merged Enable setTextZoom function of Android WebViewSetting [#81](https://github.com/pichillilorenzo/flutter_inappwebview/pull/81) (thanks to [YouCii](https://github.com/YouCii)) +- Merged bug fix for android build: Android dependency 'androidx.core:core' has different version for the compile (1.0.0) and runtime (1.0.1) classpath [#83](https://github.com/pichillilorenzo/flutter_inappwebview/pull/83) (thanks to [cinos1](https://github.com/cinos1)) ## 1.1.1 diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 854d4b20..9e57a2d1 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 11:23:41.893007","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 12:29:54.757036","version":"2.10.4"} \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index 205da3d3..714549c2 100755 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,11 +1,13 @@ buildscript { + ext.kotlin_version = '1.6.10' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } From 22649342e8563028a7c2ddacff3cf0702410fe37 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 16:19:31 +0200 Subject: [PATCH 34/40] added onDownloadStartRequest event --- CHANGELOG.md | 2 + .../in_app_webview/InAppWebView.java | 21 ++- .../types/DownloadStartRequest.java | 150 ++++++++++++++++++ example/.flutter-plugins-dependencies | 2 +- .../webview_flutter_test.dart | 6 +- example/lib/in_app_webiew_example.screen.dart | 8 +- ios/Classes/InAppWebView/InAppWebView.swift | 14 +- ios/Classes/Types/DownloadStartRequest.swift | 42 +++++ lib/src/in_app_browser/in_app_browser.dart | 11 +- .../headless_in_app_webview.dart | 18 ++- lib/src/in_app_webview/in_app_webview.dart | 11 +- .../in_app_webview_controller.dart | 31 ++-- lib/src/in_app_webview/webview.dart | 14 +- lib/src/types.dart | 69 ++++++++ 14 files changed, 352 insertions(+), 47 deletions(-) create mode 100644 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/DownloadStartRequest.java create mode 100644 ios/Classes/Types/DownloadStartRequest.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 1394a28f..3831a7d2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ - `getOriginalUrl` method is cross-platform now - Updated Android `compileSdkVersion` to 31 - Added `singleInstance` option for Android `ChromeSafariBrowser` implementation +- Added `onDownloadStartRequest` event and deprecated old `onDownloadStart` event +- Fixed missing `onZoomScaleChanged` call for `InAppBrowser` class - Fixed `requestImageRef` method always `null` on iOS - Fixed "applicationNameForUserAgent is not work in ios" [#525](https://github.com/pichillilorenzo/flutter_inappwebview/issues/525) - Fixed "Crash when try select file from webview input on Android" [#867](https://github.com/pichillilorenzo/flutter_inappwebview/issues/867) diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java index 38ac2393..e0de2517 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_webview/InAppWebView.java @@ -37,6 +37,7 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.CookieManager; import android.webkit.DownloadListener; +import android.webkit.URLUtil; import android.webkit.ValueCallback; import android.webkit.WebBackForwardList; import android.webkit.WebHistoryItem; @@ -54,6 +55,7 @@ import androidx.webkit.WebViewCompat; import androidx.webkit.WebViewFeature; import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; +import com.pichillilorenzo.flutter_inappwebview.types.DownloadStartRequest; import com.pichillilorenzo.flutter_inappwebview.types.InAppWebViewInterface; import com.pichillilorenzo.flutter_inappwebview.JavaScriptBridgeInterface; import com.pichillilorenzo.flutter_inappwebview.R; @@ -1181,14 +1183,17 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie class DownloadStartListener implements DownloadListener { @Override - public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { - Map obj = new HashMap<>(); - obj.put("url", url); - obj.put("userAgent", userAgent); - obj.put("contentDisposition", contentDisposition); - obj.put("mimetype", mimetype); - obj.put("contentLength", contentLength); - channel.invokeMethod("onDownloadStart", obj); + public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) { + DownloadStartRequest downloadStartRequest = new DownloadStartRequest( + url, + userAgent, + contentDisposition, + mimeType, + contentLength, + URLUtil.guessFileName(url, contentDisposition, mimeType), + null + ); + channel.invokeMethod("onDownloadStartRequest", downloadStartRequest.toMap()); } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/DownloadStartRequest.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/DownloadStartRequest.java new file mode 100644 index 00000000..504fb693 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/DownloadStartRequest.java @@ -0,0 +1,150 @@ +package com.pichillilorenzo.flutter_inappwebview.types; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class DownloadStartRequest { + + @NonNull + private String url; + @NonNull + private String userAgent; + @NonNull + private String contentDisposition; + @NonNull + private String mimeType; + private long contentLength; + @Nullable + private String suggestedFilename; + @Nullable + private String textEncodingName; + + public DownloadStartRequest(@NonNull String url, @NonNull String userAgent, @NonNull String contentDisposition, @NonNull String mimeType, long contentLength, @Nullable String suggestedFilename, @Nullable String textEncodingName) { + this.url = url; + this.userAgent = userAgent; + this.contentDisposition = contentDisposition; + this.mimeType = mimeType; + this.contentLength = contentLength; + this.suggestedFilename = suggestedFilename; + this.textEncodingName = textEncodingName; + } + + public Map toMap() { + Map obj = new HashMap<>(); + obj.put("url", url); + obj.put("userAgent", userAgent); + obj.put("contentDisposition", contentDisposition); + obj.put("mimeType", mimeType); + obj.put("contentLength", contentLength); + obj.put("suggestedFilename", suggestedFilename); + obj.put("textEncodingName", textEncodingName); + return obj; + } + + @NonNull + public String getUrl() { + return url; + } + + public void setUrl(@NonNull String url) { + this.url = url; + } + + @NonNull + public String getUserAgent() { + return userAgent; + } + + public void setUserAgent(@NonNull String userAgent) { + this.userAgent = userAgent; + } + + @NonNull + public String getContentDisposition() { + return contentDisposition; + } + + public void setContentDisposition(@NonNull String contentDisposition) { + this.contentDisposition = contentDisposition; + } + + @NonNull + public String getMimeType() { + return mimeType; + } + + public void setMimeType(@NonNull String mimeType) { + this.mimeType = mimeType; + } + + public long getContentLength() { + return contentLength; + } + + public void setContentLength(long contentLength) { + this.contentLength = contentLength; + } + + @Nullable + public String getSuggestedFilename() { + return suggestedFilename; + } + + public void setSuggestedFilename(@Nullable String suggestedFilename) { + this.suggestedFilename = suggestedFilename; + } + + @Nullable + public String getTextEncodingName() { + return textEncodingName; + } + + public void setTextEncodingName(@Nullable String textEncodingName) { + this.textEncodingName = textEncodingName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DownloadStartRequest that = (DownloadStartRequest) o; + + if (contentLength != that.contentLength) return false; + if (!url.equals(that.url)) return false; + if (!userAgent.equals(that.userAgent)) return false; + if (!contentDisposition.equals(that.contentDisposition)) return false; + if (!mimeType.equals(that.mimeType)) return false; + if (suggestedFilename != null ? !suggestedFilename.equals(that.suggestedFilename) : that.suggestedFilename != null) + return false; + return textEncodingName != null ? textEncodingName.equals(that.textEncodingName) : that.textEncodingName == null; + } + + @Override + public int hashCode() { + int result = url.hashCode(); + result = 31 * result + userAgent.hashCode(); + result = 31 * result + contentDisposition.hashCode(); + result = 31 * result + mimeType.hashCode(); + result = 31 * result + (int) (contentLength ^ (contentLength >>> 32)); + result = 31 * result + (suggestedFilename != null ? suggestedFilename.hashCode() : 0); + result = 31 * result + (textEncodingName != null ? textEncodingName.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "DownloadStartRequest{" + + "url='" + url + '\'' + + ", userAgent='" + userAgent + '\'' + + ", contentDisposition='" + contentDisposition + '\'' + + ", mimeType='" + mimeType + '\'' + + ", contentLength=" + contentLength + + ", suggestedFilename='" + suggestedFilename + '\'' + + ", textEncodingName='" + textEncodingName + '\'' + + '}'; + } +} diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 9e57a2d1..a452f15c 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-16 12:29:54.757036","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 16:15:55.135230","version":"2.10.4"} \ No newline at end of file diff --git a/example/integration_test/webview_flutter_test.dart b/example/integration_test/webview_flutter_test.dart index 3a79f1ca..04d4e170 100644 --- a/example/integration_test/webview_flutter_test.dart +++ b/example/integration_test/webview_flutter_test.dart @@ -2705,7 +2705,7 @@ void main() { expect(numberOfMatches, 2); }); - testWidgets('onDownloadStart', (WidgetTester tester) async { + testWidgets('onDownloadStartRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onDownloadStartCompleter = Completer(); await tester.pumpWidget( @@ -2739,8 +2739,8 @@ void main() { onWebViewCreated: (controller) { controllerCompleter.complete(controller); }, - onDownloadStart:(controller, url, userAgent, contentDisposition, mimeType, contentLength) { - onDownloadStartCompleter.complete(url.toString()); + onDownloadStartRequest: (controller, request) { + onDownloadStartCompleter.complete(request.url.toString()); }, ), ), diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index 90f77064..569153d2 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -24,7 +24,8 @@ class _InAppWebViewExampleScreenState extends State { InAppWebViewGroupOptions options = InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, - mediaPlaybackRequiresUserGesture: false + mediaPlaybackRequiresUserGesture: false, + useOnDownloadStart: true ), android: AndroidInAppWebViewOptions( useHybridComposition: true, @@ -123,7 +124,7 @@ class _InAppWebViewExampleScreenState extends State { key: webViewKey, // contextMenu: contextMenu, initialUrlRequest: - URLRequest(url: Uri.parse("https://github.com/flutter")), + URLRequest(url: Uri.parse("https://testfiledownload.com/")), // initialFile: "assets/index.html", initialUserScripts: UnmodifiableListView([]), initialOptions: options, @@ -131,6 +132,9 @@ class _InAppWebViewExampleScreenState extends State { onWebViewCreated: (controller) { webViewController = controller; }, + onDownloadStartRequest: (controller, request) { + print(request); + }, onLoadStart: (controller, url) { setState(() { this.url = url.toString(); diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f70de3dc..7a9234ae 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -1546,7 +1546,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi let mimeType = navigationResponse.response.mimeType if let url = navigationResponse.response.url, navigationResponse.isForMainFrame { if url.scheme != "file", mimeType != nil, !mimeType!.starts(with: "text/") { - onDownloadStart(url: url.absoluteString) + let downloadStartRequest = DownloadStartRequest(url: url.absoluteString, + userAgent: nil, + contentDisposition: nil, + mimeType: mimeType, + contentLength: navigationResponse.response.expectedContentLength, + suggestedFilename: navigationResponse.response.suggestedFilename, + textEncodingName: navigationResponse.response.textEncodingName) + onDownloadStartRequest(request: downloadStartRequest) if useOnNavigationResponse == nil || !useOnNavigationResponse! { decisionHandler(.cancel) } @@ -2363,9 +2370,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi channel?.invokeMethod("onOverScrolled", arguments: arguments) } - public func onDownloadStart(url: String) { - let arguments: [String: Any] = ["url": url] - channel?.invokeMethod("onDownloadStart", arguments: arguments) + public func onDownloadStartRequest(request: DownloadStartRequest) { + channel?.invokeMethod("onDownloadStartRequest", arguments: request.toMap()) } public func onLoadResourceCustomScheme(url: String, result: FlutterResult?) { diff --git a/ios/Classes/Types/DownloadStartRequest.swift b/ios/Classes/Types/DownloadStartRequest.swift new file mode 100644 index 00000000..808f9453 --- /dev/null +++ b/ios/Classes/Types/DownloadStartRequest.swift @@ -0,0 +1,42 @@ +// +// DownloadStartRequest.swift +// flutter_inappwebview +// +// Created by Lorenzo Pichilli on 17/04/22. +// + +import Foundation + +public class DownloadStartRequest: NSObject { + var url: String + var userAgent: String? + var contentDisposition: String? + var mimeType: String? + var contentLength: Int64 + var suggestedFilename: String? + var textEncodingName: String? + + public init(url: String, userAgent: String?, contentDisposition: String?, + mimeType: String?, contentLength: Int64, + suggestedFilename: String?, textEncodingName: String?) { + self.url = url + self.userAgent = userAgent + self.contentDisposition = contentDisposition + self.mimeType = mimeType + self.contentLength = contentLength + self.suggestedFilename = suggestedFilename + self.textEncodingName = textEncodingName + } + + public func toMap () -> [String:Any?] { + return [ + "url": url, + "userAgent": userAgent, + "contentDisposition": contentDisposition, + "mimeType": mimeType, + "contentLength": contentLength, + "suggestedFilename": suggestedFilename, + "textEncodingName": textEncodingName + ] + } +} diff --git a/lib/src/in_app_browser/in_app_browser.dart b/lib/src/in_app_browser/in_app_browser.dart index 8195243d..74f45c1b 100755 --- a/lib/src/in_app_browser/in_app_browser.dart +++ b/lib/src/in_app_browser/in_app_browser.dart @@ -377,16 +377,21 @@ class InAppBrowser { ///**Official iOS API**: https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll void onScrollChanged(int x, int y) {} - ///Event fired when [InAppBrowser] recognizes and starts a downloadable file. + ///Use [onDownloadStartRequest] instead + @Deprecated('Use `onDownloadStartRequest` instead') + void onDownloadStart(Uri url) {} + + ///Event fired when [WebView] recognizes a downloadable file. + ///To download the file, you can use the [flutter_downloader](https://pub.dev/packages/flutter_downloader) plugin. /// - ///[url] represents the url of the file. + ///[downloadStartRequest] represents the request of the file to download. /// ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnDownloadStart] option to `true`. /// ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener) /// ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview - void onDownloadStart(Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength) {} + void onDownloadStartRequest(DownloadStartRequest downloadStartRequest) {} ///Event fired when the [InAppBrowser] webview finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a [CustomSchemeResponse] to load a specific resource encoded to `base64`. /// diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index c9b16d67..7507cb3a 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -64,7 +64,8 @@ class HeadlessInAppWebView implements WebView { this.shouldOverrideUrlLoading, this.onLoadResource, this.onScrollChanged, - this.onDownloadStart, + @Deprecated('Use `onDownloadStartRequest` instead') this.onDownloadStart, + this.onDownloadStartRequest, this.onLoadResourceCustomScheme, this.onCreateWindow, this.onCloseWindow, @@ -301,14 +302,15 @@ class HeadlessInAppWebView implements WebView { @override void Function(InAppWebViewController controller)? onWindowBlur; + ///Use [onDownloadStartRequest] instead + @Deprecated('Use `onDownloadStartRequest` instead') @override - void Function( - InAppWebViewController controller, - Uri url, - String userAgent, - String contentDisposition, - String mimeType, - int contentLength)? onDownloadStart; + final void Function(InAppWebViewController controller, Uri url)? + onDownloadStart; + + @override + final void Function(InAppWebViewController controller, DownloadStartRequest downloadStartRequest)? + onDownloadStartRequest; @override void Function(InAppWebViewController controller, int activeMatchOrdinal, diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index 5c5f5552..c136fa22 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -53,7 +53,8 @@ class InAppWebView extends StatefulWidget implements WebView { this.shouldOverrideUrlLoading, this.onLoadResource, this.onScrollChanged, - this.onDownloadStart, + @Deprecated('Use `onDownloadStartRequest` instead') this.onDownloadStart, + this.onDownloadStartRequest, this.onLoadResourceCustomScheme, this.onCreateWindow, this.onCloseWindow, @@ -211,10 +212,16 @@ class InAppWebView extends StatefulWidget implements WebView { InAppWebViewController controller, Uri url, bool precomposed)? androidOnReceivedTouchIconUrl; + ///Use [onDownloadStartRequest] instead + @Deprecated('Use `onDownloadStartRequest` instead') @override - final void Function(InAppWebViewController controller, Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength)? + final void Function(InAppWebViewController controller, Uri url)? onDownloadStart; + @override + final void Function(InAppWebViewController controller, DownloadStartRequest downloadStartRequest)? + onDownloadStartRequest; + @override final void Function(InAppWebViewController controller, int activeMatchOrdinal, int numberOfMatches, bool isDoneCounting)? onFindResultReceived; 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 a1534940..998e64d6 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -201,20 +201,26 @@ class InAppWebViewController { _inAppBrowser!.onScrollChanged(x, y); } break; - case "onDownloadStart": - if ((_webview != null && _webview!.onDownloadStart != null) || + case "onDownloadStartRequest": + if ((_webview != null && + // ignore: deprecated_member_use_from_same_package + (_webview!.onDownloadStart != null || _webview!.onDownloadStartRequest != null)) || _inAppBrowser != null) { - String url = call.arguments["url"]; - String userAgent = call.arguments["userAgent"]; - String contentDisposition = call.arguments["contentDisposition"]; - String mimeType = call.arguments["mimetype"]; - int contentLength = call.arguments["contentLength"] as int; - Uri uri = Uri.parse(url); + Map arguments = call.arguments.cast(); + DownloadStartRequest downloadStartRequest = DownloadStartRequest.fromMap(arguments)!; - if (_webview != null && _webview!.onDownloadStart != null) - _webview!.onDownloadStart!(this, uri, userAgent, contentDisposition, mimeType, contentLength); - else - _inAppBrowser!.onDownloadStart(uri, userAgent, contentDisposition, mimeType, contentLength); + if (_webview != null) { + if (_webview!.onDownloadStartRequest != null) + _webview!.onDownloadStartRequest!(this, downloadStartRequest); + else { + // ignore: deprecated_member_use_from_same_package + _webview!.onDownloadStart!(this, downloadStartRequest.url); + } + } else { + // ignore: deprecated_member_use_from_same_package + _inAppBrowser!.onDownloadStart(downloadStartRequest.url); + _inAppBrowser!.onDownloadStartRequest(downloadStartRequest); + } } break; case "onLoadResourceCustomScheme": @@ -380,6 +386,7 @@ class InAppWebViewController { } else { // ignore: deprecated_member_use_from_same_package _inAppBrowser!.androidOnScaleChanged(oldScale, newScale); + _inAppBrowser!.onZoomScaleChanged(oldScale, newScale); } } break; diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart index 496000d0..19a2f2ab 100644 --- a/lib/src/in_app_webview/webview.dart +++ b/lib/src/in_app_webview/webview.dart @@ -112,18 +112,23 @@ abstract class WebView { final void Function(InAppWebViewController controller, int x, int y)? onScrollChanged; + ///Use [onDownloadStartRequest] instead + @Deprecated('Use `onDownloadStartRequest` instead') + final void Function(InAppWebViewController controller, Uri url)? + onDownloadStart; + ///Event fired when [WebView] recognizes a downloadable file. ///To download the file, you can use the [flutter_downloader](https://pub.dev/packages/flutter_downloader) plugin. /// - ///[url] represents the url of the file. + ///[downloadStartRequest] represents the request of the file to download. /// ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewOptions.useOnDownloadStart] option to `true`. /// ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#setDownloadListener(android.webkit.DownloadListener) /// ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview - final void Function(InAppWebViewController controller, Uri url, String userAgent, String contentDisposition, String mimeType, int contentLength)? - onDownloadStart; + final void Function(InAppWebViewController controller, DownloadStartRequest downloadStartRequest)? + onDownloadStartRequest; ///Event fired when the [WebView] finds the `custom-scheme` while loading a resource. Here you can handle the url request and return a [CustomSchemeResponse] to load a specific resource encoded to `base64`. /// @@ -696,7 +701,8 @@ abstract class WebView { this.shouldOverrideUrlLoading, this.onLoadResource, this.onScrollChanged, - this.onDownloadStart, + @Deprecated('Use `onDownloadStartRequest` instead') this.onDownloadStart, + this.onDownloadStartRequest, this.onLoadResourceCustomScheme, this.onCreateWindow, this.onCloseWindow, diff --git a/lib/src/types.dart b/lib/src/types.dart index 2cb3bfe8..0c66dcd1 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -6891,4 +6891,73 @@ class WebViewImplementation { @override int get hashCode => _value.hashCode; +} + +///Class representing a download request of the WebView used by the event [WebView.onDownloadStartRequest]. +class DownloadStartRequest { + ///The full url to the content that should be downloaded. + Uri url; + + ///the user agent to be used for the download. + String? userAgent; + + ///Content-disposition http header, if present. + String? contentDisposition; + + ///The mimetype of the content reported by the server. + String? mimeType; + + ///The file size reported by the server. + int contentLength; + + ///A suggested filename to use if saving the resource to disk. + String? suggestedFilename; + + ///The name of the text encoding of the receiver, or `null` if no text encoding was specified. + String? textEncodingName; + + DownloadStartRequest( + {required this.url, + this.userAgent, + this.contentDisposition, + this.mimeType, + required this.contentLength, + this.suggestedFilename, + this.textEncodingName}); + + static DownloadStartRequest? fromMap(Map? map) { + if (map == null) { + return null; + } + + return DownloadStartRequest( + url: Uri.parse(map["url"]), + userAgent: map["userAgent"], + contentDisposition: map["contentDisposition"], + mimeType: map["mimeType"], + contentLength: map["contentLength"], + suggestedFilename: map["suggestedFilename"], + textEncodingName: map["textEncodingName"]); + } + + Map toMap() { + return { + "url": url.toString(), + "userAgent": userAgent, + "contentDisposition": contentDisposition, + "mimeType": mimeType, + "contentLength": contentLength, + "suggestedFilename": suggestedFilename, + "textEncodingName": textEncodingName + }; + } + + Map toJson() { + return this.toMap(); + } + + @override + String toString() { + return toMap().toString(); + } } \ No newline at end of file From 25e9ea6e19d8e6f81beaeaed349f01f30af9355f Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 16:35:43 +0200 Subject: [PATCH 35/40] updated version and changelog --- CHANGELOG.md | 3 ++- example/lib/in_app_webiew_example.screen.dart | 8 ++------ pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3831a7d2..a269632a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 5.3.3 +## 5.4.0 - `getOriginalUrl` method is cross-platform now - Updated Android `compileSdkVersion` to 31 @@ -29,6 +29,7 @@ - Merged "Add application/wasm MimeType with InAppLocalhostServer" [#1054](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1054) (thanks to [foxstream528](https://github.com/foxstream528)) - Merged "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) - Merged "updated com.android.tools.build:gradle" [#1066](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1066) (thanks to [chownation](https://github.com/chownation)) +- Merged "WIP - expose content-disposition and content-length from android" [#1088](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1088) (thanks to [ashank96](https://github.com/ashank96)) ## 5.3.2 diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index 569153d2..90f77064 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -24,8 +24,7 @@ class _InAppWebViewExampleScreenState extends State { InAppWebViewGroupOptions options = InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, - mediaPlaybackRequiresUserGesture: false, - useOnDownloadStart: true + mediaPlaybackRequiresUserGesture: false ), android: AndroidInAppWebViewOptions( useHybridComposition: true, @@ -124,7 +123,7 @@ class _InAppWebViewExampleScreenState extends State { key: webViewKey, // contextMenu: contextMenu, initialUrlRequest: - URLRequest(url: Uri.parse("https://testfiledownload.com/")), + URLRequest(url: Uri.parse("https://github.com/flutter")), // initialFile: "assets/index.html", initialUserScripts: UnmodifiableListView([]), initialOptions: options, @@ -132,9 +131,6 @@ class _InAppWebViewExampleScreenState extends State { onWebViewCreated: (controller) { webViewController = controller; }, - onDownloadStartRequest: (controller, request) { - print(request); - }, onLoadStart: (controller, url) { setState(() { this.url = url.toString(); diff --git a/pubspec.yaml b/pubspec.yaml index 45162ede..830ed983 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 5.3.3 +version: 5.4.0 homepage: https://github.com/pichillilorenzo/flutter_inappwebview environment: From 65e06984cb00f3dd3aa4e56a2cdc72ffea1e96ef Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 16:43:16 +0200 Subject: [PATCH 36/40] fix #1092 --- CHANGELOG.md | 1 + example/.flutter-plugins-dependencies | 2 +- ios/Classes/InAppWebView/InAppWebView.swift | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a269632a..301dccf5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - Merged "Fixed the unexpected behavior of InAppWebView and HeadlessInAppWebView when initialUrlRequest was set as null." [#1064](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1064) (thanks to [RodXander](https://github.com/RodXander)) - Merged "updated com.android.tools.build:gradle" [#1066](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1066) (thanks to [chownation](https://github.com/chownation)) - Merged "WIP - expose content-disposition and content-length from android" [#1088](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1088) (thanks to [ashank96](https://github.com/ashank96)) +- Merged "Fix ios persistance when using sharedCookie" [#1093](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1093) (thanks to [EA-YOUHOU](https://github.com/EA-YOUHOU)) ## 5.3.2 diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index a452f15c..a5775f64 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 16:15:55.135230","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 16:40:00.837943","version":"2.10.4"} \ No newline at end of file diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index f2360fd3..4c59f433 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -531,8 +531,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi // Set Cookies in iOS 11 and above, initialize websiteDataStore before setting cookies // See also https://forums.developer.apple.com/thread/97194 // check if websiteDataStore has not been initialized before - if(!options.incognito && options.cacheEnabled) { - configuration.websiteDataStore = WKWebsiteDataStore.default() + if(!options.incognito && !options.cacheEnabled) { + configuration.websiteDataStore = WKWebsiteDataStore.nonPersistent() } for cookie in HTTPCookieStorage.shared.cookies ?? [] { configuration.websiteDataStore.httpCookieStore.setCookie(cookie, completionHandler: nil) From df0f0090349fa05112162d3c344215e33ba161e2 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 16:44:11 +0200 Subject: [PATCH 37/40] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 301dccf5..a21dde1d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Fixed "In android, when click a href with img returns img src on onCreateWindow" [#951](https://github.com/pichillilorenzo/flutter_inappwebview/issues/951) - Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) - Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) +- Fixed "Local storage & cookie didn't persist when sharedCookie and cache both enabled" [#1092](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1092) - Merged "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) - Merged "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) - Merged "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) From fab9ae4c8bb71b12c0c8a51874407ba75cc176c9 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 17:13:15 +0200 Subject: [PATCH 38/40] updated pubspec.yaml --- CHANGELOG.md | 1 + example/.flutter-plugins-dependencies | 2 +- pubspec.yaml | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a21dde1d..1e71df9f 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - `getOriginalUrl` method is cross-platform now - Updated Android `compileSdkVersion` to 31 +- Updated Flutter environment: sdk to `>=2.14.0 <3.0.0` and flutter version to `>=2.5.0` - Added `singleInstance` option for Android `ChromeSafariBrowser` implementation - Added `onDownloadStartRequest` event and deprecated old `onDownloadStart` event - Fixed missing `onZoomScaleChanged` call for `InAppBrowser` class diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index a5775f64..406d4d61 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 16:40:00.837943","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 17:10:57.323200","version":"2.10.4"} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 830ed983..fdb7b010 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,8 @@ version: 5.4.0 homepage: https://github.com/pichillilorenzo/flutter_inappwebview environment: - sdk: ">=2.12.0-0 <3.0.0" - flutter: ">=1.22.2" + sdk: ">=2.14.0 <3.0.0" + flutter: ">=2.5.0" dependencies: flutter: From 23edf4054f85019cc11454d0b17a5d07be183d06 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 17:17:11 +0200 Subject: [PATCH 39/40] Update InAppWebViewMethodHandler.swift --- ios/Classes/InAppWebViewMethodHandler.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/InAppWebViewMethodHandler.swift b/ios/Classes/InAppWebViewMethodHandler.swift index 33d80f29..ca13aa8c 100644 --- a/ios/Classes/InAppWebViewMethodHandler.swift +++ b/ios/Classes/InAppWebViewMethodHandler.swift @@ -290,7 +290,7 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate { break case "zoomBy": let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue - let animated = arguments!["iosAnimated"] as! Bool + let animated = arguments!["animated"] as! Bool webView?.zoomBy(zoomFactor: zoomFactor, animated: animated) result(true) break From 4edd47ef9226c942811fcf0fa003a4f3d1f5f4fc Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 17 Apr 2022 17:22:20 +0200 Subject: [PATCH 40/40] updated changelog --- CHANGELOG.md | 2 ++ example/.flutter-plugins-dependencies | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e71df9f..e7935ed8 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Fixed "crash at com.pichillilorenzo.flutter_inappwebview.in_app_webview.InAppWebView$11.run (InAppWebView.java:1307)" [#1040](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1040) - Fixed "Unexpected behavior when using a null initialUrlRequest" [#1063](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1063) - Fixed "Local storage & cookie didn't persist when sharedCookie and cache both enabled" [#1092](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1092) +- Fixed "ios zoomBy crash: Foundation/NSNumber.swift:467: Fatal error: Unable to bridge NSNumber to Float" [#873](https://github.com/pichillilorenzo/flutter_inappwebview/issues/873) - Merged "Update Options.swift" [#889](https://github.com/pichillilorenzo/flutter_inappwebview/pull/889) (thanks to [cloudygeek](https://github.com/cloudygeek)) - Merged "fix: Applicatio nNameForUserAgent is not working in iOS" [#1095](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1095) (thanks to [sunalwaysknows](https://github.com/sunalwaysknows)) - Merged "Make sure we open a new instance of a custom chrome chrome tab" [#812](https://github.com/pichillilorenzo/flutter_inappwebview/pull/812) (thanks to [savy-91](https://github.com/savy-91)) @@ -33,6 +34,7 @@ - Merged "updated com.android.tools.build:gradle" [#1066](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1066) (thanks to [chownation](https://github.com/chownation)) - Merged "WIP - expose content-disposition and content-length from android" [#1088](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1088) (thanks to [ashank96](https://github.com/ashank96)) - Merged "Fix ios persistance when using sharedCookie" [#1093](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1093) (thanks to [EA-YOUHOU](https://github.com/EA-YOUHOU)) +- Merged "Fixes zoomBy with floats (iOS)" [#1109](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1109) (thanks to [Manuito83](https://github.com/Manuito83)) ## 5.3.2 diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 406d4d61..6dcd5d95 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 17:10:57.323200","version":"2.10.4"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"flutter_downloader","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":[]},{"name":"integration_test","path":"/Users/lorenzopichilli/fvm/versions/2.10.4/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":[]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2022-04-17 17:18:13.163601","version":"2.10.4"} \ No newline at end of file