You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cordova.apache.org by "ASF subversion and git services (JIRA)" <ji...@apache.org> on 2017/09/15 20:27:01 UTC

[jira] [Commented] (CB-6936) app crashes if webview is destroyed while dialog box open

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

ASF subversion and git services commented on CB-6936:
-----------------------------------------------------

Commit dddb2837ddfa4a13e9f2f748bdc432bcdd78847e in cordova-android's branch refs/heads/master from [~bowserj]
[ https://gitbox.apache.org/repos/asf?p=cordova-android.git;h=dddb283 ]

CB-6936: Merge pull request #304 from uareurapid/master

CB-6936: fix crash when calling methods on a destroyed webview

> 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: cordova-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.4.14#64029)

---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@cordova.apache.org
For additional commands, e-mail: issues-help@cordova.apache.org