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.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SearchView; import android.widget.SearchView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity; 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.R;
import com.pichillilorenzo.flutter_inappwebview.Util; 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.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.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings; 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.URLRequest;
import com.pichillilorenzo.flutter_inappwebview.types.UserScript; 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.io.IOException;
import java.util.ArrayList; 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 != null && webView.inAppWebViewChromeClient != null) {
manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); manager.plugin.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient);
} }
if (webView.channelDelegate != null) { RelativeLayout containerView = (RelativeLayout) findViewById(R.id.container);
webView.channelDelegate.dispose(); if (containerView != null) {
containerView.removeAllViews();
} }
webView.setWebChromeClient(new WebChromeClient()); webView.dispose();
webView.setWebViewClient(new WebViewClient() { webView = null;
public void onPageFinished(WebView view, String url) {
webView.dispose();
webView.destroy();
webView = null;
manager = null;
}
});
webView.loadUrl("about:blank");
finish(); finish();
} }
} }

View File

@ -158,47 +158,13 @@ public class FlutterWebView implements PlatformWebView {
@Override @Override
public void dispose() { public void dispose() {
if (keepAliveId == null && webView != null) { if (keepAliveId == null && webView != null) {
if (webView.channelDelegate != null) { webView.dispose();
webView.channelDelegate.dispose(); webView = null;
}
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;
}
if (pullToRefreshLayout != null) { if (pullToRefreshLayout != null) {
pullToRefreshLayout.dispose(); pullToRefreshLayout.dispose();
pullToRefreshLayout = null; pullToRefreshLayout = null;
} }
}
});
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(false);
webView.loadUrl("about:blank");
} }
} }

View File

@ -45,9 +45,11 @@ import android.webkit.DownloadListener;
import android.webkit.URLUtil; import android.webkit.URLUtil;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList; import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
import android.webkit.WebHistoryItem; import android.webkit.WebHistoryItem;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebStorage; import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.HorizontalScrollView; import android.widget.HorizontalScrollView;
import android.widget.LinearLayout; 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.PrintJS;
import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PromisePolyfillJS; import com.pichillilorenzo.flutter_inappwebview.plugin_scripts_js.PromisePolyfillJS;
import com.pichillilorenzo.flutter_inappwebview.print_job.PrintJobController; 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.print_job.PrintJobSettings;
import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout; import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout;
import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld; import com.pichillilorenzo.flutter_inappwebview.types.ContentWorld;
@ -107,6 +108,7 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -2002,6 +2004,23 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Override @Override
public void dispose() { 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(); userContentController.dispose();
if (findInteractionController != null) { if (findInteractionController != null) {
findInteractionController.dispose(); findInteractionController.dispose();
@ -2026,14 +2045,28 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
callAsyncJavaScriptCallbacks.clear(); callAsyncJavaScriptCallbacks.clear();
evaluateJavaScriptContentWorldCallbacks.clear(); evaluateJavaScriptContentWorldCallbacks.clear();
inAppBrowserDelegate = null; inAppBrowserDelegate = null;
inAppWebViewChromeClient = null; if (inAppWebViewRenderProcessClient != null) {
inAppWebViewClientCompat = null; inAppWebViewRenderProcessClient.dispose();
inAppWebViewClient = null; inAppWebViewRenderProcessClient = null;
javaScriptBridgeInterface = null; }
inAppWebViewRenderProcessClient = null; if (inAppWebViewChromeClient != null) {
channelDelegate = 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; plugin = null;
super.dispose(); loadUrl("about:blank");
} }
@Override @Override

View File

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