Move clearCookies behind the platform abstraction (#1663)

This is a followup for #1618, #1624, and #1645, and moves the plugins.flutter.io/cookie_manager method channel behind the platform interface which allows a third party package to provide a new platform implementation the cooke manager.

See the description for #1618 for more details.

Following this PR all platform specific code can be replaced by an external package.
diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md
index 306181c..4ba6202 100644
--- a/packages/webview_flutter/CHANGELOG.md
+++ b/packages/webview_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.9
+
+* Allow external packages to provide webview implementations for new platforms.
+
 ## 0.3.8+1
 
 * Suppress deprecation warning for BinaryMessages. See: https://github.com/flutter/flutter/issues/33446
diff --git a/packages/webview_flutter/lib/platform_interface.dart b/packages/webview_flutter/lib/platform_interface.dart
index 5d8899a..bfb5b62 100644
--- a/packages/webview_flutter/lib/platform_interface.dart
+++ b/packages/webview_flutter/lib/platform_interface.dart
@@ -10,20 +10,20 @@
 
 import 'webview_flutter.dart';
 
-/// Interface for callbacks made by [WebViewPlatform].
+/// Interface for callbacks made by [WebViewPlatformController].
 ///
-/// The webview plugin implements this class, and passes an instance to the [WebViewPlatform].
-/// [WebViewPlatform] is notifying this handler on events that happened on the platform's webview.
+/// The webview plugin implements this class, and passes an instance to the [WebViewPlatformController].
+/// [WebViewPlatformController] is notifying this handler on events that happened on the platform's webview.
 abstract class WebViewPlatformCallbacksHandler {
-  /// Invoked by [WebViewPlatform] when a JavaScript channel message is received.
+  /// Invoked by [WebViewPlatformController] when a JavaScript channel message is received.
   void onJavaScriptChannelMessage(String channel, String message);
 
-  /// Invoked by [WebViewPlatform] when a navigation request is pending.
+  /// Invoked by [WebViewPlatformController] when a navigation request is pending.
   ///
   /// If true is returned the navigation is allowed, otherwise it is blocked.
   bool onNavigationRequest({String url, bool isForMainFrame});
 
-  /// Invoked by [WebViewPlatform] when a page has finished loading.
+  /// Invoked by [WebViewPlatformController] when a page has finished loading.
   void onPageFinished(String url);
 }
 
@@ -31,13 +31,13 @@
 ///
 /// An instance implementing this interface is passed to the `onWebViewPlatformCreated` callback that is
 /// passed to [WebViewPlatformBuilder#onWebViewPlatformCreated].
-abstract class WebViewPlatform {
+abstract class WebViewPlatformController {
   /// Creates a new WebViewPlatform.
   ///
   /// Callbacks made by the WebView will be delegated to `handler`.
   ///
   /// The `handler` parameter must not be null.
-  WebViewPlatform(WebViewPlatformCallbacksHandler handler);
+  WebViewPlatformController(WebViewPlatformCallbacksHandler handler);
 
   /// Loads the specified URL.
   ///
@@ -182,7 +182,7 @@
   }
 }
 
-/// Configuration to use when creating a new [WebViewPlatform].
+/// Configuration to use when creating a new [WebViewPlatformController].
 class CreationParams {
   CreationParams(
       {this.initialUrl, this.webSettings, this.javascriptChannelNames});
@@ -194,7 +194,7 @@
 
   /// The initial [WebSettings] for the new webview.
   ///
-  /// This can later be updated with [WebViewPlatform.updateSettings].
+  /// This can later be updated with [WebViewPlatformController.updateSettings].
   final WebSettings webSettings;
 
   /// The initial set of JavaScript channels that are configured for this webview.
@@ -217,14 +217,14 @@
 }
 
 typedef WebViewPlatformCreatedCallback = void Function(
-    WebViewPlatform webViewPlatform);
+    WebViewPlatformController webViewPlatformController);
 
-/// Interface building a platform WebView implementation.
+/// Interface for a platform implementation of a WebView.
 ///
-/// [WebView#platformBuilder] controls the builder that is used by [WebView].
+/// [WebView.platform] controls the builder that is used by [WebView].
 /// [AndroidWebViewPlatform] and [CupertinoWebViewPlatform] are the default implementations
 /// for Android and iOS respectively.
