From 88e89bd1023da78e128c929810a158ced263eeff Mon Sep 17 00:00:00 2001
From: Lorenzo Pichilli <pichillilorenzo@gmail.com>
Date: Thu, 5 May 2022 20:19:16 +0200
Subject: [PATCH] fixed iOS nil exception on URLRequest url property, update
 some iOS classes to use ChannelDelegate class and Disposable protocol, added
 some more null checks on Android

---
 .../FlutterWebViewFactory.java                |   1 +
 .../InAppWebViewFlutterPlugin.java            |   2 +-
 .../InAppWebViewStatic.java                   |   3 +-
 .../flutter_inappwebview/MyCookieManager.java |   6 +-
 .../flutter_inappwebview/MyWebStorage.java    |  37 ++++--
 .../flutter_inappwebview/PlatformUtil.java    |   3 +-
 .../RequestPermissionHandler.java             |  46 -------
 .../WebViewFeatureManager.java                |   3 +-
 .../ChromeSafariBrowserManager.java           |   3 +-
 .../CredentialDatabaseHandler.java            | 112 ++++++++++--------
 .../HeadlessInAppWebViewManager.java          |   3 +-
 .../in_app_browser/InAppBrowserManager.java   |   3 +-
 .../proxy/ProxyManager.java                   |   3 +-
 .../types/IChannelDelegate.java               |   3 +-
 .../types/URLRequest.java                     |  17 +--
 .../ios/Flutter/flutter_export_environment.sh |   7 +-
 ios/Classes/CredentialDatabase.swift          |  21 +---
 .../HeadlessInAppWebView.swift                |  41 ++-----
 .../HeadlessInAppWebViewManager.swift         |  19 +--
 .../HeadlessWebViewChannelDelegate.swift      |  59 +++++++++
 .../InAppBrowser/InAppBrowserManager.swift    |  30 ++---
 .../InAppBrowserWebViewController.swift       |   4 +-
 .../ContextMenuSettings.swift                 |   0
 .../CustomSchemeHandler.swift}                |   2 +-
 .../FlutterWebViewController.swift            |   4 +-
 .../InAppWebView/FlutterWebViewFactory.swift  |   1 +
 ios/Classes/InAppWebView/InAppWebView.swift   |   2 +-
 ios/Classes/InAppWebViewStatic.swift          |  19 +--
 ios/Classes/MyCookieManager.swift             |  21 +---
 ios/Classes/MyWebStorageManager.swift         |  21 +---
 ios/Classes/PlatformUtil.swift                |  19 +--
 .../PullToRefreshChannelDelegate.swift        |  90 ++++++++++++++
 .../PullToRefresh/PullToRefreshControl.swift  |  66 ++---------
 .../ChromeSafariBrowserManager.swift          |  19 +--
 ios/Classes/SwiftFlutterPlugin.swift          |   2 +-
 ios/Classes/Types/ChannelDelegate.swift       |  27 +++++
 ios/Classes/Types/Disposable.swift            |  12 ++
 .../FlutterMethodCallDelegate.swift           |   0
 .../HttpAuthenticationChallenge.swift         |   0
 ios/Classes/Types/URLRequest.swift            |   7 +-
 ios/Storyboards/WebView.storyboard            |   4 +-
 lib/src/types/url_request.dart                |   2 +-
 42 files changed, 393 insertions(+), 351 deletions(-)
 delete mode 100755 android/src/main/java/com/pichillilorenzo/flutter_inappwebview/RequestPermissionHandler.java
 create mode 100644 ios/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift
 rename ios/Classes/{ => InAppWebView}/ContextMenuSettings.swift (100%)
 rename ios/Classes/{CustomeSchemeHandler.swift => InAppWebView/CustomSchemeHandler.swift} (96%)
 create mode 100644 ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift
 create mode 100644 ios/Classes/Types/ChannelDelegate.swift
 create mode 100644 ios/Classes/Types/Disposable.swift
 rename ios/Classes/{ => Types}/FlutterMethodCallDelegate.swift (100%)
 rename ios/Classes/{ => Types}/HttpAuthenticationChallenge.swift (100%)

diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java
index bc9a325b..86185543 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/FlutterWebViewFactory.java
@@ -13,6 +13,7 @@ import io.flutter.plugin.platform.PlatformView;
 import io.flutter.plugin.platform.PlatformViewFactory;
 
 public class FlutterWebViewFactory extends PlatformViewFactory {
+  public static final String VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview";
   private final InAppWebViewFlutterPlugin plugin;
 
   public FlutterWebViewFactory(final InAppWebViewFlutterPlugin plugin) {
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java
index 4fbbb1dd..55ef9ff4 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewFlutterPlugin.java
@@ -87,7 +87,7 @@ public class InAppWebViewFlutterPlugin implements FlutterPlugin, ActivityAware {
     chromeSafariBrowserManager = new ChromeSafariBrowserManager(this);
     flutterWebViewFactory = new FlutterWebViewFactory(this);
     platformViewRegistry.registerViewFactory(
-                    "com.pichillilorenzo/flutter_inappwebview", flutterWebViewFactory);
+            FlutterWebViewFactory.VIEW_TYPE_ID, flutterWebViewFactory);
 
     platformUtil = new PlatformUtil(this);
     inAppWebViewStatic = new InAppWebViewStatic(this);
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java
index 6b263e92..8fdcc4e8 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebViewStatic.java
@@ -12,7 +12,6 @@ import androidx.webkit.WebViewCompat;
 import androidx.webkit.WebViewFeature;
 
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.lang.reflect.Method;
 import java.util.HashMap;
@@ -24,7 +23,7 @@ import java.util.Set;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class InAppWebViewStatic extends ChannelDelegateImpl implements Disposable {
+public class InAppWebViewStatic extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "InAppWebViewStatic";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static";
   
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java
index adde338a..6dba0384 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyCookieManager.java
@@ -9,7 +9,6 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -23,10 +22,10 @@ import java.util.TimeZone;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class MyCookieManager extends ChannelDelegateImpl implements Disposable {
+public class MyCookieManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "MyCookieManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager";
-
+  @Nullable
   public static CookieManager cookieManager;
   @Nullable
   public InAppWebViewFlutterPlugin plugin;
@@ -305,5 +304,6 @@ public class MyCookieManager extends ChannelDelegateImpl implements Disposable {
   public void dispose() {
     super.dispose();
     plugin = null;
+    cookieManager = null;
   }
 }
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java
index 285fba54..b9ff890a 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/MyWebStorage.java
@@ -7,7 +7,6 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -17,10 +16,11 @@ import java.util.Map;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
+public class MyWebStorage extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "MyWebStorage";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager";
 
+  @Nullable
   public static WebStorage webStorageManager;
   @Nullable
   public InAppWebViewFlutterPlugin plugin;
@@ -38,15 +38,23 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
         getOrigins(result);
         break;
       case "deleteAllData":
-        webStorageManager.deleteAllData();
-        result.success(true);
+        if (webStorageManager == null) {
+          webStorageManager.deleteAllData();
+          result.success(true);
+        } else {
+          result.success(false);
+        }
         break;
       case "deleteOrigin":
         {
-          String origin = (String) call.argument("origin");
-          webStorageManager.deleteOrigin(origin);
+          if (webStorageManager == null) {
+            String origin = (String) call.argument("origin");
+            webStorageManager.deleteOrigin(origin);
+            result.success(true);
+          } else {
+            result.success(false);
+          }
         }
-        result.success(true);
         break;
       case "getQuotaForOrigin":
         {
@@ -57,7 +65,7 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
       case "getUsageForOrigin":
        {
           String origin = (String) call.argument("origin");
-         getUsageForOrigin(origin, result);
+          getUsageForOrigin(origin, result);
        }
        break;
       default:
@@ -66,6 +74,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
   }
 
   public void getOrigins(final MethodChannel.Result result) {
+    if (webStorageManager == null) {
+      result.success(new ArrayList<>());
+      return;
+    }
     webStorageManager.getOrigins(new ValueCallback<Map>() {
       @Override
       public void onReceiveValue(Map value) {
@@ -86,6 +98,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
   }
 
   public void getQuotaForOrigin(String origin, final MethodChannel.Result result) {
+    if (webStorageManager == null) {
+      result.success(0);
+      return;
+    }
     webStorageManager.getQuotaForOrigin(origin, new ValueCallback<Long>() {
       @Override
       public void onReceiveValue(Long value) {
@@ -95,6 +111,10 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
   }
 
   public void getUsageForOrigin(String origin, final MethodChannel.Result result) {
+    if (webStorageManager == null) {
+      result.success(0);
+      return;
+    }
     webStorageManager.getUsageForOrigin(origin, new ValueCallback<Long>() {
       @Override
       public void onReceiveValue(Long value) {
@@ -107,5 +127,6 @@ public class MyWebStorage extends ChannelDelegateImpl implements Disposable {
   public void dispose() {
     super.dispose();
     plugin = null;
+    webStorageManager = null;
   }
 }
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java
index 0437a2f1..8f42e701 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/PlatformUtil.java
@@ -6,7 +6,6 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -16,7 +15,7 @@ import java.util.TimeZone;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class PlatformUtil extends ChannelDelegateImpl implements Disposable {
+public class PlatformUtil extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "PlatformUtil";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil";
   
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/RequestPermissionHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/RequestPermissionHandler.java
deleted file mode 100755
index c1ca8fe3..00000000
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/RequestPermissionHandler.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.pichillilorenzo.flutter_inappwebview;
-
-import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public abstract class RequestPermissionHandler implements ActivityCompat.OnRequestPermissionsResultCallback {
-
-    private static Map<Integer, List<Runnable>> actionDictionary = new HashMap<>();
-
-    public static void checkAndRun(Activity activity, String permission, int requestCode, Runnable runnable) {
-
-        int permissionCheck = ContextCompat.checkSelfPermission(activity.getApplicationContext(), permission);
-
-        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
-            if (actionDictionary.containsKey(requestCode))
-                actionDictionary.get(requestCode).add(runnable);
-            else
-                actionDictionary.put(requestCode, Arrays.asList(runnable));
-            ActivityCompat.requestPermissions(activity, new String[]{permission}, requestCode);
-        }
-        else
-            runnable.run();
-    }
-
-    @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
-        if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
-            List<Runnable> callbacks = actionDictionary.get(requestCode);
-            for (Runnable runnable : callbacks) {
-                runnable.run();
-                callbacks.remove(runnable);
-            }
-        }
-    }
-
-}
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java
index 1df294b4..ac38dd94 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/WebViewFeatureManager.java
@@ -5,12 +5,11 @@ import androidx.annotation.Nullable;
 import androidx.webkit.WebViewFeature;
 
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class WebViewFeatureManager extends ChannelDelegateImpl implements Disposable {
+public class WebViewFeatureManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "WebViewFeatureManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webviewfeature";
 
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java
index 2af399ee..dca7150f 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/chrome_custom_tabs/ChromeSafariBrowserManager.java
@@ -9,7 +9,6 @@ import androidx.annotation.Nullable;
 import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
 import com.pichillilorenzo.flutter_inappwebview.Util;
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.io.Serializable;
 import java.util.HashMap;
@@ -20,7 +19,7 @@ import java.util.UUID;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class ChromeSafariBrowserManager extends ChannelDelegateImpl implements Disposable {
+public class ChromeSafariBrowserManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "ChromeBrowserManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser";
   
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java
index 851f0648..bb532a9e 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/credential_database/CredentialDatabaseHandler.java
@@ -9,7 +9,6 @@ import androidx.annotation.RequiresApi;
 
 import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 import com.pichillilorenzo.flutter_inappwebview.types.URLCredential;
 import com.pichillilorenzo.flutter_inappwebview.types.URLProtectionSpace;
 
@@ -22,10 +21,11 @@ import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
 @RequiresApi(api = Build.VERSION_CODES.O)
-public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Disposable {
+public class CredentialDatabaseHandler extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "CredentialDatabaseHandler";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database";
 
+  @Nullable
   public static CredentialDatabase credentialDatabase;
   @Nullable
   public InAppWebViewFlutterPlugin plugin;
@@ -42,80 +42,97 @@ public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Di
       case "getAllAuthCredentials":
         {
           List<Map<String, Object>> allCredentials = new ArrayList<>();
-          List<URLProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll();
-          for (URLProtectionSpace protectionSpace : protectionSpaces) {
-            List<Map<String, Object>> credentials = new ArrayList<>();
-            for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) {
-              credentials.add(credential.toMap());
+          if (credentialDatabase != null) {
+            List<URLProtectionSpace> protectionSpaces = credentialDatabase.protectionSpaceDao.getAll();
+            for (URLProtectionSpace protectionSpace : protectionSpaces) {
+              List<Map<String, Object>> credentials = new ArrayList<>();
+              for (URLCredential credential : credentialDatabase.credentialDao.getAllByProtectionSpaceId(protectionSpace.getId())) {
+                credentials.add(credential.toMap());
+              }
+              Map<String, Object> obj = new HashMap<>();
+              obj.put("protectionSpace", protectionSpace.toMap());
+              obj.put("credentials", credentials);
+              allCredentials.add(obj);
             }
-            Map<String, Object> obj = new HashMap<>();
-            obj.put("protectionSpace", protectionSpace.toMap());
-            obj.put("credentials", credentials);
-            allCredentials.add(obj);
           }
           result.success(allCredentials);
         }
         break;
       case "getHttpAuthCredentials":
         {
-          String host = (String) call.argument("host");
-          String protocol = (String) call.argument("protocol");
-          String realm = (String) call.argument("realm");
-          Integer port = (Integer) call.argument("port");
-
           List<Map<String, Object>> credentials = new ArrayList<>();
-          for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) {
-            credentials.add(credential.toMap());
+          if (credentialDatabase != null) {
+            String host = (String) call.argument("host");
+            String protocol = (String) call.argument("protocol");
+            String realm = (String) call.argument("realm");
+            Integer port = (Integer) call.argument("port");
+
+            for (URLCredential credential : credentialDatabase.getHttpAuthCredentials(host, protocol, realm, port)) {
+              credentials.add(credential.toMap());
+            }
           }
           result.success(credentials);
         }
         break;
       case "setHttpAuthCredential":
         {
-          String host = (String) call.argument("host");
-          String protocol = (String) call.argument("protocol");
-          String realm = (String) call.argument("realm");
-          Integer port = (Integer) call.argument("port");
-          String username = (String) call.argument("username");
-          String password = (String) call.argument("password");
+          if (credentialDatabase != null) {
+            String host = (String) call.argument("host");
+            String protocol = (String) call.argument("protocol");
+            String realm = (String) call.argument("realm");
+            Integer port = (Integer) call.argument("port");
+            String username = (String) call.argument("username");
+            String password = (String) call.argument("password");
 
-          credentialDatabase.setHttpAuthCredential(host, protocol, realm, port, username, password);
-
-          result.success(true);
+            credentialDatabase.setHttpAuthCredential(host, protocol, realm, port, username, password);
+            result.success(true);
+          } else {
+            result.success(false);
+          }
         }
         break;
       case "removeHttpAuthCredential":
         {
-          String host = (String) call.argument("host");
-          String protocol = (String) call.argument("protocol");
-          String realm = (String) call.argument("realm");
-          Integer port = (Integer) call.argument("port");
-          String username = (String) call.argument("username");
-          String password = (String) call.argument("password");
+          if (credentialDatabase != null) {
+            String host = (String) call.argument("host");
+            String protocol = (String) call.argument("protocol");
+            String realm = (String) call.argument("realm");
+            Integer port = (Integer) call.argument("port");
+            String username = (String) call.argument("username");
+            String password = (String) call.argument("password");
 
-          credentialDatabase.removeHttpAuthCredential(host, protocol, realm, port, username, password);
-
-          result.success(true);
+            credentialDatabase.removeHttpAuthCredential(host, protocol, realm, port, username, password);
+            result.success(true);
+          } else {
+            result.success(false);
+          }
         }
         break;
       case "removeHttpAuthCredentials":
         {
-          String host = (String) call.argument("host");
-          String protocol = (String) call.argument("protocol");
-          String realm = (String) call.argument("realm");
-          Integer port = (Integer) call.argument("port");
+          if (credentialDatabase != null) {
+            String host = (String) call.argument("host");
+            String protocol = (String) call.argument("protocol");
+            String realm = (String) call.argument("realm");
+            Integer port = (Integer) call.argument("port");
 
-          credentialDatabase.removeHttpAuthCredentials(host, protocol, realm, port);
-
-          result.success(true);
+            credentialDatabase.removeHttpAuthCredentials(host, protocol, realm, port);
+            result.success(true);
+          } else {
+            result.success(false);
+          }
         }
         break;
       case "clearAllAuthCredentials":
-        credentialDatabase.clearAllAuthCredentials();
-        if (plugin != null && plugin.applicationContext != null) {
-          WebViewDatabase.getInstance(plugin.applicationContext).clearHttpAuthUsernamePassword();
+        if (credentialDatabase != null) {
+          credentialDatabase.clearAllAuthCredentials();
+          if (plugin != null && plugin.applicationContext != null) {
+            WebViewDatabase.getInstance(plugin.applicationContext).clearHttpAuthUsernamePassword();
+          }
+          result.success(true);
+        } else {
+          result.success(false);
         }
-        result.success(true);
         break;
       default:
         result.notImplemented();
@@ -126,5 +143,6 @@ public class CredentialDatabaseHandler extends ChannelDelegateImpl implements Di
   public void dispose() {
     super.dispose();
     plugin = null;
+    credentialDatabase = null;
   }
 }
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java
index eeb9183b..62409008 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/headless_in_app_webview/HeadlessInAppWebViewManager.java
@@ -27,7 +27,6 @@ import androidx.annotation.NonNull;
 import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
 import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.FlutterWebView;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -37,7 +36,7 @@ import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 import io.flutter.plugin.common.MethodChannel.Result;
 
-public class HeadlessInAppWebViewManager extends ChannelDelegateImpl implements Disposable {
+public class HeadlessInAppWebViewManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "HeadlessInAppWebViewManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview";
   
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java
index 0e73319c..189ed20d 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java
@@ -37,7 +37,6 @@ import androidx.annotation.Nullable;
 
 import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -53,7 +52,7 @@ import io.flutter.plugin.common.MethodChannel.Result;
 /**
  * InAppBrowserManager
  */
-public class InAppBrowserManager extends ChannelDelegateImpl implements Disposable {
+public class InAppBrowserManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "InAppBrowserManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser";
   
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java
index 2d49f1c8..261fdecb 100755
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/proxy/ProxyManager.java
@@ -8,7 +8,6 @@ import androidx.webkit.WebViewFeature;
 
 import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin;
 import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl;
-import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
 import com.pichillilorenzo.flutter_inappwebview.types.ProxyRuleExt;
 
 import java.util.HashMap;
@@ -17,7 +16,7 @@ import java.util.concurrent.Executor;
 import io.flutter.plugin.common.MethodCall;
 import io.flutter.plugin.common.MethodChannel;
 
-public class ProxyManager extends ChannelDelegateImpl implements Disposable {
+public class ProxyManager extends ChannelDelegateImpl {
   protected static final String LOG_TAG = "ProxyManager";
   public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_proxycontroller";
 
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java
index 3de75d6f..b050788a 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/IChannelDelegate.java
@@ -4,8 +4,7 @@ import androidx.annotation.Nullable;
 
 import io.flutter.plugin.common.MethodChannel;
 
-public interface IChannelDelegate extends MethodChannel.MethodCallHandler {
+public interface IChannelDelegate extends MethodChannel.MethodCallHandler, Disposable {
   @Nullable
   MethodChannel getChannel();
-  void dispose();
 }
diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/URLRequest.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/URLRequest.java
index 313c78f2..dd156a5d 100644
--- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/URLRequest.java
+++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/URLRequest.java
@@ -1,6 +1,5 @@
 package com.pichillilorenzo.flutter_inappwebview.types;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import java.util.Arrays;
@@ -8,7 +7,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 public class URLRequest {
-  @NonNull
+  @Nullable
   private String url;
   @Nullable
   private String method;
@@ -17,7 +16,7 @@ public class URLRequest {
   @Nullable
   private Map<String, String> headers;
 
-  public URLRequest(@NonNull String url, @Nullable String method, @Nullable byte[] body, @Nullable Map<String, String> headers) {
+  public URLRequest(@Nullable String url, @Nullable String method, @Nullable byte[] body, @Nullable Map<String, String> headers) {
     this.url = url;
     this.method = method;
     this.body = body;
@@ -30,10 +29,12 @@ public class URLRequest {
       return null;
     }
     String url = (String) map.get("url");
+    if (url == null) {
+      url = "about:blank";
+    }
     String method = (String) map.get("method");
     byte[] body = (byte[]) map.get("body");
     Map<String, String> headers = (Map<String, String>) map.get("headers");
-    assert url != null;
     return new URLRequest(url, method, body, headers);
   }
 
@@ -55,12 +56,12 @@ public class URLRequest {
     return urlRequestMap;
   }
 
-  @NonNull
+  @Nullable
   public String getUrl() {
     return url;
   }
 
-  public void setUrl(@NonNull String url) {
+  public void setUrl(@Nullable String url) {
     this.url = url;
   }
 
@@ -98,7 +99,7 @@ public class URLRequest {
 
     URLRequest that = (URLRequest) o;
 
-    if (!url.equals(that.url)) return false;
+    if (url != null ? !url.equals(that.url) : that.url != null) return false;
     if (method != null ? !method.equals(that.method) : that.method != null) return false;
     if (!Arrays.equals(body, that.body)) return false;
     return headers != null ? headers.equals(that.headers) : that.headers == null;
@@ -106,7 +107,7 @@ public class URLRequest {
 
   @Override
   public int hashCode() {
-    int result = url.hashCode();
+    int result = url != null ? url.hashCode() : 0;
     result = 31 * result + (method != null ? method.hashCode() : 0);
     result = 31 * result + Arrays.hashCode(body);
     result = 31 * result + (headers != null ? headers.hashCode() : 0);
diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh
index dad54015..9e98dd5e 100755
--- a/example/ios/Flutter/flutter_export_environment.sh
+++ b/example/ios/Flutter/flutter_export_environment.sh
@@ -3,11 +3,12 @@
 export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4"
 export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
 export "COCOAPODS_PARALLEL_CODE_SIGN=true"
-export "FLUTTER_TARGET=lib/main.dart"
+export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart"
 export "FLUTTER_BUILD_DIR=build"
 export "FLUTTER_BUILD_NAME=1.0.0"
 export "FLUTTER_BUILD_NUMBER=1"
+export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
 export "DART_OBFUSCATION=false"
-export "TRACK_WIDGET_CREATION=false"
+export "TRACK_WIDGET_CREATION=true"
 export "TREE_SHAKE_ICONS=false"
-export "PACKAGE_CONFIG=.packages"
+export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json"
diff --git a/ios/Classes/CredentialDatabase.swift b/ios/Classes/CredentialDatabase.swift
index 5bfb1e64..42c88425 100755
--- a/ios/Classes/CredentialDatabase.swift
+++ b/ios/Classes/CredentialDatabase.swift
@@ -7,26 +7,18 @@
 
 import Foundation
 
-class CredentialDatabase: NSObject, FlutterPlugin {
-
+class CredentialDatabase: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     static var credentialStore: URLCredentialStorage?
 
-    static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         CredentialDatabase.registrar = registrar
         CredentialDatabase.credentialStore = URLCredentialStorage.shared
-        
-        CredentialDatabase.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_credential_database", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: CredentialDatabase.channel!)
     }
 
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         switch call.method {
             case "getAllAuthCredentials":
@@ -196,9 +188,8 @@ class CredentialDatabase: NSObject, FlutterPlugin {
         }
     }
     
-    public func dispose() {
-        CredentialDatabase.channel?.setMethodCallHandler(nil)
-        CredentialDatabase.channel = nil
+    public override func dispose() {
+        super.dispose()
         CredentialDatabase.registrar = nil
         CredentialDatabase.credentialStore = nil
     }
diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift
index 55b65d9a..d688f50f 100644
--- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift
+++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift
@@ -7,47 +7,22 @@
 
 import Foundation
 
-public class HeadlessInAppWebView : FlutterMethodCallDelegate {
+public class HeadlessInAppWebView : Disposable {
+    static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_headless_inappwebview_"
     var id: String
-    var channel: FlutterMethodChannel?
+    var channelDelegate: HeadlessWebViewChannelDelegate?
     var flutterWebView: FlutterWebViewController?
     
     public init(id: String, flutterWebView: FlutterWebViewController) {
         self.id = id
-        super.init()
         self.flutterWebView = flutterWebView
-        self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_headless_inappwebview_" + id,
+        let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id,
                                        binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
-        self.channel?.setMethodCallHandler(self.handle)
-    }
-    
-    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
-        let arguments = call.arguments as? NSDictionary
-        
-        switch call.method {
-        case "dispose":
-            dispose()
-            result(true)
-            break
-        case "setSize":
-            let sizeMap = arguments!["size"] as? [String: Any?]
-            if let size = Size2D.fromMap(map: sizeMap) {
-                setSize(size: size)
-            }
-            result(true)
-            break
-        case "getSize":
-            result(getSize()?.toMap())
-            break
-        default:
-            result(FlutterMethodNotImplemented)
-            break
-        }
+        self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel)
     }
     
     public func onWebViewCreated() {
-        let arguments: [String: Any?] = [:]
-        channel?.invokeMethod("onWebViewCreated", arguments: arguments)
+        channelDelegate?.onWebViewCreated();
     }
     
     public func prepare(params: NSDictionary) {
@@ -87,8 +62,8 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate {
     }
     
     public func dispose() {
-        channel?.setMethodCallHandler(nil)
-        channel = nil
+        channelDelegate?.dispose()
+        channelDelegate = nil
         HeadlessInAppWebViewManager.webViews[id] = nil
         flutterWebView = nil
     }
diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift
index 97e808a0..e884ecb2 100644
--- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift
+++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift
@@ -13,23 +13,17 @@ import WebKit
 import Foundation
 import AVFoundation
 
-public class HeadlessInAppWebViewManager: NSObject, FlutterPlugin {
+public class HeadlessInAppWebViewManager: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     static var webViews: [String: HeadlessInAppWebView?] = [:]
     
-    public static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         HeadlessInAppWebViewManager.registrar = registrar
-        HeadlessInAppWebViewManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_headless_inappwebview", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: HeadlessInAppWebViewManager.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         let id: String = arguments!["id"] as! String
 
@@ -58,9 +52,8 @@ public class HeadlessInAppWebViewManager: NSObject, FlutterPlugin {
         flutterWebView.makeInitialLoad(params: params as NSDictionary)
     }
     
-    public func dispose() {
-        HeadlessInAppWebViewManager.channel?.setMethodCallHandler(nil)
-        HeadlessInAppWebViewManager.channel = nil
+    public override func dispose() {
+        super.dispose()
         HeadlessInAppWebViewManager.registrar = nil
         let headlessWebViews = HeadlessInAppWebViewManager.webViews.values
         headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in
diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift b/ios/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift
new file mode 100644
index 00000000..e6f151c1
--- /dev/null
+++ b/ios/Classes/HeadlessInAppWebView/HeadlessWebViewChannelDelegate.swift
@@ -0,0 +1,59 @@
+//
+//  HeadlessWebViewChannelDelegate.swift
+//  flutter_inappwebview
+//
+//  Created by Lorenzo Pichilli on 05/05/22.
+//
+
+import Foundation
+
+public class HeadlessWebViewChannelDelegate : ChannelDelegate {
+    private var headlessWebView: HeadlessInAppWebView?
+
+    public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) {
+        super.init(channel: channel)
+        self.headlessWebView = headlessWebView
+    }
+
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+        let arguments = call.arguments as? NSDictionary
+        
+        switch call.method {
+        case "dispose":
+            if let headlessWebView = headlessWebView {
+                headlessWebView.dispose()
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "setSize":
+            if let headlessWebView = headlessWebView {
+                let sizeMap = arguments!["size"] as? [String: Any?]
+                if let size = Size2D.fromMap(map: sizeMap) {
+                    headlessWebView.setSize(size: size)
+                }
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "getSize":
+            result(headlessWebView?.getSize()?.toMap())
+            break
+        default:
+            result(FlutterMethodNotImplemented)
+            break
+        }
+    }
+
+    public func onWebViewCreated() {
+        let arguments: [String: Any?] = [:]
+        channel?.invokeMethod("onWebViewCreated", arguments: arguments)
+    }
+
+    public override func dispose() {
+        super.dispose()
+        headlessWebView = nil
+    }
+  }
diff --git a/ios/Classes/InAppBrowser/InAppBrowserManager.swift b/ios/Classes/InAppBrowser/InAppBrowserManager.swift
index 4f89ffdf..8dd465eb 100755
--- a/ios/Classes/InAppBrowser/InAppBrowserManager.swift
+++ b/ios/Classes/InAppBrowser/InAppBrowserManager.swift
@@ -11,28 +11,21 @@ import WebKit
 import Foundation
 import AVFoundation
 
-let WEBVIEW_STORYBOARD = "WebView"
-let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
-let NAV_STORYBOARD_CONTROLLER_ID = "navController"
-
-public class InAppBrowserManager: NSObject, FlutterPlugin {
+public class InAppBrowserManager: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappbrowser"
+    static let WEBVIEW_STORYBOARD = "WebView"
+    static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController"
+    static let NAV_STORYBOARD_CONTROLLER_ID = "navController"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     
     private var previousStatusBarStyle = -1
     
-    public static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         InAppBrowserManager.registrar = registrar
-        InAppBrowserManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: InAppBrowserManager.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
 
         switch call.method {
@@ -100,8 +93,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
     }
     
     public func presentViewController(webViewController: InAppBrowserWebViewController) {
-        let storyboard = UIStoryboard(name: WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
-        let navController = storyboard.instantiateViewController(withIdentifier: NAV_STORYBOARD_CONTROLLER_ID) as! InAppBrowserNavigationController
+        let storyboard = UIStoryboard(name: InAppBrowserManager.WEBVIEW_STORYBOARD, bundle: Bundle(for: InAppWebViewFlutterPlugin.self))
+        let navController = storyboard.instantiateViewController(withIdentifier: InAppBrowserManager.NAV_STORYBOARD_CONTROLLER_ID) as! InAppBrowserNavigationController
         webViewController.edgesForExtendedLayout = []
         navController.pushViewController(webViewController, animated: false)
         webViewController.prepareNavigationControllerBeforeViewWillAppear()
@@ -141,9 +134,8 @@ public class InAppBrowserManager: NSObject, FlutterPlugin {
         result(true)
     }
     
-    public func dispose() {
-        InAppBrowserManager.channel?.setMethodCallHandler(nil)
-        InAppBrowserManager.channel = nil
+    public override func dispose() {
+        super.dispose()
         InAppBrowserManager.registrar = nil
     }
 }
diff --git a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift
index ecc7499c..7c840c27 100755
--- a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift
+++ b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift
@@ -65,11 +65,9 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
         methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
         channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
         
-        let pullToRefreshLayoutChannel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + id,
-                                                              binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
         let pullToRefreshSettings = PullToRefreshSettings()
         let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
-        let pullToRefreshControl = PullToRefreshControl(channel: pullToRefreshLayoutChannel, settings: pullToRefreshSettings)
+        let pullToRefreshControl = PullToRefreshControl(registrar: SwiftFlutterPlugin.instance!.registrar!, id: id, settings: pullToRefreshSettings)
         webView.pullToRefreshControl = pullToRefreshControl
         pullToRefreshControl.delegate = webView
         pullToRefreshControl.prepare()
diff --git a/ios/Classes/ContextMenuSettings.swift b/ios/Classes/InAppWebView/ContextMenuSettings.swift
similarity index 100%
rename from ios/Classes/ContextMenuSettings.swift
rename to ios/Classes/InAppWebView/ContextMenuSettings.swift
diff --git a/ios/Classes/CustomeSchemeHandler.swift b/ios/Classes/InAppWebView/CustomSchemeHandler.swift
similarity index 96%
rename from ios/Classes/CustomeSchemeHandler.swift
rename to ios/Classes/InAppWebView/CustomSchemeHandler.swift
index a1121e33..072779af 100755
--- a/ios/Classes/CustomeSchemeHandler.swift
+++ b/ios/Classes/InAppWebView/CustomSchemeHandler.swift
@@ -10,7 +10,7 @@ import Foundation
 import WebKit
 
 @available(iOS 11.0, *)
-class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
+class CustomSchemeHandler : NSObject, WKURLSchemeHandler {
     var schemeHandlers: [Int:WKURLSchemeTask] = [:]
     
     func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
diff --git a/ios/Classes/InAppWebView/FlutterWebViewController.swift b/ios/Classes/InAppWebView/FlutterWebViewController.swift
index 0d2f0c41..8827eee2 100755
--- a/ios/Classes/InAppWebView/FlutterWebViewController.swift
+++ b/ios/Classes/InAppWebView/FlutterWebViewController.swift
@@ -63,11 +63,9 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
         methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
         channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
         
-        let pullToRefreshLayoutChannel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_" + String(describing: viewId),
-                                                              binaryMessenger: registrar.messenger())
         let pullToRefreshSettings = PullToRefreshSettings()
         let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
-        let pullToRefreshControl = PullToRefreshControl(channel: pullToRefreshLayoutChannel, settings: pullToRefreshSettings)
+        let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings)
         webView!.pullToRefreshControl = pullToRefreshControl
         pullToRefreshControl.delegate = webView!
         pullToRefreshControl.prepare()
diff --git a/ios/Classes/InAppWebView/FlutterWebViewFactory.swift b/ios/Classes/InAppWebView/FlutterWebViewFactory.swift
index 30fcce52..2e202510 100755
--- a/ios/Classes/InAppWebView/FlutterWebViewFactory.swift
+++ b/ios/Classes/InAppWebView/FlutterWebViewFactory.swift
@@ -9,6 +9,7 @@ import Flutter
 import Foundation
 
 public class FlutterWebViewFactory: NSObject, FlutterPlatformViewFactory {
+    static let VIEW_TYPE_ID = "com.pichillilorenzo/flutter_inappwebview"
     private var registrar: FlutterPluginRegistrar?
     
     init(registrar: FlutterPluginRegistrar?) {
diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift
index 98c311bf..c030af3c 100755
--- a/ios/Classes/InAppWebView/InAppWebView.swift
+++ b/ios/Classes/InAppWebView/InAppWebView.swift
@@ -565,7 +565,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
             
             if #available(iOS 11.0, *) {
                 for scheme in settings.resourceCustomSchemes {
-                    configuration.setURLSchemeHandler(CustomeSchemeHandler(), forURLScheme: scheme)
+                    configuration.setURLSchemeHandler(CustomSchemeHandler(), forURLScheme: scheme)
                 }
                 if settings.sharedCookiesEnabled {
                     // More info to sending cookies with WKWebView
diff --git a/ios/Classes/InAppWebViewStatic.swift b/ios/Classes/InAppWebViewStatic.swift
index 58e5f874..3f0dfbc5 100755
--- a/ios/Classes/InAppWebViewStatic.swift
+++ b/ios/Classes/InAppWebViewStatic.swift
@@ -8,24 +8,18 @@
 import Foundation
 import WebKit
 
-class InAppWebViewStatic: NSObject, FlutterPlugin {
+class InAppWebViewStatic: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     static var webViewForUserAgent: WKWebView?
     static var defaultUserAgent: String?
     
-    static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         InAppWebViewStatic.registrar = registrar
-        InAppWebViewStatic.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_static", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: InAppWebViewStatic.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         
         switch call.method {
@@ -73,9 +67,8 @@ class InAppWebViewStatic: NSObject, FlutterPlugin {
         }
     }
     
-    public func dispose() {
-        InAppWebViewStatic.channel?.setMethodCallHandler(nil)
-        InAppWebViewStatic.channel = nil
+    public override func dispose() {
+        super.dispose()
         InAppWebViewStatic.registrar = nil
         InAppWebViewStatic.webViewForUserAgent = nil
         InAppWebViewStatic.defaultUserAgent = nil
diff --git a/ios/Classes/MyCookieManager.swift b/ios/Classes/MyCookieManager.swift
index 1f892d87..04cf7626 100755
--- a/ios/Classes/MyCookieManager.swift
+++ b/ios/Classes/MyCookieManager.swift
@@ -9,26 +9,18 @@ import Foundation
 import WebKit
 
 @available(iOS 11.0, *)
-class MyCookieManager: NSObject, FlutterPlugin {
-
+class MyCookieManager: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     static var httpCookieStore: WKHTTPCookieStore?
     
-    static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         MyCookieManager.registrar = registrar
         MyCookieManager.httpCookieStore = WKWebsiteDataStore.default().httpCookieStore
-        
-        MyCookieManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_cookiemanager", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: MyCookieManager.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         switch call.method {
             case "setCookie":
@@ -298,9 +290,8 @@ class MyCookieManager: NSObject, FlutterPlugin {
         })
     }
     
-    public func dispose() {
-        MyCookieManager.channel?.setMethodCallHandler(nil)
-        MyCookieManager.channel = nil
+    public override func dispose() {
+        super.dispose()
         MyCookieManager.registrar = nil
         MyCookieManager.httpCookieStore = nil
     }
diff --git a/ios/Classes/MyWebStorageManager.swift b/ios/Classes/MyWebStorageManager.swift
index 426f30e5..0b5eca8f 100755
--- a/ios/Classes/MyWebStorageManager.swift
+++ b/ios/Classes/MyWebStorageManager.swift
@@ -9,26 +9,18 @@ import Foundation
 import WebKit
 
 @available(iOS 9.0, *)
-class MyWebStorageManager: NSObject, FlutterPlugin {
-
+class MyWebStorageManager: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
     static var websiteDataStore: WKWebsiteDataStore?
     
-    static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         MyWebStorageManager.registrar = registrar
         MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default()
-        
-        MyWebStorageManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_webstoragemanager", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: MyWebStorageManager.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         switch call.method {
             case "fetchDataRecords":
@@ -108,9 +100,8 @@ class MyWebStorageManager: NSObject, FlutterPlugin {
         }
     }
     
-    public func dispose() {
-        MyWebStorageManager.channel?.setMethodCallHandler(nil)
-        MyWebStorageManager.channel = nil
+    public override func dispose() {
+        super.dispose()
         MyWebStorageManager.registrar = nil
         MyWebStorageManager.websiteDataStore = nil
     }
diff --git a/ios/Classes/PlatformUtil.swift b/ios/Classes/PlatformUtil.swift
index 0bf29b40..0f3afbec 100644
--- a/ios/Classes/PlatformUtil.swift
+++ b/ios/Classes/PlatformUtil.swift
@@ -7,22 +7,16 @@
 
 import Foundation
 
-class PlatformUtil: NSObject, FlutterPlugin {
+class PlatformUtil: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
-    
-    static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
     
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         InAppWebViewStatic.registrar = registrar
-        InAppWebViewStatic.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_platformutil", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: InAppWebViewStatic.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
         
         switch call.method {
@@ -61,9 +55,8 @@ class PlatformUtil: NSObject, FlutterPlugin {
         return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date))
     }
     
-    public func dispose() {
-        PlatformUtil.channel?.setMethodCallHandler(nil)
-        PlatformUtil.channel = nil
+    public override func dispose() {
+        super.dispose()
         PlatformUtil.registrar = nil
     }
 }
diff --git a/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift b/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift
new file mode 100644
index 00000000..df33c16a
--- /dev/null
+++ b/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift
@@ -0,0 +1,90 @@
+//
+//  PullToRefreshChannelDelegate.swift
+//  flutter_inappwebview
+//
+//  Created by Lorenzo Pichilli on 05/05/22.
+//
+
+import Foundation
+
+public class PullToRefreshChannelDelegate : ChannelDelegate {
+    private var pullToRefreshControl: PullToRefreshControl?
+    
+    public init(pullToRefreshControl: PullToRefreshControl , channel: FlutterMethodChannel) {
+        super.init(channel: channel)
+        self.pullToRefreshControl = pullToRefreshControl
+    }
+    
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+        let arguments = call.arguments as? NSDictionary
+        
+        switch call.method {
+        case "setEnabled":
+            if let pullToRefreshView = pullToRefreshControl {
+                let enabled = arguments!["enabled"] as! Bool
+                if enabled {
+                    pullToRefreshView.delegate?.enablePullToRefresh()
+                } else {
+                    pullToRefreshView.delegate?.disablePullToRefresh()
+                }
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "setRefreshing":
+            if let pullToRefreshView = pullToRefreshControl {
+                let refreshing = arguments!["refreshing"] as! Bool
+                if refreshing {
+                    pullToRefreshView.beginRefreshing()
+                } else {
+                    pullToRefreshView.endRefreshing()
+                }
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "setColor":
+            if let pullToRefreshView = pullToRefreshControl {
+                let color = arguments!["color"] as! String
+                pullToRefreshView.tintColor = UIColor(hexString: color)
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "setBackgroundColor":
+            if let pullToRefreshView = pullToRefreshControl {
+                let color = arguments!["color"] as! String
+                pullToRefreshView.backgroundColor = UIColor(hexString: color)
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        case "setStyledTitle":
+            if let pullToRefreshView = pullToRefreshControl {
+                let attributedTitleMap = arguments!["attributedTitle"] as! [String: Any?]
+                pullToRefreshView.attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
+                result(true)
+            } else {
+                result(false)
+            }
+            break
+        default:
+            result(FlutterMethodNotImplemented)
+            break
+        }
+    }
+    
+    public func onRefresh() {
+        let arguments: [String: Any?] = [:]
+        channel?.invokeMethod("onRefresh", arguments: arguments)
+    }
+    
+    public override func dispose() {
+        super.dispose()
+        pullToRefreshControl = nil
+    }
+}
diff --git a/ios/Classes/PullToRefresh/PullToRefreshControl.swift b/ios/Classes/PullToRefresh/PullToRefreshControl.swift
index fb808d4b..f2583988 100644
--- a/ios/Classes/PullToRefresh/PullToRefreshControl.swift
+++ b/ios/Classes/PullToRefresh/PullToRefreshControl.swift
@@ -8,29 +8,26 @@
 import Foundation
 import Flutter
 
-public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
-    
-    var channel: FlutterMethodChannel?
+public class PullToRefreshControl : UIRefreshControl, Disposable {
+    static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_pull_to_refresh_";
+    var channelDelegate: PullToRefreshChannelDelegate?
     var settings: PullToRefreshSettings?
     var shouldCallOnRefresh = false
     var delegate: PullToRefreshDelegate?
     
-    public init(channel: FlutterMethodChannel?, settings: PullToRefreshSettings?) {
+    public init(registrar: FlutterPluginRegistrar, id: Any, settings: PullToRefreshSettings?) {
         super.init()
-        self.channel = channel
         self.settings = settings
+        let channel = FlutterMethodChannel(name: PullToRefreshControl.METHOD_CHANNEL_NAME_PREFIX + String(describing: id),
+                                           binaryMessenger: registrar.messenger())
+        self.channelDelegate = PullToRefreshChannelDelegate(pullToRefreshControl: self, channel: channel)
     }
     
     required init?(coder: NSCoder) {
         super.init(coder: coder)
     }
     
-    public static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
-    
     public func prepare() {
-        self.channel?.setMethodCallHandler(self.handle)
         if let options = settings {
             if options.enabled {
                 delegate?.enablePullToRefresh()
@@ -48,53 +45,9 @@ public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
         addTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
-        let arguments = call.arguments as? NSDictionary
-        
-        switch call.method {
-        case "setEnabled":
-            let enabled = arguments!["enabled"] as! Bool
-            if enabled {
-                delegate?.enablePullToRefresh()
-            } else {
-                delegate?.disablePullToRefresh()
-            }
-            result(true)
-            break
-        case "setRefreshing":
-            let refreshing = arguments!["refreshing"] as! Bool
-            if refreshing {
-                self.beginRefreshing()
-            } else {
-                self.endRefreshing()
-            }
-            result(true)
-            break
-        case "setColor":
-            let color = arguments!["color"] as! String
-            tintColor = UIColor(hexString: color)
-            result(true)
-            break
-        case "setBackgroundColor":
-            let color = arguments!["color"] as! String
-            backgroundColor = UIColor(hexString: color)
-            result(true)
-            break
-        case "setStyledTitle":
-            let attributedTitleMap = arguments!["attributedTitle"] as! [String: Any?]
-            attributedTitle = NSAttributedString.fromMap(map: attributedTitleMap)
-            result(true)
-            break
-        default:
-            result(FlutterMethodNotImplemented)
-            break
-        }
-    }
-    
     public func onRefresh() {
         shouldCallOnRefresh = false
-        let arguments: [String: Any?] = [:]
-        self.channel?.invokeMethod("onRefresh", arguments: arguments)
+        channelDelegate?.onRefresh()
     }
     
     @objc public func updateShouldCallOnRefresh() {
@@ -102,7 +55,8 @@ public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
     }
     
     public func dispose() {
-        channel?.setMethodCallHandler(nil)
+        channelDelegate?.dispose()
+        channelDelegate = nil
         removeTarget(self, action: #selector(updateShouldCallOnRefresh), for: .valueChanged)
         delegate = nil
     }
diff --git a/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift b/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift
index f157f3ec..46bb65ea 100755
--- a/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift
+++ b/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift
@@ -12,22 +12,16 @@ import Foundation
 import AVFoundation
 import SafariServices
 
-public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
+public class ChromeSafariBrowserManager: ChannelDelegate {
+    static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser"
     static var registrar: FlutterPluginRegistrar?
-    static var channel: FlutterMethodChannel?
-    
-    public static func register(with registrar: FlutterPluginRegistrar) {
-        
-    }
     
     init(registrar: FlutterPluginRegistrar) {
-        super.init()
+        super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger()))
         ChromeSafariBrowserManager.registrar = registrar
-        ChromeSafariBrowserManager.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_chromesafaribrowser", binaryMessenger: registrar.messenger())
-        registrar.addMethodCallDelegate(self, channel: ChromeSafariBrowserManager.channel!)
     }
     
-    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
         let arguments = call.arguments as? NSDictionary
 
         switch call.method {
@@ -92,9 +86,8 @@ public class ChromeSafariBrowserManager: NSObject, FlutterPlugin {
         result(FlutterError.init(code: "ChromeSafariBrowserManager", message: "SafariViewController is not available!", details: nil))
     }
     
-    public func dispose() {
-        ChromeSafariBrowserManager.channel?.setMethodCallHandler(nil)
-        ChromeSafariBrowserManager.channel = nil
+    public override func dispose() {
+        super.dispose()
         ChromeSafariBrowserManager.registrar = nil
     }
 }
diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift
index 75631fac..e5fbe685 100755
--- a/ios/Classes/SwiftFlutterPlugin.swift
+++ b/ios/Classes/SwiftFlutterPlugin.swift
@@ -42,7 +42,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
         super.init()
         
         self.registrar = registrar
-        registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: "com.pichillilorenzo/flutter_inappwebview")
+        registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID)
         
         platformUtil = PlatformUtil(registrar: registrar)
         inAppBrowserManager = InAppBrowserManager(registrar: registrar)
diff --git a/ios/Classes/Types/ChannelDelegate.swift b/ios/Classes/Types/ChannelDelegate.swift
new file mode 100644
index 00000000..c451b4b9
--- /dev/null
+++ b/ios/Classes/Types/ChannelDelegate.swift
@@ -0,0 +1,27 @@
+//
+//  ChannelDelegate.swift
+//  flutter_inappwebview
+//
+//  Created by Lorenzo Pichilli on 04/05/22.
+//
+
+import Foundation
+
+public class ChannelDelegate : FlutterMethodCallDelegate, Disposable {
+    var channel: FlutterMethodChannel?
+    
+    public init(channel: FlutterMethodChannel) {
+        super.init()
+        self.channel = channel
+        self.channel?.setMethodCallHandler(handle)
+    }
+    
+    public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+        
+    }
+    
+    public func dispose() {
+        channel?.setMethodCallHandler(nil)
+        channel = nil
+    }
+}
diff --git a/ios/Classes/Types/Disposable.swift b/ios/Classes/Types/Disposable.swift
new file mode 100644
index 00000000..0a34a942
--- /dev/null
+++ b/ios/Classes/Types/Disposable.swift
@@ -0,0 +1,12 @@
+//
+//  Disposable.swift
+//  flutter_inappwebview
+//
+//  Created by Lorenzo Pichilli on 04/05/22.
+//
+
+import Foundation
+
+public protocol Disposable {
+    func dispose() -> Void
+}
diff --git a/ios/Classes/FlutterMethodCallDelegate.swift b/ios/Classes/Types/FlutterMethodCallDelegate.swift
similarity index 100%
rename from ios/Classes/FlutterMethodCallDelegate.swift
rename to ios/Classes/Types/FlutterMethodCallDelegate.swift
diff --git a/ios/Classes/HttpAuthenticationChallenge.swift b/ios/Classes/Types/HttpAuthenticationChallenge.swift
similarity index 100%
rename from ios/Classes/HttpAuthenticationChallenge.swift
rename to ios/Classes/Types/HttpAuthenticationChallenge.swift
diff --git a/ios/Classes/Types/URLRequest.swift b/ios/Classes/Types/URLRequest.swift
index 1b41a991..701a4233 100644
--- a/ios/Classes/Types/URLRequest.swift
+++ b/ios/Classes/Types/URLRequest.swift
@@ -9,8 +9,11 @@ import Foundation
 
 extension URLRequest {
     public init(fromPluginMap: [String:Any?]) {
-        let url = fromPluginMap["url"] as! String
-        self.init(url: URL(string: url)!)
+        if let urlString = fromPluginMap["url"] as? String, let url = URL(string: urlString) {
+            self.init(url: url)
+        } else {
+            self.init(url: URL(string: "about:blank")!)
+        }
         
         if let method = fromPluginMap["method"] as? String {
             httpMethod = method
diff --git a/ios/Storyboards/WebView.storyboard b/ios/Storyboards/WebView.storyboard
index 8b733683..9c71b050 100755
--- a/ios/Storyboards/WebView.storyboard
+++ b/ios/Storyboards/WebView.storyboard
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina5_5" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment version="2048" identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
diff --git a/lib/src/types/url_request.dart b/lib/src/types/url_request.dart
index 74e29c54..3d76ea6f 100644
--- a/lib/src/types/url_request.dart
+++ b/lib/src/types/url_request.dart
@@ -4,7 +4,7 @@ import 'url_request_network_service_type.dart';
 
 ///A URL load request that is independent of protocol or URL scheme.
 class URLRequest {
-  ///The URL of the request.
+  ///The URL of the request. Setting this to `null` will load `about:blank`.
   Uri? url;
 
   ///The HTTP request method.