[webview_flutter] Implement loadRequest in iOS package. (#4480)

diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index 4db6dbf..c1b19fd 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.3.0
+
+* Implemented new `loadRequest` method from platform interface.
+
 ## 2.2.0
 
 * Implemented new `runJavascript` and `runJavascriptReturningResult` methods in platform interface.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
index ba0deb4..2be87fb 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
@@ -193,7 +193,6 @@
 				C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */,
 				5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */,
 			);
-			name = Pods;
 			path = Pods;
 			sourceTree = "<group>";
 		};
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
index 9d127c2..61e43c1 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m
@@ -5,6 +5,7 @@
 @import Flutter;
 @import XCTest;
 @import webview_flutter_wkwebview;
+@import webview_flutter_wkwebview.Test;
 
 // OCMock library doesn't generate a valid modulemap.
 #import <OCMock/OCMock.h>
@@ -301,4 +302,196 @@
   [self waitForExpectationsWithTimeout:30.0 handler:nil];
 }
 
+- (void)testBuildNSURLRequestReturnsNilForNonDictionaryValue {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+
+  // Run
+  NSURLRequest *request = [controller buildNSURLRequest:@{@"request" : @"Non Dictionary Value"}];
+
+  // Verify
+  XCTAssertNil(request);
+}
+
+- (void)testBuildNSURLRequestReturnsNilForMissingURI {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+
+  // Run
+  NSURLRequest *request = [controller buildNSURLRequest:@{@"request" : @{}}];
+
+  // Verify
+  XCTAssertNil(request);
+}
+
+- (void)testBuildNSURLRequestReturnsNilForInvalidURI {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+
+  // Run
+  NSDictionary *requestData = @{@"uri" : @"invalid uri"};
+  NSURLRequest *request = [controller buildNSURLRequest:@{@"request" : requestData}];
+
+  // Verify
+  XCTAssertNil(request);
+}
+
+- (void)testBuildNSURLRequestBuildsNSMutableURLRequestWithOptionalParameters {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+
+  // Run
+  NSDictionary *requestData = @{
+    @"uri" : @"https://flutter.dev",
+    @"method" : @"POST",
+    @"headers" : @{@"Foo" : @"Bar"},
+    @"body" : [FlutterStandardTypedData
+        typedDataWithBytes:[@"Test Data" dataUsingEncoding:NSUTF8StringEncoding]],
+  };
+  NSURLRequest *request = [controller buildNSURLRequest:@{@"request" : requestData}];
+
+  // Verify
+  XCTAssertNotNil(request);
+  XCTAssertEqualObjects(request.URL.absoluteString, @"https://flutter.dev");
+  XCTAssertEqualObjects(request.HTTPMethod, @"POST");
+  XCTAssertEqualObjects(request.allHTTPHeaderFields, @{@"Foo" : @"Bar"});
+  XCTAssertEqualObjects(request.HTTPBody, [@"Test Data" dataUsingEncoding:NSUTF8StringEncoding]);
+}
+
+- (void)testBuildNSURLRequestBuildsNSMutableURLRequestWithoutOptionalParameters {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+
+  // Run
+  NSDictionary *requestData = @{
+    @"uri" : @"https://flutter.dev",
+  };
+  NSURLRequest *request = [controller buildNSURLRequest:@{@"request" : requestData}];
+
+  // Verify
+  XCTAssertNotNil(request);
+  XCTAssertEqualObjects(request.URL.absoluteString, @"https://flutter.dev");
+  XCTAssertEqualObjects(request.HTTPMethod, @"GET");
+  XCTAssertNil(request.allHTTPHeaderFields);
+  XCTAssertNil(request.HTTPBody);
+}
+
+- (void)testOnLoadUrlReturnsErrorResultForInvalidRequest {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+  XCTestExpectation *resultExpectation =
+      [self expectationWithDescription:@"Should return error result when request cannot be built"];
+
+  // Run
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"loadUrl"
+                                                                    arguments:@{}];
+  [controller onLoadUrl:methodCall
+                 result:^(id _Nullable result) {
+                   XCTAssertTrue([result class] == [FlutterError class]);
+                   [resultExpectation fulfill];
+                 }];
+
+  // Verify
+  [self waitForExpectationsWithTimeout:30.0 handler:nil];
+}
+
+- (void)testOnLoadUrlLoadsRequestWithSuccessResult {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+  XCTestExpectation *resultExpectation = [self expectationWithDescription:@"Should return nil"];
+  FLTWKWebView *mockView = OCMClassMock(FLTWKWebView.class);
+  controller.webView = mockView;
+
+  // Run
+  FlutterMethodCall *methodCall =
+      [FlutterMethodCall methodCallWithMethodName:@"loadUrl"
+                                        arguments:@{@"url" : @"https://flutter.dev/"}];
+  [controller onLoadUrl:methodCall
+                 result:^(id _Nullable result) {
+                   XCTAssertNil(result);
+                   [resultExpectation fulfill];
+                 }];
+
+  // Verify
+  OCMVerify([mockView loadRequest:[OCMArg any]]);
+  [self waitForExpectationsWithTimeout:30.0 handler:nil];
+}
+
+- (void)testOnLoadRequestReturnsErroResultForInvalidRequest {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+  XCTestExpectation *resultExpectation =
+      [self expectationWithDescription:@"Should return error result when request cannot be built"];
+
+  // Run
+  FlutterMethodCall *methodCall = [FlutterMethodCall methodCallWithMethodName:@"loadRequest"
+                                                                    arguments:@{}];
+  [controller onLoadRequest:methodCall
+                     result:^(id _Nullable result) {
+                       XCTAssertTrue([result class] == [FlutterError class]);
+                       [resultExpectation fulfill];
+                     }];
+
+  // Verify
+  [self waitForExpectationsWithTimeout:30.0 handler:nil];
+}
+
+- (void)testOnLoadRequestLoadsRequestWithSuccessResult {
+  // Setup
+  FLTWebViewController *controller =
+      [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
+                                   viewIdentifier:1
+                                        arguments:nil
+                                  binaryMessenger:self.mockBinaryMessenger];
+  XCTestExpectation *resultExpectation = [self expectationWithDescription:@"Should return nil"];
+  FLTWKWebView *mockView = OCMClassMock(FLTWKWebView.class);
+  controller.webView = mockView;
+
+  // Run
+  FlutterMethodCall *methodCall = [FlutterMethodCall
+      methodCallWithMethodName:@"loadRequest"
+                     arguments:@{@"request" : @{@"uri" : @"https://flutter.dev/"}}];
+  [controller onLoadRequest:methodCall
+                     result:^(id _Nullable result) {
+                       XCTAssertNil(result);
+                       [resultExpectation fulfill];
+                     }];
+
+  // Verify
+  OCMVerify([mockView loadRequest:[OCMArg any]]);
+  [self waitForExpectationsWithTimeout:30.0 handler:nil];
+}
+
 @end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