-abstract class WebViewBuilder {
+abstract class WebViewPlatform {
   /// Builds a new WebView.
   ///
   /// Returns a Widget tree that embeds the created webview.
@@ -232,10 +232,10 @@
   /// `creationParams` are the initial parameters used to setup the webview.
   ///
   /// `webViewPlatformHandler` will be used for handling callbacks that are made by the created
-  /// [WebViewPlatform].
+  /// [WebViewPlatformController].
   ///
-  /// `onWebViewPlatformCreated` will be invoked after the platform specific [WebViewPlatform]
-  /// implementation is created with the [WebViewPlatform] instance as a parameter.
+  /// `onWebViewPlatformCreated` will be invoked after the platform specific [WebViewPlatformController]
+  /// implementation is created with the [WebViewPlatformController] instance as a parameter.
   ///
   /// `gestureRecognizers` specifies which gestures should be consumed by the web view.
   /// It is possible for other gesture recognizers to be competing with the web view on pointer
@@ -256,4 +256,12 @@
     WebViewPlatformCreatedCallback onWebViewPlatformCreated,
     Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
   });
+
+  /// Clears all cookies for all [WebView] instances.
+  ///
+  /// Returns true if cookies were present before clearing, else false.
+  Future<bool> clearCookies() {
+    throw UnimplementedError(
+        "WebView clearCookies is not implemented on the current platform");
+  }
 }
diff --git a/packages/webview_flutter/lib/src/webview_android.dart b/packages/webview_flutter/lib/src/webview_android.dart
index 8d5f98a..f7afcc0 100644
--- a/packages/webview_flutter/lib/src/webview_android.dart
+++ b/packages/webview_flutter/lib/src/webview_android.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:async';
+
 import 'package:flutter/foundation.dart';
 import 'package:flutter/gestures.dart';
 import 'package:flutter/services.dart';
@@ -12,10 +14,10 @@
 
 /// Builds an Android webview.
 ///
-/// This is used as the default implementation for [WebView.platformBuilder] on Android. It uses
+/// This is used as the default implementation for [WebView.platform] on Android. It uses
 /// an [AndroidView] to embed the webview in the widget hierarchy, and uses a method channel to
 /// communicate with the platform code.
-class AndroidWebViewBuilder implements WebViewBuilder {
+class AndroidWebView implements WebViewPlatform {
   @override
   Widget build({
     BuildContext context,
@@ -55,4 +57,7 @@
       ),
     );
   }
+
+  @override
+  Future<bool> clearCookies() => MethodChannelWebViewPlatform.clearCookies();
 }
diff --git a/packages/webview_flutter/lib/src/webview_cupertino.dart b/packages/webview_flutter/lib/src/webview_cupertino.dart
index 04ca9d7..0e84908 100644
--- a/packages/webview_flutter/lib/src/webview_cupertino.dart
+++ b/packages/webview_flutter/lib/src/webview_cupertino.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:async';
+
 import 'package:flutter/foundation.dart';
 import 'package:flutter/gestures.dart';
 import 'package:flutter/services.dart';
@@ -12,10 +14,10 @@
 
 /// Builds an iOS webview.
 ///
-/// This is used as the default implementation for [WebView.platformBuilder] on iOS. It uses
+/// This is used as the default implementation for [WebView.platform] on iOS. It uses
 /// a [UiKitView] to embed the webview in the widget hierarchy, and uses a method channel to
 /// communicate with the platform code.
