[webview_flutter_android] Fixes crash when the Java `InstanceManager` was used after plugin was removed from engine (#6943)

* dont throw errors on all instance manager methods

* tests

* version bump

* change to logging a warning and ignore calls in other methods

* the

* documentation
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index d45e735..37abf3c 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.1.3
+
+* Fixes crash when the Java `InstanceManager` was used after plugin was removed from the engine.
+
 ## 3.1.2
 
 * Fixes bug where an `AndroidWebViewController` couldn't be reused with a new `WebViewWidget`.
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java
index fefd577..55775a9 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/InstanceManager.java
@@ -6,6 +6,7 @@
 
 import android.os.Handler;
 import android.os.Looper;
+import android.util.Log;
 import androidx.annotation.Nullable;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
@@ -35,6 +36,8 @@
   // 0 <= n < 2^16.
   private static final long MIN_HOST_CREATED_IDENTIFIER = 65536;
   private static final long CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL = 30000;
+  private static final String TAG = "InstanceManager";
+  private static final String CLOSED_WARNING = "Method was called while the manager was closed.";
 
   /** Interface for listening when a weak reference of an instance is removed from the manager. */
   public interface FinalizationListener {
@@ -79,11 +82,15 @@
    *
    * @param identifier the identifier paired to an instance.
    * @param <T> the expected return type.
-   * @return the removed instance if the manager contains the given identifier, otherwise null.
+   * @return the removed instance if the manager contains the given identifier, otherwise null if
+   *     the manager doesn't contain the value or the manager is closed.
    */
   @Nullable
   public <T> T remove(long identifier) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return null;
+    }
     return (T) strongInstances.remove(identifier);
   }
 
@@ -95,11 +102,14 @@
    *
    * @param instance an instance that may be stored in the manager.
    * @return the identifier associated with `instance` if the manager contains the value, otherwise
-   *     null.
+   *     null if the manager doesn't contain the value or the manager is closed.
    */
   @Nullable
   public Long getIdentifierForStrongReference(Object instance) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return null;
+    }
     final Long identifier = identifiers.get(instance);
     if (identifier != null) {
       strongInstances.put(identifier, instance);
@@ -114,11 +124,16 @@
    * The Dart InstanceManager is considered the source of truth and has the capability to overwrite
    * stored pairs in response to hot restarts.
    *
+   * <p>If the manager is closed, the addition is ignored.
+   *
    * @param instance the instance to be stored.
    * @param identifier the identifier to be paired with instance. This value must be >= 0.
    */
   public void addDartCreatedInstance(Object instance, long identifier) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return;
+    }
     addInstance(instance, identifier);
   }
 
@@ -126,10 +141,13 @@
    * Adds a new instance that was instantiated from the host platform.
    *
    * @param instance the instance to be stored.
-   * @return the unique identifier stored with instance.
+   * @return the unique identifier stored with instance. If the manager is closed, returns -1.
    */
   public long addHostCreatedInstance(Object instance) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return -1;
+    }
     final long identifier = nextIdentifier++;
     addInstance(instance, identifier);
     return identifier;
@@ -141,11 +159,14 @@
    * @param identifier the identifier paired to an instance.
    * @param <T> the expected return type.
    * @return the instance associated with `identifier` if the manager contains the value, otherwise
-   *     null.
+   *     null if the manager doesn't contain the value or the manager is closed.
    */
   @Nullable
   public <T> T getInstance(long identifier) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return null;
+    }
     final WeakReference<T> instance = (WeakReference<T>) weakInstances.get(identifier);
     if (instance != null) {
       return instance.get();
@@ -157,22 +178,38 @@
    * Returns whether this manager contains the given `instance`.
    *
    * @param instance the instance whose presence in this manager is to be tested.
-   * @return whether this manager contains the given `instance`.
+   * @return whether this manager contains the given `instance`. If the manager is closed, returns
+   *     `false`.
    */
   public boolean containsInstance(Object instance) {
-    assertManagerIsNotClosed();
+    if (isClosed()) {
+      Log.w(TAG, CLOSED_WARNING);
+      return false;
+    }
     return identifiers.containsKey(instance);
   }
 
   /**
    * Closes the manager and releases resources.
    *
-   * <p>Calling a method after calling this one will throw an {@link AssertionError}. This method
-   * excluded.
+   * <p>Methods called after this one will be ignored and log a warning.
    */
   public void close() {
     handler.removeCallbacks(this::releaseAllFinalizedInstances);
     isClosed = true;
+    identifiers.clear();
+    weakInstances.clear();
+    strongInstances.clear();
+    weakReferencesToIdentifiers.clear();
+  }
+
+  /**
+   * Whether the manager has released resources and is not longer usable.
+   *
+   * <p>See {@link #close()}.
+   */
+  public boolean isClosed() {
+    return isClosed;
   }
 
   private void releaseAllFinalizedInstances() {
@@ -199,10 +236,4 @@
     weakReferencesToIdentifiers.put(weakReference, identifier);
     strongInstances.put(identifier, instance);
   }
-
-  private void assertManagerIsNotClosed() {
-    if (isClosed) {
-      throw new AssertionError("Manager has already been closed.");
-    }
-  }
 }
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/InstanceManagerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/InstanceManagerTest.java
index 4731e2a..6a19c88 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/InstanceManagerTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/InstanceManagerTest.java
@@ -5,6 +5,7 @@
 package io.flutter.plugins.webviewflutter;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -59,4 +60,52 @@
 
     instanceManager.close();
   }
+
+  @Test
+  public void removeReturnsNullWhenClosed() {
+    final Object object = new Object();
+    final InstanceManager instanceManager = InstanceManager.open(identifier -> {});
+    instanceManager.addDartCreatedInstance(object, 0);
+    instanceManager.close();
+
+    assertNull(instanceManager.remove(0));
+  }
+
+  @Test
+  public void getIdentifierForStrongReferenceReturnsNullWhenClosed() {
+    final Object object = new Object();
+    final InstanceManager instanceManager = InstanceManager.open(identifier -> {});
+    instanceManager.addDartCreatedInstance(object, 0);
+    instanceManager.close();
+
+    assertNull(instanceManager.getIdentifierForStrongReference(object));
+  }
+
+  @Test
+  public void addHostCreatedInstanceReturnsNegativeOneWhenClosed() {
+    final InstanceManager instanceManager = InstanceManager.open(identifier -> {});
+    instanceManager.close();
+
+    assertEquals(instanceManager.addHostCreatedInstance(new Object()), -1L);
+  }
+
+  @Test
+  public void getInstanceReturnsNullWhenClosed() {
+    final Object object = new Object();
+    final InstanceManager instanceManager = InstanceManager.open(identifier -> {});
+    instanceManager.addDartCreatedInstance(object, 0);
+    instanceManager.close();
+
+    assertNull(instanceManager.getInstance(0));
+  }
+
+  @Test
+  public void containsInstanceReturnsFalseWhenClosed() {
+    final Object object = new Object();
+    final InstanceManager instanceManager = InstanceManager.open(identifier -> {});
+    instanceManager.addDartCreatedInstance(object, 0);
+    instanceManager.close();
+
+    assertFalse(instanceManager.containsInstance(object));
+  }
 }
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index 57346e1..123a7c9 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget on Android.
 repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_android
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 3.1.2
+version: 3.1.3
 
 environment:
   sdk: ">=2.17.0 <3.0.0"