[ 
https://issues.apache.org/jira/browse/CB-6936?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14033861#comment-14033861
 ] 

Shingo Toda commented on CB-6936:
---------------------------------

Thanks Joe very much for your advice.

Actually I want to fix this problem as soon as possible. If you are OK,  could 
you confirm that modification to Notification.java should work fine and does 
not harm the other plugins (if your advice for destroyed WebView check is 
incorporated)?

Also which one of the 'core' plugins do you know have this issue?

The patch would be made by us and used internally but I hope the solution will 
be found and it will be incorporated into future versions.

> 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