index 21240f6..ea95cdd 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -6,6 +6,7 @@
 
 import 'dart:async';
 import 'dart:convert';
+import 'dart:typed_data';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
@@ -120,6 +121,7 @@
   listCache,
   clearCache,
   navigationDelegate,
+  doPostRequest,
 }
 
 class _SampleMenu extends StatelessWidget {
@@ -157,6 +159,9 @@
               case _MenuOptions.navigationDelegate:
                 _onNavigationDelegateExample(controller.data!, context);
                 break;
+              case _MenuOptions.doPostRequest:
+                _onDoPostRequest(controller.data!, context);
+                break;
             }
           },
           itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
@@ -189,6 +194,10 @@
               value: _MenuOptions.navigationDelegate,
               child: Text('Navigation Delegate example'),
             ),
+            const PopupMenuItem<_MenuOptions>(
+              value: _MenuOptions.doPostRequest,
+              child: Text('Post Request'),
+            ),
           ],
         );
       },
@@ -259,6 +268,17 @@
     await controller.loadUrl('data:text/html;base64,$contentBase64');
   }
 
+  void _onDoPostRequest(
+      WebViewController controller, BuildContext context) async {
+    WebViewRequest request = WebViewRequest(
+      uri: Uri.parse('https://httpbin.org/post'),
+      method: WebViewRequestMethod.post,
+      headers: {'foo': 'bar', 'Content-Type': 'text/plain'},
+      body: Uint8List.fromList('Test Body'.codeUnits),
+    );
+    await controller.loadRequest(request);
+  }
+
   Widget _getCookieList(String cookies) {
     if (cookies == null || cookies == '""') {
       return Container();
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
index 403db1f..b2555cd 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart
@@ -322,6 +322,11 @@
     return _webViewPlatformController.loadUrl(url, headers);
   }
 
+  /// Loads a page by making the specified request.
+  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_wkwebview/ios/Classes/FlutterWebView.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h
index db52124..6d8e463 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h
@@ -27,6 +27,7 @@
 - (UIView*)view;
 
 - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
+
 @end
 
 @interface FLTWebViewFactory : NSObject <FlutterPlatformViewFactory>
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
index 5e12f8a..b8355ad 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m
@@ -5,6 +5,7 @@
 #import "FlutterWebView.h"
 #import "FLTWKNavigationDelegate.h"
 #import "FLTWKProgressionDelegate.h"
+#import "FlutterWebView_Test.h"
 #import "JavaScriptChannelHandler.h"
 
 @implementation FLTWebViewFactory {
@@ -116,7 +117,11 @@
 
     NSString* initialUrl = args[@"initialUrl"];
     if ([initialUrl isKindOfClass:[NSString class]]) {
-      [self loadUrl:initialUrl];
+      NSURL* url = [NSURL URLWithString:initialUrl];
+      if (url) {
+        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
+        [_webView loadRequest:request];
+      }
     }
   }
   return self;
@@ -137,6 +142,8 @@
     [self onUpdateSettings:call result:result];
   } else if ([[call method] isEqualToString:@"loadUrl"]) {
     [self onLoadUrl:call result:result];
+  } else if ([[call method] isEqualToString:@"loadRequest"]) {
+    [self onLoadRequest:call result:result];
   } else if ([[call method] isEqualToString:@"canGoBack"]) {
     [self onCanGoBack:call result:result];
   } else if ([[call method] isEqualToString:@"canGoForward"]) {
@@ -186,12 +193,34 @@
 }
 
 - (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result {
-  if (![self loadRequest:[call arguments]]) {
+  NSMutableDictionary* requestData = [[NSMutableDictionary alloc] init];
+  if (call.arguments[@"url"]) {
+    requestData[@"uri"] = call.arguments[@"url"];
+  }
+  if (call.arguments[@"headers"]) {
+    requestData[@"headers"] = call.arguments[@"headers"];
+  }
+  NSURLRequest* request = [self buildNSURLRequest:@{@"request" : requestData}];
+  if (!request) {
     result([FlutterError
         errorWithCode:@"loadUrl_failed"
               message:@"Failed parsing the URL"
               details:[NSString stringWithFormat:@"Request was: '%@'", [call arguments]]]);
   } else {
+    [_webView loadRequest:request];
+    result(nil);
+  }
+}
+
+- (void)onLoadRequest:(FlutterMethodCall*)call result:(FlutterResult)result {
+  NSURLRequest* request = [self buildNSURLRequest:[call arguments]];
+  if (!request) {
+    result([FlutterError
+        errorWithCode:@"loadRequest_failed"
+              message:@"Failed parsing the URL"
+              details:[NSString stringWithFormat:@"Request was: '%@'", [call arguments]]]);
+  } else {
+    [_webView loadRequest:request];
     result(nil);
   }
 }
@@ -459,37 +488,47 @@
   }
 }
 
