You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cordova.apache.org by "Joe Bowser (JIRA)" <ji...@apache.org> on 2014/06/17 08:12:02 UTC
[jira] [Updated] (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: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)