-class CupertinoWebViewBuilder implements WebViewBuilder {
+class CupertinoWebView implements WebViewPlatform {
   @override
   Widget build({
     BuildContext context,
@@ -39,4 +41,7 @@
       creationParamsCodec: const StandardMessageCodec(),
     );
   }
+
+  @override
+  Future<bool> clearCookies() => MethodChannelWebViewPlatform.clearCookies();
 }
diff --git a/packages/webview_flutter/lib/src/webview_method_channel.dart b/packages/webview_flutter/lib/src/webview_method_channel.dart
index d86a8b4..91cb3b6 100644
--- a/packages/webview_flutter/lib/src/webview_method_channel.dart
+++ b/packages/webview_flutter/lib/src/webview_method_channel.dart
@@ -8,8 +8,8 @@
 
 import '../platform_interface.dart';
 
-/// A [WebViewPlatform] that uses a method channel to control the webview.
-class MethodChannelWebViewPlatform implements WebViewPlatform {
+/// A [WebViewPlatformController] that uses a method channel to control the webview.
+class MethodChannelWebViewPlatform implements WebViewPlatformController {
   MethodChannelWebViewPlatform(int id, this._platformCallbacksHandler)
       : assert(_platformCallbacksHandler != null),
         _channel = MethodChannel('plugins.flutter.io/webview_$id') {
@@ -20,6 +20,9 @@
 
   final MethodChannel _channel;
 
+  static const MethodChannel _cookieManagerChannel =
+      MethodChannel('plugins.flutter.io/cookie_manager');
+
   Future<bool> _onMethodCall(MethodCall call) async {
     switch (call.method) {
       case 'javascriptChannelMessage':
@@ -105,6 +108,16 @@
         'removeJavascriptChannels', javascriptChannelNames.toList());
   }
 
+  /// Method channel mplementation for [WebViewPlatform.clearCookies].
+  static Future<bool> clearCookies() {
+    return _cookieManagerChannel
+        // TODO(amirh): remove this when the invokeMethod update makes it to stable Flutter.
+        // https://github.com/flutter/flutter/issues/26431
+        // ignore: strong_mode_implicit_dynamic_method
+        .invokeMethod('clearCookies')
+        .then<bool>((dynamic result) => result);
+  }
+
   static Map<String, dynamic> _webSettingsToMap(WebSettings settings) {
     final Map<String, dynamic> map = <String, dynamic>{};
     void _addIfNonNull(String key, dynamic value) {
diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart
index dd7e920..3c0175e 100644
--- a/packages/webview_flutter/lib/webview_flutter.dart
+++ b/packages/webview_flutter/lib/webview_flutter.dart
@@ -6,7 +6,6 @@
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/gestures.dart';
-import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
 
 import 'platform_interface.dart';
@@ -125,37 +124,37 @@
   })  : assert(javascriptMode != null),
         super(key: key);
 
-  static WebViewBuilder _platformBuilder;
+  static WebViewPlatform _platform;
 
-  /// Sets a custom [WebViewBuilder].
+  /// Sets a custom [WebViewPlatform].
   ///
   /// This property can be set to use a custom platform implementation for WebViews.
   ///
-  /// Setting `platformBuilder` doesn't affect [WebView]s that were already created.
+  /// Setting `platform` doesn't affect [WebView]s that were already created.
   ///
-  /// The default value is [AndroidWebViewBuilder] on Android and [CupertinoWebViewBuilder] on iOs.
-  static set platformBuilder(WebViewBuilder platformBuilder) {
-    _platformBuilder = platformBuilder;
+  /// The default value is [AndroidWebView] on Android and [CupertinoWebView] on iOS.
+  static set platform(WebViewPlatform platform) {
+    _platform = platform;
   }
 
-  /// The [WebViewBuilder] that's used to create new [WebView]s.
+  /// The WebView platform that's used by this WebView.
   ///
-  /// The default value is [AndroidWebViewBuilder] on Android and [CupertinoWebViewBuilder] on iOs.
-  static WebViewBuilder get platformBuilder {
-    if (_platformBuilder == null) {
+  /// The default value is [AndroidWebView] on Android and [CupertinoWebView] on iOS.
+  static WebViewPlatform get platform {
+    if (_platform == null) {
       switch (defaultTargetPlatform) {
         case TargetPlatform.android:
-          _platformBuilder = AndroidWebViewBuilder();
+          _platform = AndroidWebView();
           break;
         case TargetPlatform.iOS:
-          _platformBuilder = CupertinoWebViewBuilder();
+          _platform = CupertinoWebView();
           break;
         default:
           throw UnsupportedError(
               "Trying to use the default webview implementation for $defaultTargetPlatform but there isn't a default one");
       }
     }
-    return _platformBuilder;
+    return _platform;
   }
 
   /// If not null invoked once the web view is created.
@@ -268,7 +267,7 @@
 
   @override
   Widget build(BuildContext context) {
-    return WebView.platformBuilder.build(
+    return WebView.platform.build(
       context: context,
       onWebViewPlatformCreated: _onWebViewPlatformCreated,
       webViewPlatformCallbacksHandler: _platformCallbacksHandler,
@@ -294,7 +293,7 @@
     });
   }
 
-  void _onWebViewPlatformCreated(WebViewPlatform webViewPlatform) {
+  void _onWebViewPlatformCreated(WebViewPlatformController webViewPlatform) {
     final WebViewController controller =
         WebViewController._(widget, webViewPlatform, _platformCallbacksHandler);
     _controller.complete(controller);
@@ -416,13 +415,13 @@
 class WebViewController {
   WebViewController._(
     this._widget,
-    this._webViewPlatform,
+    this._webViewPlatformController,
     this._platformCallbacksHandler,
-  ) : assert(_webViewPlatform != null) {
+  ) : assert(_webViewPlatformController != null) {
     _settings = _webSettingsFromWidget(_widget);
   }
 
-  final WebViewPlatform _webViewPlatform;
+  final WebViewPlatformController _webViewPlatformController;
 
   final _PlatformCallbacksHandler _platformCallbacksHandler;
 
@@ -444,7 +443,7 @@
   }) async {
     assert(url != null);
     _validateUrlString(url);
-    return _webViewPlatform.loadUrl(url, headers);
+    return _webViewPlatformController.loadUrl(url, headers);
   }
 
   /// Accessor to the current URL that the WebView is displaying.
@@ -455,7 +454,7 @@
   /// words, by the time this future completes, the WebView may be displaying a
   /// different URL).
   Future<String> currentUrl() {
-    return _webViewPlatform.currentUrl();
+    return _webViewPlatformController.currentUrl();
   }
 
   /// Checks whether there's a back history item.
@@ -463,7 +462,7 @@
   /// Note that this operation is asynchronous, and it is possible that the "canGoBack" state has
   /// changed by the time the future completed.
   Future<bool> canGoBack() {
-    return _webViewPlatform.canGoBack();
+    return _webViewPlatformController.canGoBack();
   }
 
   /// Checks whether there's a forward history item.
@@ -471,26 +470,26 @@
   /// Note that this operation is asynchronous, and it is possible that the "canGoForward" state has
   /// changed by the time the future completed.
   Future<bool> canGoForward() {
-    return _webViewPlatform.canGoForward();
+    return _webViewPlatformController.canGoForward();
   }
 
   /// Goes back in the history of this WebView.
   ///
   /// If there is no back history item this is a no-op.
   Future<void> goBack() {
-    return _webViewPlatform.goBack();
+    return _webViewPlatformController.goBack();
   }
 
   /// Goes forward in the history of this WebView.
   ///
   /// If there is no forward history item this is a no-op.
   Future<void> goForward() {
-    return _webViewPlatform.goForward();
+    return _webViewPlatformController.goForward();
   }
 
   /// Reloads the current URL.
   Future<void> reload() {
-    return _webViewPlatform.reload();
+    return _webViewPlatformController.reload();
   }
 
   /// Clears all caches used by the [WebView].
@@ -504,7 +503,7 @@
   ///
   /// Note: Calling this method also triggers a reload.
   Future<void> clearCache() async {
-    await _webViewPlatform.clearCache();
+    await _webViewPlatformController.clearCache();
     return reload();
   }
 
@@ -518,7 +517,7 @@
     final WebSettings update =
         _clearUnchangedWebSettings(_settings, newSettings);
     _settings = newSettings;
-    return _webViewPlatform.updateSettings(update);
+    return _webViewPlatformController.updateSettings(update);
   }
 
   Future<void> _updateJavascriptChannels(
@@ -531,10 +530,10 @@
     final Set<String> channelsToRemove =
         currentChannels.difference(newChannelNames);
     if (channelsToRemove.isNotEmpty) {
-      _webViewPlatform.removeJavascriptChannels(channelsToRemove);
+      _webViewPlatformController.removeJavascriptChannels(channelsToRemove);
     }
     if (channelsToAdd.isNotEmpty) {
-      _webViewPlatform.addJavascriptChannels(channelsToAdd);
+      _webViewPlatformController.addJavascriptChannels(channelsToAdd);
     }
     _platformCallbacksHandler._updateJavascriptChannelsFromSet(newChannels);
   }
@@ -567,7 +566,7 @@
     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
     // https://github.com/flutter/flutter/issues/26431
     // ignore: strong_mode_implicit_dynamic_method
-    return _webViewPlatform.evaluateJavascript(javascriptString);
+    return _webViewPlatformController.evaluateJavascript(javascriptString);
   }
 }
 
@@ -580,21 +579,14 @@
 
   CookieManager._();
 
-  static const MethodChannel _channel =
-      MethodChannel('plugins.flutter.io/cookie_manager');
   static CookieManager _instance;
 
-  /// Clears all cookies.
+  /// Clears all cookies for all [WebView] instances.
   ///
-  /// This is supported for >= IOS 9.
+  /// This is a no op on iOS version smaller than 9.
   ///
   /// Returns true if cookies were present before clearing, else false.
-  Future<bool> clearCookies() => _channel
-      // TODO(amirh): remove this when the invokeMethod update makes it to stable Flutter.
-      // https://github.com/flutter/flutter/issues/26431
-      // ignore: strong_mode_implicit_dynamic_method
-      .invokeMethod('clearCookies')
-      .then<bool>((dynamic result) => result);
+  Future<bool> clearCookies() => WebView.platform.clearCookies();
 }
 
 // Throws an ArgumentError if `url` is not a valid URL string.
diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml
index da24d39..2dbabc8 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.8+1
+version: 0.3.9
 author: Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter
 
diff --git a/packages/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/test/webview_flutter_test.dart
index 2a458ad..d451a86 100644
--- a/packages/webview_flutter/test/webview_flutter_test.dart
+++ b/packages/webview_flutter/test/webview_flutter_test.dart
@@ -752,10 +752,10 @@
 
   group('Custom platform implementation', () {
     setUpAll(() {
-      WebView.platformBuilder = MyWebViewBuilder();
+      WebView.platform = MyWebViewPlatform();
     });
     tearDownAll(() {
-      WebView.platformBuilder = null;
+      WebView.platform = null;
     });
 
     testWidgets('creation', (WidgetTester tester) async {
@@ -765,8 +765,8 @@
         ),
       );
 
-      final MyWebViewBuilder builder = WebView.platformBuilder;
-      final MyWebViewPlatform platform = builder.lastPlatformBuilt;
+      final MyWebViewPlatform builder = WebView.platform;
+      final MyWebViewPlatformController platform = builder.lastPlatformBuilt;
 
       expect(
           platform.creationParams,
@@ -794,8 +794,8 @@
         ),
       );
 
-      final MyWebViewBuilder builder = WebView.platformBuilder;
-      final MyWebViewPlatform platform = builder.lastPlatformBuilt;
+      final MyWebViewPlatform builder = WebView.platform;
+      final MyWebViewPlatformController platform = builder.lastPlatformBuilt;
 
       final Map<String, String> headers = <String, String>{
         'header': 'value',
@@ -1033,8 +1033,8 @@
   }
 }
 
-class MyWebViewBuilder implements WebViewBuilder {
-  MyWebViewPlatform lastPlatformBuilt;
+class MyWebViewPlatform implements WebViewPlatform {
+  MyWebViewPlatformController lastPlatformBuilt;
 
   @override
   Widget build({
@@ -1045,15 +1045,20 @@
     Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
   }) {
     assert(onWebViewPlatformCreated != null);
-    lastPlatformBuilt = MyWebViewPlatform(
+    lastPlatformBuilt = MyWebViewPlatformController(
         creationParams, gestureRecognizers, webViewPlatformCallbacksHandler);
     onWebViewPlatformCreated(lastPlatformBuilt);
     return Container();
   }
+
+  @override
+  Future<bool> clearCookies() {
+    return Future<bool>.sync(() => null);
+  }
 }
 
-class MyWebViewPlatform extends WebViewPlatform {
-  MyWebViewPlatform(this.creationParams, this.gestureRecognizers,
+class MyWebViewPlatformController extends WebViewPlatformController {
+  MyWebViewPlatformController(this.creationParams, this.gestureRecognizers,
       WebViewPlatformCallbacksHandler platformHandler)
       : super(platformHandler);