-- (bool)loadRequest:(NSDictionary<NSString*, id>*)request {
-  if (!request) {
-    return false;
+/**
+ * Parses the method call arguments and converts them to an NSURLRequest object.
+ *
+ * @param arguments the method call arguments.
+ *
+ * @return NSURLRequest object.
+ */
+- (NSURLRequest*)buildNSURLRequest:(NSDictionary<NSString*, id>*)arguments {
+  id requestParameters = arguments[@"request"];
+  if (![requestParameters isKindOfClass:[NSDictionary class]]) {
+    return nil;
   }
 
-  NSString* url = request[@"url"];
-  if ([url isKindOfClass:[NSString class]]) {
-    id headers = request[@"headers"];
-    if ([headers isKindOfClass:[NSDictionary class]]) {
-      return [self loadUrl:url withHeaders:headers];
-    } else {
-      return [self loadUrl:url];
-    }
+  NSString* urlString = requestParameters[@"uri"];
+  if (!urlString) {
+    return nil;
   }
 
-  return false;
-}
-
-- (bool)loadUrl:(NSString*)url {
-  return [self loadUrl:url withHeaders:[NSMutableDictionary dictionary]];
-}
-
-- (bool)loadUrl:(NSString*)url withHeaders:(NSDictionary<NSString*, NSString*>*)headers {
-  NSURL* nsUrl = [NSURL URLWithString:url];
-  if (!nsUrl) {
-    return false;
+  NSURL* url = [NSURL URLWithString:urlString];
+  if (!url) {
+    return nil;
   }
-  NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:nsUrl];
-  [request setAllHTTPHeaderFields:headers];
-  [_webView loadRequest:request];
-  return true;
+
+  NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
+
+  NSString* httpMethod = requestParameters[@"method"];
+  if (httpMethod) {
+    [request setHTTPMethod:httpMethod];
+  }
+
+  id httpBody = requestParameters[@"body"];
+  if ([httpBody isKindOfClass:[FlutterStandardTypedData class]]) {
+    [request setHTTPBody:[httpBody data]];
+  }
+
+  id headers = requestParameters[@"headers"];
+  if ([headers isKindOfClass:[NSDictionary class]]) {
+    [request setAllHTTPHeaderFields:headers];
+  }
+
+  return request;
 }
 
 - (void)registerJavaScriptChannels:(NSSet*)channelNames
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap
new file mode 100644
index 0000000..fa51430
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap
@@ -0,0 +1,10 @@
+framework module webview_flutter_wkwebview {
+  umbrella header "webview-umbrella.h"
+  
+  export *
+  module * { export * }
+
+  explicit module Test {
+    header "FlutterWebView_Test.h"
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView_Test.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView_Test.h
new file mode 100644
index 0000000..13973f8
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView_Test.h
@@ -0,0 +1,21 @@
+// 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.
+
+// This header is available in the Test module. Import via "@import webview_flutter_wkwebview.Test;"
+
+#import <webview_flutter_wkwebview/FlutterWebView.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface FLTWebViewController ()
+
+- (NSURLRequest*)buildNSURLRequest:(NSDictionary<NSString*, id>*)arguments;
+
+- (void)onLoadUrl:(FlutterMethodCall*)call result:(FlutterResult)result;
+
+- (void)onLoadRequest:(FlutterMethodCall*)call result:(FlutterResult)result;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
new file mode 100644
index 0000000..c37282e
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
@@ -0,0 +1,11 @@
+// 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 <Foundation/Foundation.h>
+#import <webview_flutter_wkwebview/FLTCookieManager.h>
+#import <webview_flutter_wkwebview/FLTWKNavigationDelegate.h>
+#import <webview_flutter_wkwebview/FLTWKProgressionDelegate.h>
+#import <webview_flutter_wkwebview/FLTWebViewFlutterPlugin.h>
+#import <webview_flutter_wkwebview/FlutterWebView.h>
+#import <webview_flutter_wkwebview/JavaScriptChannelHandler.h>
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/webview_flutter_wkwebview.podspec b/packages/webview_flutter/webview_flutter_wkwebview/ios/webview_flutter_wkwebview.podspec
index 2dfb336..89c0623 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/webview_flutter_wkwebview.podspec
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/webview_flutter_wkwebview.podspec
@@ -14,8 +14,9 @@
   s.author           = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
   s.source           = { :http => 'https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview' }
   s.documentation_url = 'https://pub.dev/packages/webview_flutter'
-  s.source_files = 'Classes/**/*'
+  s.source_files = 'Classes/**/*.{h,m}'
   s.public_header_files = 'Classes/**/*.h'
+  s.module_map = 'Classes/FlutterWebView.modulemap'
   s.dependency 'Flutter'
 
   s.platform = :ios, '9.0'
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index 5176adb..ff2b69f 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
 repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.2.0
+version: 2.3.0
 
 environment:
   sdk: ">=2.14.0 <3.0.0"
@@ -18,7 +18,7 @@
 dependencies:
   flutter:
     sdk: flutter
-  webview_flutter_platform_interface: ^1.2.0
+  webview_flutter_platform_interface: ^1.3.0
 
 dev_dependencies:
   flutter_driver: