[ 
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)

Reply via email to