[
https://issues.apache.org/jira/browse/CB-6936?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Joe Bowser updated CB-6936:
---------------------------
Component/s: (was: Plugin Dialogs)
Priority: Minor (was: Major)
Removing dialogs, because this could be any plugin.
> app crashes if webview is destroyed while dialog box open
> ---------------------------------------------------------
>
> Key: CB-6936
> URL: https://issues.apache.org/jira/browse/CB-6936
> Project: Apache Cordova
> Issue Type: Bug
> Components: Android
> Affects Versions: 3.4.0
> Environment: Android 4.x on physical device
> Or any Android environment
> Reporter: Shingo Toda
> Assignee: Joe Bowser
> Priority: Minor
>
> We have an Android application which implements an embedded WebView
> "container" in which it executes customer Cordova apps.
> Under certain conditions our container needs to terminate the customer app,
> and during this termination it calls {{CordovaWebView.destroy()}} to disable
> CordovaWebView.
> But application may entirely crash during this termination in some scenarios.
> For example:
> # call {{navigator.notification.alert}}, {{confirm}} or {{prompt}} and leave
> popup dialog open
> # this termination is done for some reason while dialog box is till open
> # all views on CordovaWebView are released but dialog box still remains
> # attempt to close dialog by pressing button in the dialog
> # application crashes with Unknown exception.
> {code}
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): 81508: Unknown exception
> occurred.
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): java.lang.NullPointerException
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> android.webkit.WebView.setNetworkAvailable(WebView.java:2639)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.NativeToJsMessageQueue$OnlineEventsBridgeMode$1.run(NativeToJsMessageQueue.java:305)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> android.app.Activity.runOnUiThread(Activity.java:4175)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.NativeToJsMessageQueue$OnlineEventsBridgeMode.onNativeToJsMessageAvailable(NativeToJsMessageQueue.java:313)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.NativeToJsMessageQueue.enqueueMessage(NativeToJsMessageQueue.java:253)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.NativeToJsMessageQueue.addPluginResult(NativeToJsMessageQueue.java:246)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.CordovaWebView.sendPluginResult(CordovaWebView.java:572)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.CallbackContext.sendPluginResult(CallbackContext.java:64)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> org.apache.cordova.dialogs.Notification$1$1.onClick(Notification.java:150)
> 06-13 21:45:19.765: E/FSP_INTS-MAPS_AG(11176): at
> com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
> {code}
> h2. Problem
> Obviously CordovaWebView is already not available but dialog still exists. If
> a user press button in dialog, {{onClick()}} gets called and consequently
> {{CordovaWebView.setNetworkAvailable()}} gets called to send message from
> queue to JavaScript even though WebView is already destroyed. As a result,
> entire application crashes.
> h3. Workaround
> We made a method to check if WebView is destroyed or not.
> {code}
> private boolean isWebViewDestroyed() {
> final String url = webView.getUrl();
> if (url == null ||
> url.equals("about:blank")) {
> return true;
> } else {
> return false;
> }
> }
> {code}
> And check this before {{callbackContext.sendPluginResult()}} is called.
> {code}
> public synchronized void alert(final String message, final String title,
> final String buttonLabel, final CallbackContext callbackContext) {
> final CordovaInterface cordova = this.cordova;
> Runnable runnable = new Runnable() {
> public void run() {
> AlertDialog.Builder dlg = new
> AlertDialog.Builder(cordova.getActivity());
> dlg.setMessage(message);
> dlg.setTitle(title);
> dlg.setCancelable(true);
> dlg.setPositiveButton(buttonLabel,
> new AlertDialog.OnClickListener() {
> public void onClick(DialogInterface dialog, int
> which) {
> dialog.dismiss();
> if (!isWebViewDestroyed()) {
> callbackContext.sendPluginResult(new
> PluginResult(PluginResult.Status.OK, 0));
> }
> }
> });
> dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
> public void onCancel(DialogInterface dialog)
> {
> dialog.dismiss();
> if (!isWebViewDestroyed()) {
> callbackContext.sendPluginResult(new
> PluginResult(PluginResult.Status.OK, 0));
> }
> }
> });
> dlg.create();
> dlg.show();
> };
> };
> this.cordova.getActivity().runOnUiThread(runnable);
> }
> {code}
> Similar changes are also applied to {{confirm()}} and {{prompt()}}. This
> workaround works fine on my application.
> h2. Question
> I want to know if this workaround is correct.
> * Do you know how to check if WebView is destroyed or not? I end up choosing
> {{getURL()}} as a result of experimental test. I appreciate any official or
> popular way.
> * {{isWebViewDestroyed()}} could be before
> {{webView.sendPluginResult(pluginResult, callbackId)}} in
> {{CallbackContext.sendPluginResult()}}? I think this way would prevent any
> APIs from this problem. But I'm afraid if this idea may impacts on other
> plugin API calls.
--
This message was sent by Atlassian JIRA
(v6.2#6252)