[webview_flutter] always make sure the contentInset or the sum of contentInset and adjustedContentInset is 0 on iOS. (#2466)

diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md
index 32ccc7c..f87091e 100644
--- a/packages/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.3.19+5
+
+* On iOS, always keep contentInsets of the WebView to be 0.
+* Fix XCTest case to follow XCTest naming convention.
+
 ## 0.3.19+4
 
 * On iOS, fix the scroll view content inset is automatically adjusted. After the fix, the content position of the WebView is customizable by Flutter.
diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.h b/packages/webview_flutter/ios/Classes/FlutterWebView.h
index 08e6b8a..6277901 100644
--- a/packages/webview_flutter/ios/Classes/FlutterWebView.h
+++ b/packages/webview_flutter/ios/Classes/FlutterWebView.h
@@ -21,4 +21,12 @@
 - (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
 @end
 
+/**
+ * The WkWebView used for the plugin.
+ *
+ * This class overrides some methods in `WKWebView` to serve the needs for the plugin.
+ */
+@interface FLTWKWebView : WKWebView
+@end
+
 NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m
index b1fc143..20aad2c 100644
--- a/packages/webview_flutter/ios/Classes/FlutterWebView.m
+++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m
@@ -34,8 +34,30 @@
 
 @end
 
+@implementation FLTWKWebView
+
+- (void)setFrame:(CGRect)frame {
+  [super setFrame:frame];
+  self.scrollView.contentInset = UIEdgeInsetsZero;
+  // We don't want the contentInsets to be adjusted by iOS, flutter should always take control of
+  // webview's contentInsets.
+  // self.scrollView.contentInset = UIEdgeInsetsZero;
+  if (@available(iOS 11, *)) {
+    // Above iOS 11, adjust contentInset to compensate the adjustedContentInset so the sum will
+    // always be 0.
+    if (UIEdgeInsetsEqualToEdgeInsets(self.scrollView.adjustedContentInset, UIEdgeInsetsZero)) {
+      return;
+    }
+    UIEdgeInsets insetToAdjust = self.scrollView.adjustedContentInset;
+    self.scrollView.contentInset = UIEdgeInsetsMake(-insetToAdjust.top, -insetToAdjust.left,
+                                                    -insetToAdjust.bottom, -insetToAdjust.right);
+  }
+}
+
+@end
+
 @implementation FLTWebViewController {
-  WKWebView* _webView;
+  FLTWKWebView* _webView;
   int64_t _viewId;
   FlutterMethodChannel* _channel;
   NSString* _currentUrl;
@@ -69,7 +91,7 @@
     [self updateAutoMediaPlaybackPolicy:args[@"autoMediaPlaybackPolicy"]
                         inConfiguration:configuration];
 
-    _webView = [[WKWebView alloc] initWithFrame:frame configuration:configuration];
+    _webView = [[FLTWKWebView alloc] initWithFrame:frame configuration:configuration];
     _navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel];
     _webView.navigationDelegate = _navigationDelegate;
     __weak __typeof__(self) weakSelf = self;
diff --git a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m
index a545fd7..45fa521 100644
--- a/packages/webview_flutter/ios/Tests/FLTWebViewTests.m
+++ b/packages/webview_flutter/ios/Tests/FLTWebViewTests.m
@@ -7,6 +7,8 @@
 @import XCTest;
 @import webview_flutter;
 
+static bool feq(CGFloat a, CGFloat b) { return fabs(b - a) < FLT_EPSILON; }
+
 @interface FLTWebViewTests : XCTestCase
 
 @property(strong, nonatomic) NSObject<FlutterBinaryMessenger> *mockBinaryMessenger;
@@ -20,7 +22,7 @@
   self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
 }
 
-- (void)canInitFLTWebViewController {
+- (void)testCanInitFLTWebViewController {
   FLTWebViewController *controller =
       [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
                                    viewIdentifier:1
@@ -29,7 +31,7 @@
   XCTAssertNotNil(controller);
 }
 
-- (void)canInitFLTWebViewFactory {
+- (void)testCanInitFLTWebViewFactory {
   FLTWebViewFactory *factory =
       [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger];
   XCTAssertNotNil(factory);
@@ -50,7 +52,7 @@
   }
 }
 
-- (void)webViewScrollIndicatorAticautomaticallyAdjustsScrollIndicatorInsetsShouldbeNoOnIOS13 {
+- (void)testWebViewScrollIndicatorAticautomaticallyAdjustsScrollIndicatorInsetsShouldbeNoOnIOS13 {
   if (@available(iOS 13, *)) {
     FLTWebViewController *controller =
         [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400)
@@ -64,4 +66,24 @@
   }
 }
 
+- (void)testContentInsetsSumAlwaysZeroAfterSetFrame {
+  FLTWKWebView *webView = [[FLTWKWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 400)];
+  webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 300, 0);
+  XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(webView.scrollView.contentInset, UIEdgeInsetsZero));
+  webView.frame = CGRectMake(0, 0, 300, 200);
+  XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(webView.scrollView.contentInset, UIEdgeInsetsZero));
+  XCTAssertTrue(CGRectEqualToRect(webView.frame, CGRectMake(0, 0, 300, 200)));
+
+  if (@available(iOS 11, *)) {
+    // After iOS 11, we need to make sure the contentInset compensates the adjustedContentInset.
+    UIScrollView *partialMockScrollView = OCMPartialMock(webView.scrollView);
+    UIEdgeInsets insetToAdjust = UIEdgeInsetsMake(0, 0, 300, 0);
+    OCMStub(partialMockScrollView.adjustedContentInset).andReturn(insetToAdjust);
+    XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(webView.scrollView.contentInset, UIEdgeInsetsZero));
+    webView.frame = CGRectMake(0, 0, 300, 100);
+    XCTAssertTrue(feq(webView.scrollView.contentInset.bottom, -insetToAdjust.bottom));
+    XCTAssertTrue(CGRectEqualToRect(webView.frame, CGRectMake(0, 0, 300, 100)));
+  }
+}
+
 @end
diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml
index e528e8d..bbe6107 100644
--- a/packages/webview_flutter/pubspec.yaml
+++ b/packages/webview_flutter/pubspec.yaml
@@ -1,6 +1,6 @@
 name: webview_flutter
 description: A Flutter plugin that provides a WebView widget on Android and iOS.
-version: 0.3.19+4
+version: 0.3.19+5
 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter
 
 environment: