[webview_flutter] Add platform interface method `loadRequest`. (#4450)

diff --git a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md
index 04641f9..0579121 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 @@
+## 1.3.0
+
+* Added `loadRequest` method to platform interface.
+
 ## 1.2.0
 
 * Added `runJavascript` and `runJavascriptReturningResult` interface methods to supersede `evaluateJavascript`.
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart
index 9610038..a88479e 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart
@@ -92,6 +92,14 @@
   }
 
   @override
+  Future<void> loadRequest(WebViewRequest request) async {
+    assert(request != null);
+    return _channel.invokeMethod<void>('loadRequest', <String, dynamic>{
+      'request': request.toJson(),
+    });
+  }
+
+  @override
   Future<String?> currentUrl() => _channel.invokeMethod<String>('currentUrl');
 
   @override
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform_controller.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform_controller.dart
index b42da43..806f950 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform_controller.dart
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform_controller.dart
@@ -39,6 +39,25 @@
         "WebView loadUrl is not implemented on the current platform");
   }
 
+  /// Makes a specific HTTP request ands 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.
+  Future<void> loadRequest(
+    WebViewRequest request,
+  ) {
+    throw UnimplementedError(
+        "WebView loadRequest is not implemented on the current platform");
+  }
+
   /// Updates the webview settings.
   ///
   /// Any non null field in `settings` will be set as the new setting value.
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart
index b1a9b9b..8ce8341 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart
@@ -10,3 +10,4 @@
 export 'web_resource_error.dart';
 export 'web_resource_error_type.dart';
 export 'web_settings.dart';
+export 'webview_request.dart';
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_request.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_request.dart
new file mode 100644
index 0000000..5e520f1
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_request.dart
@@ -0,0 +1,58 @@
+// 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.
+
+import 'dart:typed_data';
+
+/// Defines the supported HTTP methods for loading a page in [WebView].
+enum WebViewRequestMethod {
+  /// HTTP GET method.
+  get,
+
+  /// HTTP POST method.
+  post,
+}
+
+/// Extension methods on the [WebViewRequestMethod] enum.
+extension WebViewRequestMethodExtensions on WebViewRequestMethod {
+  /// Converts [WebViewRequestMethod] to [String] format.
+  String serialize() {
+    switch (this) {
+      case WebViewRequestMethod.get:
+        return 'get';
+      case WebViewRequestMethod.post:
+        return 'post';
+    }
+  }
+}
+
+/// Defines the parameters that can be used to load a page in the [WebView].
+class WebViewRequest {
+  /// Creates the [WebViewRequest].
+  WebViewRequest({
+    required this.uri,
+    required this.method,
+    this.headers = const {},
+    this.body,
+  });
+
+  /// URI for the request.
+  final Uri uri;
+
+  /// HTTP method used to make the request.
+  final WebViewRequestMethod method;
+
+  /// Headers for the request.
+  final Map<String, String> headers;
+
+  /// HTTP body for the request.
+  final Uint8List? body;
+
+  /// Serializes the [WebViewRequest] to JSON.
+  Map<String, dynamic> toJson() => {
+        'uri': this.uri.toString(),
+        'method': this.method.serialize(),
+        'headers': this.headers,
+        'body': this.body,
+      };
+}
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml
index 994c3dc..508af0e 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 @@
 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: 1.2.0
+version: 1.3.0
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart
index 85f184f..b85b7b3 100644
--- a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_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/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/mockito.dart';
@@ -101,6 +103,56 @@
       );
     });
 
+    test('loadRequest', () async {
+      await webViewPlatform.loadRequest(WebViewRequest(
+        uri: Uri.parse('https://test.url'),
+        method: WebViewRequestMethod.get,
+      ));
+
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall(
+            'loadRequest',
+            arguments: <String, dynamic>{
+              'request': {
+                'uri': 'https://test.url',
+                'method': 'get',
+                'headers': {},
+                'body': null,
+              }
+            },
+          ),
+        ],
+      );
+    });
+
+    test('loadRequest with optional parameters', () async {
+      await webViewPlatform.loadRequest(WebViewRequest(
+        uri: Uri.parse('https://test.url'),
+        method: WebViewRequestMethod.get,
+        headers: {'foo': 'bar'},
+        body: Uint8List.fromList('hello world'.codeUnits),
+      ));
+
+      expect(
+        log,
+        <Matcher>[
+          isMethodCall(
+            'loadRequest',
+            arguments: <String, dynamic>{
+              'request': {
+                'uri': 'https://test.url',
+                'method': 'get',
+                'headers': {'foo': 'bar'},
+                'body': 'hello world'.codeUnits,
+              }
+            },
+          ),
+        ],
+      );
+    });
+
     test('currentUrl', () async {
       final String? currentUrl = await webViewPlatform.currentUrl();
 
diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_request_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_request_test.dart
new file mode 100644
index 0000000..5d2b568
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_request_test.dart
@@ -0,0 +1,39 @@
+// 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.
+
+import 'dart:typed_data';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:webview_flutter_platform_interface/src/types/types.dart';
+
+void main() {
+  test('WebViewRequestMethod should serialize correctly', () {
+    expect(WebViewRequestMethod.get.serialize(), 'get');
+    expect(WebViewRequestMethod.post.serialize(), 'post');
+  });
+
+  test('WebViewRequest should serialize correctly', () {
+    WebViewRequest request;
+    Map<String, dynamic> serializedRequest;
+    // Test serialization without headers or a body
+    request = WebViewRequest(
+      uri: Uri.parse('https://flutter.dev'),
+      method: WebViewRequestMethod.get,
+    );
+    serializedRequest = request.toJson();
+    expect(serializedRequest['uri'], 'https://flutter.dev');
+    expect(serializedRequest['method'], 'get');
+    expect(serializedRequest['headers'], {});
+    expect(serializedRequest['body'], null);
+    // Test serialization of headers and body
+    request = WebViewRequest(
+      uri: Uri.parse('https://flutter.dev'),
+      method: WebViewRequestMethod.get,
+      headers: {'foo': 'bar'},
+      body: Uint8List.fromList('Example Body'.codeUnits),
+    );
+    serializedRequest = request.toJson();
+    expect(serializedRequest['headers'], {'foo': 'bar'});
+    expect(serializedRequest['body'], 'Example Body'.codeUnits);
+  });
+}