From 0b70ecc462e7d47830bf9e5fe9d5043f3118be4f Mon Sep 17 00:00:00 2001 From: agu Date: Tue, 14 Apr 2026 17:02:12 +0800 Subject: [PATCH 1/2] [webview_flutter] Add headers and isDownloadRequest to NavigationRequest --- .../webview_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../lib/src/types/navigation_request.dart | 9 ++++++++- .../webview_flutter_platform_interface/pubspec.yaml | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md index 72e84d87c3d1..8e9bc89e89ad 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.15.2 + +* Adds `headers` and `isDownloadRequest` to `NavigationRequest`,so we can easily tell if it was made to download an attachment from `onDownloadStart`. + ## 2.15.1 * Fixes dartdoc comments that accidentally used HTML. diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/navigation_request.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/navigation_request.dart index 6e8794f71314..5104a864a4a7 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/navigation_request.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/navigation_request.dart @@ -5,11 +5,18 @@ /// Defines the parameters of the pending navigation callback. class NavigationRequest { /// Creates a [NavigationRequest]. - const NavigationRequest({required this.url, required this.isMainFrame}); + const NavigationRequest({required this.url, required this.isMainFrame, this.headers}); /// The URL of the pending navigation request. final String url; /// Indicates whether the request was made in the web site's main frame or a subframe. final bool isMainFrame; + + /// Headers for the request. + final Map? headers; + + /// Indicates whether the request was made to download an attachment. + bool get isDownloadRequest => + headers?['content-disposition']?.toLowerCase().startsWith('attachment') ?? false; } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml index 6528399fd0e0..00e771975c15 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/webview_flutt issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview_flutter%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.15.1 +version: 2.15.2 environment: sdk: ^3.9.0 From 444fb585072a9fda0dc5d64af3d0f1cfb5d18bb4 Mon Sep 17 00:00:00 2001 From: agu Date: Tue, 14 Apr 2026 17:06:03 +0800 Subject: [PATCH 2/2] [webview_flutter_android] Add headers to NavigationRequest to tell if it isDownloadRequest from onDownloadStart --- .../webview_flutter_android/CHANGELOG.md | 4 +++ .../lib/src/android_webview_controller.dart | 15 +++++++-- .../webview_flutter_android/pubspec.yaml | 2 +- .../android_navigation_delegate_test.dart | 33 +++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index f96b5c98e499..ac25d5f9bea0 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.11.1 + +* Adds `headers` to `NavigationRequest` to tell if it `isDownloadRequest` from `onDownloadStart`. + ## 4.11.0 * Adds support to opt out of Android inset changes. See diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart index f33fba2dc0fa..906d57783028 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart @@ -1680,7 +1680,18 @@ class AndroidNavigationDelegate extends PlatformNavigationDelegate { int contentLength, ) { if (weakThis.target != null) { - weakThis.target?._handleNavigation(url, isForMainFrame: true); + if (!contentDisposition.toLowerCase().startsWith('attachment')) { + contentDisposition = 'attachment; $contentDisposition'.trim(); + } + weakThis.target?._handleNavigation( + url, + isForMainFrame: true, + headers: { + 'content-disposition': contentDisposition, + 'content-type': mimetype, + 'content-length': contentLength.toString(), + }, + ); } }, ); @@ -1744,7 +1755,7 @@ class AndroidNavigationDelegate extends PlatformNavigationDelegate { } final FutureOr returnValue = onNavigationRequest( - NavigationRequest(url: url, isMainFrame: isForMainFrame), + NavigationRequest(url: url, isMainFrame: isForMainFrame, headers: headers), ); if (returnValue is NavigationDecision && diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index da5165f07330..f31f42cfd8db 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 4.11.0 +version: 4.11.1 environment: sdk: ^3.9.0 diff --git a/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart index 4a7d4ef06fa6..45e598b7c740 100644 --- a/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart @@ -579,6 +579,39 @@ void main() { }, ); + test( + 'isDownloadRequest from onDownloadStart should be true', + () { + final androidNavigationDelegate = AndroidNavigationDelegate( + _buildCreationParams(), + ); + + androidNavigationDelegate.setOnLoadRequest((_) { + return Future.value(); + }); + + late final NavigationRequest callbackNavigationRequest; + androidNavigationDelegate.setOnNavigationRequest(( + NavigationRequest navigationRequest, + ) { + callbackNavigationRequest = navigationRequest; + return NavigationDecision.navigate; + }); + + CapturingDownloadListener.lastCreatedListener.onDownloadStart( + MockDownloadListener(), + 'https://www.google.com', + '', + '', + '', + 0, + ); + + expect(callbackNavigationRequest.url, 'https://www.google.com'); + expect(callbackNavigationRequest.isDownloadRequest, true); + }, + ); + test('onUrlChange', () { final androidNavigationDelegate = AndroidNavigationDelegate( _buildCreationParams(),