fixed android InAppWebView and InAppBrowser dispose functions to correctly dispose resources

This commit is contained in:
Lorenzo Pichilli 2023-05-20 13:03:03 +02:00
parent 5a113f6e8a
commit 2da9db9769
4 changed files with 121 additions and 109 deletions

View File

@ -13,30 +13,27 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SearchView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.R;
import com.pichillilorenzo.flutter_inappwebview.Util;
import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteractionController;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewChromeClient;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewSettings;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings;
import com.pichillilorenzo.flutter_inappwebview.types.Disposable;
import com.pichillilorenzo.flutter_inappwebview.types.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript;
import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView;
import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebViewSettings;
import java.io.IOException;
import java.util.ArrayList;
@ -538,19 +535,12 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
manager.plugin.activityPluginBinding != null && webView.inAppWebViewChromeClient != null) {
manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient);
}
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
RelativeLayout containerView = (RelativeLayout) findViewById(R.id.container);
if (containerView != null) {
containerView.removeAllViews();
}
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
manager = null;
}
});
webView.loadUrl("about:blank");
webView.dispose();
webView = null;
finish();
}
}

View File

@ -158,47 +158,13 @@ public class FlutterWebView implements PlatformWebView {
@Override
public void dispose() {
if (keepAliveId == null && webView != null) {
if (webView.channelDelegate != null) {
webView.channelDelegate.dispose();
}
webView.removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
WebViewCompat.setWebViewRenderProcessClient(webView, null);
}
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
if (webView.inAppWebViewRenderProcessClient != null) {
webView.inAppWebViewRenderProcessClient.dispose();
}
if (webView.inAppWebViewChromeClient != null) {
webView.inAppWebViewChromeClient.dispose();
}
if (webView.inAppWebViewClientCompat != null) {
webView.inAppWebViewClientCompat.dispose();
}
if (webView.inAppWebViewClient != null) {
webView.inAppWebViewClient.dispose();
}
if (webView.javaScriptBridgeInterface != null) {
webView.javaScriptBridgeInterface.dispose();
}
if (webView != null) {
webView.dispose();
webView.destroy();
webView = null;
}
webView.dispose();
webView = null;
if (pullToRefreshLayout != null) {
pullToRefreshLayout.dispose();
pullToRefreshLayout = null;
}
}
});
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(false);
webView.loadUrl("about:blank");
if (pullToRefreshLayout != null) {
pullToRefreshLayout.dispose();
pullToRefreshLayout = null;
}
}
}

View File

@ -45,9 +45,11 @@ import android.webkit.DownloadListener;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebHistoryItem;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
@ -80,7 +82,6 @@ import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PluginScriptsU
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PrintJS;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PromisePolyfillJS;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobManager;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobSettings;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
@ -107,6 +108,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.regex.Pattern;
@ -2002,6 +2004,23 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Override
public void dispose() {
if (channelDelegate != null) {
channelDelegate.dispose();
channelDelegate = null;
}
super.dispose();
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(false);
removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) {
WebViewCompat.setWebViewRenderProcessClient(this, null);
}
setWebChromeClient(new WebChromeClient());
setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
destroy();
}
});
userContentController.dispose();
if (findInteractionController != null) {
findInteractionController.dispose();
@ -2026,14 +2045,28 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
callAsyncJavaScriptCallbacks.clear();
evaluateJavaScriptContentWorldCallbacks.clear();
inAppBrowserDelegate = null;
inAppWebViewChromeClient = null;
inAppWebViewClientCompat = null;
inAppWebViewClient = null;
javaScriptBridgeInterface = null;
inAppWebViewRenderProcessClient = null;
channelDelegate = null;
if (inAppWebViewRenderProcessClient != null) {
inAppWebViewRenderProcessClient.dispose();
inAppWebViewRenderProcessClient = null;
}
if (inAppWebViewChromeClient != null) {
inAppWebViewChromeClient.dispose();
inAppWebViewChromeClient = null;
}
if (inAppWebViewClientCompat != null) {
inAppWebViewClientCompat.dispose();
inAppWebViewClientCompat = null;
}
if (inAppWebViewClient != null) {
inAppWebViewClient.dispose();
inAppWebViewClient = null;
}
if (javaScriptBridgeInterface != null) {
javaScriptBridgeInterface.dispose();
javaScriptBridgeInterface = null;
}
plugin = null;
super.dispose();
loadUrl("about:blank");
}
@Override

View File

@ -67,7 +67,9 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import io.flutter.plugin.common.PluginRegistry;
@ -81,6 +83,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
private static final int PICKER = 1;
private static final int PICKER_LEGACY = 3;
final String DEFAULT_MIME_TYPES = "*/*";
final Map<DialogInterface, JsResult> dialogs = new HashMap();
protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
@ -276,6 +279,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onClick(DialogInterface dialog, int which) {
result.confirm();
dialog.dismiss();
dialogs.remove(dialog);
}
};
@ -297,10 +301,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onCancel(DialogInterface dialog) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
dialogs.put(alertDialog, result);
alertDialog.show();
}
@ -360,6 +366,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onClick(DialogInterface dialog, int which) {
result.confirm();
dialog.dismiss();
dialogs.remove(dialog);
}
};
DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() {
@ -367,6 +374,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onClick(DialogInterface dialog, int which) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
};
@ -393,10 +401,12 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onCancel(DialogInterface dialog) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
dialogs.put(alertDialog, result);
alertDialog.show();
}
@ -476,6 +486,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
String text = input.getText().toString();
result.confirm(finalValue != null ? finalValue : text);
dialog.dismiss();
dialogs.remove(dialog);
}
};
DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() {
@ -483,6 +494,7 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onClick(DialogInterface dialog, int which) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
};
@ -509,11 +521,13 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onCancel(DialogInterface dialog) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.setView(layout);
dialogs.put(alertDialog, result);
alertDialog.show();
}
@ -567,50 +581,54 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
public void createBeforeUnloadDialog(String message, final JsResult result, String responseMessage, String confirmButtonTitle, String cancelButtonTitle) {
String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
dialog.dismiss();
}
};
DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
dialog.dismiss();
}
};
Activity activity = getActivity();
if (activity == null) {
return;
String alertMessage = (responseMessage != null && !responseMessage.isEmpty()) ? responseMessage : message;
DialogInterface.OnClickListener confirmClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
dialog.dismiss();
dialogs.remove(dialog);
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);
} else {
alertDialogBuilder.setPositiveButton(android.R.string.ok, confirmClickListener);
};
DialogInterface.OnClickListener cancelClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
if (cancelButtonTitle != null && !cancelButtonTitle.isEmpty()) {
alertDialogBuilder.setNegativeButton(cancelButtonTitle, cancelClickListener);
} else {
alertDialogBuilder.setNegativeButton(android.R.string.cancel, cancelClickListener);
};
Activity activity = getActivity();
if (activity == null) {
return;
}
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity, androidx.appcompat.R.style.Theme_AppCompat_Dialog_Alert);
alertDialogBuilder.setMessage(alertMessage);
if (confirmButtonTitle != null && !confirmButtonTitle.isEmpty()) {
alertDialogBuilder.setPositiveButton(confirmButtonTitle, confirmClickListener);
} else {
alertDialogBuilder.setPositiveButton(android.R.string.ok, confirmClickListener);
}
if (cancelButtonTitle != null && !cancelButtonTitle.isEmpty()) {
alertDialogBuilder.setNegativeButton(cancelButtonTitle, cancelClickListener);
} else {
alertDialogBuilder.setNegativeButton(android.R.string.cancel, cancelClickListener);
}
alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
result.cancel();
dialog.dismiss();
dialogs.remove(dialog);
}
});
alertDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
result.cancel();
dialog.dismiss();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
AlertDialog alertDialog = alertDialogBuilder.create();
dialogs.put(alertDialog, result);
alertDialog.show();
}
@Override
@ -1296,6 +1314,11 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
}
public void dispose() {
for (Map.Entry<DialogInterface, JsResult> dialog : dialogs.entrySet()) {
dialog.getValue().cancel();
dialog.getKey().dismiss();
}
dialogs.clear();
if (plugin != null && plugin.activityPluginBinding != null) {
plugin.activityPluginBinding.removeActivityResultListener(this);
}