[webview_flutter] Add loadRequest functionality to app facing package. (#4573)
* Add android implementations for loadRequest.
* Update changelog and pubspec.
* Fix comment.
* Fix comment.
* Add tests
* Add back removed license headers
* Fix analysis error
* Add support for loadRequest to app facing package
* Add test
* Comment pending dependency in pubspec
* Remove workaround for supporting custom headers when making post requests on Android.
* Document android workaround in dart doc
* Enforce uri scheme
* Update loadRequest dartdoc
* Document android workaround in readme
* Processed PR feedback.
* Updated dependency, version and changelog.
diff --git a/packages/webview_flutter/webview_flutter/CHANGELOG.md b/packages/webview_flutter/webview_flutter/CHANGELOG.md
index 1f8a33d..a9e133d 100644
--- a/packages/webview_flutter/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.6.0
+
+* Adds support for the `loadRequest` method.
+
## 2.5.0
* Adds an option to set the background color of the webview.
diff --git a/packages/webview_flutter/webview_flutter/README.md b/packages/webview_flutter/webview_flutter/README.md
index de475ad..c3982ea 100644
--- a/packages/webview_flutter/webview_flutter/README.md
+++ b/packages/webview_flutter/webview_flutter/README.md
@@ -92,3 +92,8 @@
To use Material Components when the user interacts with input elements in the WebView,
follow the steps described in the [Enabling Material Components instructions](https://flutter.dev/docs/deployment/android#enabling-material-components).
+
+### Setting custom headers on POST requests
+
+Currently, setting custom headers when making a post request with the WebViewController's `loadRequest` method is not supported on Android.
+If you require this functionality, a workaround is to make the request manually, and then load the response data using `loadHTMLString` instead.
\ No newline at end of file
diff --git a/packages/webview_flutter/webview_flutter/example/lib/main.dart b/packages/webview_flutter/webview_flutter/example/lib/main.dart
index c870ae9..02e6ef8 100644
--- a/packages/webview_flutter/webview_flutter/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter/example/lib/main.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
@@ -176,6 +177,7 @@
listCache,
clearCache,
navigationDelegate,
+ doPostRequest,
loadLocalFile,
loadHtmlString,
transparentBackground,
@@ -218,6 +220,9 @@
case MenuOptions.navigationDelegate:
_onNavigationDelegateExample(controller.data!, context);
break;
+ case MenuOptions.doPostRequest:
+ _onDoPostRequest(controller.data!, context);
+ break;
case MenuOptions.loadLocalFile:
_onLoadLocalFileExample(controller.data!, context);
break;
@@ -260,6 +265,10 @@
child: Text('Navigation Delegate example'),
),
const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.doPostRequest,
+ child: Text('Post Request'),
+ ),
+ const PopupMenuItem<MenuOptions>(
value: MenuOptions.loadHtmlString,
child: Text('Load HTML string'),
),
@@ -348,6 +357,17 @@
await controller.loadUrl('data:text/html;base64,$contentBase64');
}
+ Future<void> _onDoPostRequest(
+ WebViewController controller, BuildContext context) async {
+ final WebViewRequest request = WebViewRequest(
+ uri: Uri.parse('https://httpbin.org/post'),
+ method: WebViewRequestMethod.post,
+ headers: <String, String>{'foo': 'bar', 'Content-Type': 'text/plain'},
+ body: Uint8List.fromList('Test Body'.codeUnits),
+ );
+ await controller.loadRequest(request);
+ }
+
Future<void> _onLoadLocalFileExample(
WebViewController controller, BuildContext context) async {
final String pathToIndex = await _prepareLocalFile();
diff --git a/packages/webview_flutter/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/webview_flutter/lib/platform_interface.dart
index aa7b3a0..ab1cbb1 100644
--- a/packages/webview_flutter/webview_flutter/lib/platform_interface.dart
+++ b/packages/webview_flutter/webview_flutter/lib/platform_interface.dart
@@ -21,4 +21,6 @@
WebSetting,
WebSettings,
WebResourceError,
- WebResourceErrorType;
+ WebResourceErrorType,
+ WebViewRequest,
+ WebViewRequestMethod;
diff --git a/packages/webview_flutter/webview_flutter/lib/src/webview.dart b/packages/webview_flutter/webview_flutter/lib/src/webview.dart
index b2cc690..d76f7b3 100644
--- a/packages/webview_flutter/webview_flutter/lib/src/webview.dart
+++ b/packages/webview_flutter/webview_flutter/lib/src/webview.dart
@@ -550,6 +550,26 @@
return _webViewPlatformController.loadUrl(url, headers);
}
+ /// Makes a specific HTTP request and loads the response in the webview.
+ ///
+ /// [WebViewRequest.method] must be one of the supported HTTP methods
+ /// in [WebViewRequestMethod].
+ ///
+ /// If [WebViewRequest.headers] is not empty, its key-value pairs will be
+ /// added as the headers for the request.
+ ///
+ /// If [WebViewRequest.body] is not null, it will be added as the body
+ /// for the request.
+ ///
+ /// Throws an ArgumentError if [WebViewRequest.uri] has empty scheme.
+ ///
+ /// Android only:
+ /// When making a POST request, headers are ignored. As a workaround, make
+ /// the request manually and load the response data using [loadHTMLString].
+ Future<void> loadRequest(WebViewRequest request) async {
+ return _webViewPlatformController.loadRequest(request);
+ }
+
/// Accessor to the current URL that the WebView is displaying.
///
/// If [WebView.initialUrl] was never specified, returns `null`.
diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml
index 6c00f65..1bc6bab 100644
--- a/packages/webview_flutter/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter/pubspec.yaml
@@ -2,7 +2,7 @@
description: A Flutter plugin that provides a WebView widget on Android and iOS.
repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.5.0
+version: 2.6.0
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -19,8 +19,8 @@
dependencies:
flutter:
sdk: flutter
- webview_flutter_android: ^2.5.0
- webview_flutter_platform_interface: ^1.7.0
+ webview_flutter_android: ^2.7.0
+ webview_flutter_platform_interface: ^1.8.0
webview_flutter_wkwebview: ^2.5.0
dev_dependencies:
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
index da860f0..d422402 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:typed_data';
+
import 'package:flutter/src/foundation/basic_types.dart';
import 'package:flutter/src/gestures/recognizer.dart';
import 'package:flutter/widgets.dart';
@@ -246,6 +248,29 @@
));
});
+ testWidgets('loadRequest', (WidgetTester tester) async {
+ WebViewController? controller;
+ await tester.pumpWidget(
+ WebView(
+ onWebViewCreated: (WebViewController webViewController) {
+ controller = webViewController;
+ },
+ ),
+ );
+ expect(controller, isNotNull);
+
+ final WebViewRequest req = WebViewRequest(
+ uri: Uri.parse('https://flutter.dev'),
+ method: WebViewRequestMethod.post,
+ headers: <String, String>{'foo': 'bar'},
+ body: Uint8List.fromList('Test Body'.codeUnits),
+ );
+
+ await controller!.loadRequest(req);
+
+ verify(mockWebViewPlatformController.loadRequest(req));
+ });
+
testWidgets('Clear Cache', (WidgetTester tester) async {
WebViewController? controller;
await tester.pumpWidget(
diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
index 8857f60..fe30601 100644
--- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.mocks.dart
@@ -1,22 +1,26 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
// Mocks generated by Mockito 5.0.16 from annotations
// in webview_flutter/test/webview_flutter_test.dart.
// Do not manually edit this file.
import 'dart:async' as _i9;
-import 'package:flutter/foundation.dart' as _i7;
+import 'package:flutter/foundation.dart' as _i3;
import 'package:flutter/gestures.dart' as _i8;
import 'package:flutter/widgets.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:webview_flutter_platform_interface/src/platform_interface/javascript_channel_registry.dart'
- as _i6;
+ as _i7;
import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform.dart'
- as _i3;
+ as _i4;
import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform_callbacks_handler.dart'
- as _i5;
+ as _i6;
import 'package:webview_flutter_platform_interface/src/platform_interface/webview_platform_controller.dart'
as _i10;
-import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i4;
+import 'package:webview_flutter_platform_interface/src/types/types.dart' as _i5;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
@@ -29,14 +33,14 @@
class _FakeWidget_0 extends _i1.Fake implements _i2.Widget {
@override
- String toString({_i2.DiagnosticLevel? minLevel = _i2.DiagnosticLevel.info}) =>
+ String toString({_i3.DiagnosticLevel? minLevel = _i3.DiagnosticLevel.info}) =>
super.toString();
}
/// A class which mocks [WebViewPlatform].
///
/// See the documentation for Mockito's code generation for more information.
-class MockWebViewPlatform extends _i1.Mock implements _i3.WebViewPlatform {
+class MockWebViewPlatform extends _i1.Mock implements _i4.WebViewPlatform {
MockWebViewPlatform() {
_i1.throwOnMissingStub(this);
}
@@ -44,11 +48,11 @@
@override
_i2.Widget build(
{_i2.BuildContext? context,
- _i4.CreationParams? creationParams,
- _i5.WebViewPlatformCallbacksHandler? webViewPlatformCallbacksHandler,
- _i6.JavascriptChannelRegistry? javascriptChannelRegistry,
- _i3.WebViewPlatformCreatedCallback? onWebViewPlatformCreated,
- Set<_i7.Factory<_i8.OneSequenceGestureRecognizer>>?
+ _i5.CreationParams? creationParams,
+ _i6.WebViewPlatformCallbacksHandler? webViewPlatformCallbacksHandler,
+ _i7.JavascriptChannelRegistry? javascriptChannelRegistry,
+ _i4.WebViewPlatformCreatedCallback? onWebViewPlatformCreated,
+ Set<_i3.Factory<_i8.OneSequenceGestureRecognizer>>?
gestureRecognizers}) =>
(super.noSuchMethod(
Invocation.method(#build, [], {
@@ -83,6 +87,11 @@
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
+ _i9.Future<void> loadFlutterAsset(String? key) =>
+ (super.noSuchMethod(Invocation.method(#loadFlutterAsset, [key]),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
+ @override
_i9.Future<void> loadHtmlString(String? html, {String? baseUrl}) =>
(super.noSuchMethod(
Invocation.method(#loadHtmlString, [html], {#baseUrl: baseUrl}),
@@ -94,12 +103,12 @@
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
- _i9.Future<void> loadRequest(_i4.WebViewRequest? request) =>
+ _i9.Future<void> loadRequest(_i5.WebViewRequest? request) =>
(super.noSuchMethod(Invocation.method(#loadRequest, [request]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);
@override
- _i9.Future<void> updateSettings(_i4.WebSettings? setting) =>
+ _i9.Future<void> updateSettings(_i5.WebSettings? setting) =>
(super.noSuchMethod(Invocation.method(#updateSettings, [setting]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as _i9.Future<void>);