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 a6d3282e..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,10 +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); - 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 ac02f42f..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) { - 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 727582ae..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) {} + 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 47ab3f35..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,8 +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)? 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 4c3f7f3e..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)? 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 e6bb9048..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,15 +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"]; - Uri uri = Uri.parse(url); - if (_webview != null && _webview!.onDownloadStart != null) - _webview!.onDownloadStart!(this, uri); - else - _inAppBrowser!.onDownloadStart(uri); + Map arguments = call.arguments.cast(); + DownloadStartRequest downloadStartRequest = DownloadStartRequest.fromMap(arguments)!; + + 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": @@ -375,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 3a1fa650..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)? - 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