在Activity之外的Webview中显示AlertDialog

3
我一直在开发一个类似于Facebook聊天头像的功能,即使用户离开我们的应用程序去查看电子邮件等,该功能也需要保持活动状态供用户使用。我们需要能够通过javascript创建AlertDialogs,而不会受到用户在应用程序内切换活动的影响。当用户离开应用程序进行其他操作时,该功能可以关闭/隐藏,但是用户返回时必须仍然存在。
除了使用Service之外,我无法想到另一种让用户在其他事情上进行交互的方式。当我使用服务通过WindowManager创建webview时,webview的JsDialogHelper检测到上下文不是活动并阻止显示AlertDialogs。
如果您有任何想法使其正常工作,那将非常有帮助。我们需要允许AlertDialog弹出并进行交互以使此功能有用。我们需要在活动转换之间保留webview。
是否可能扩展JsDialogHelper使其适用于我的代码?是否有更好的方法在Android应用程序中使用webviews来实现像Facebook聊天头像一样的功能?如果它能够获得我所期望的用户体验,我也可以完全重写它。

让服务在您的应用程序中启动一个活动,当启动时,根据提供的MESSAGE_KEY显示一个对话框。 - petey
那样做是可行的,但 WebView 抱怨它无法打开 alertdialog,因为它创建时的 context 不是 Activity。我应该重写除了上面提到的 onJsAlert 之外的其他方法吗? - Matthew Runo
你放弃了很多声誉,而这些是你可以在更深入的研究中完成的。 - But I'm Not A Wrapper Class
相信我,我在这方面做了很多研究。用户体验的原因似乎决定了这个Webview必须放在与活动生命周期无关的某个地方 - 但是Webview还依赖于JavaScript警报对话框,这就是问题所在。这主要是希望有一种方法可以摆脱困境。一种可以在活动生命周期之外显示Webview并仍然使JavaScript警报正常工作的方法。 - Matthew Runo
@MatthewRuno 请看一下我在这里的回答:Android Facebook lock screen notification。你将会使用一个服务 - 所以 something not attached to the activity lifecycle所以,例如,当这个功能处于活动状态时,用户必须能够在我们的应用程序中导航做其他事情 - 当然,你可以保留视图,只要你需要它。...但是我们正在使用的服务要求它是一个webview - 好的 - 不要显示alertdialog,使用服务并使用WM添加视图。但是,我不确定这是否有帮助。 - Vikram
3个回答

4
您可以通过将窗口类型设置为TYPE_SYSTEM_ALERT,从服务中显示Dialog。记得使用传递给onJsAlertJsResult实例向用户返回所采取的操作。
    // maintain reference to JsResult instance passed to onJsAlert, in order
    // communicate back the action taken by the user.
    private JsResult mResult; 

    webView.setWebChromeClient(new WebChromeClient() {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            mResult = result;
            AlertDialog dialog = new AlertDialog.Builder(MyService.this)
                    .setTitle("Custom Dialog")
                    .setMessage("This is our custom dialog, not the one served by JsDialogHelper")
                    .setOnCancelListener(new CancelListener())
                    .setNegativeButton("Cancel", new CancelListener())
                    .setPositiveButton("Ok", new PositiveListener())
                    .create();
            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            dialog.show();

            return true;
        }
    });

    private class CancelListener implements DialogInterface.OnCancelListener,
        DialogInterface.OnClickListener {

        @Override
        public void onCancel(DialogInterface dialogInterface) {
            mResult.cancel();
        }

        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            mResult.cancel();
        }
    }

    private class PositiveListener implements DialogInterface.OnClickListener {

        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            mResult.confirm();
        }
    }

在清单文件中添加所需的权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

备选方案: 如果Web应用程序可以针对Android WebView构建,那么您可以创建JavaScript接口,使得JavaScript代码能够直接调用Android代码,从而为您显示对话框。这避免了使用JsDialogHelper的方法。

  1. 定义一个JavaScript接口:
public class WebAppInterface {
    Context context;

    WebAppInterface(Context c) {
        context = c;
    }

    // Annotation required for api >= 17
    @JavascriptInterface
    public void showDialog() {
        AlertDialog dialog = new AlertDialog.Builder(context)
                .setTitle("Custom Dialog")
                .setMessage("This is our custom dialog, not the one served by JsDialogHelper")
                .create();
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        dialog.show();
    }
}
  1. 使用addJavascriptInterface绑定Javascript和Android代码之间的接口。

webView.addJavascriptInterface(new WebAppInterface(this), "Android");

  1. 在Javascript代码中使用该接口。
<input type="button" value="Display dialog" onClick="displayDialog()" />
    <script>
        function displayDialog() {
            //alert("Javascript Dialog");
            Android.showDialog();
        }
    </script>
</input>

当我尝试这样做时,日志中会出现以下内容,但没有AlertDialog。W / JsDialogHelper:无法创建对话框,WebView上下文不是Activity。 - Matthew Runo
@MatthewRuno 你能在onJsAlert方法中设置断点或日志,以查看该方法是否被调用吗?如果您查看CallbackProxy实现,则只有在onJsAlert返回false时才需要调用JsDialogHelper中的showDialogonJsAlert的默认实现返回false,因此我怀疑是否曾调用过重写的方法。 - Manish Mulimani
@MatthewRuno 顺便问一句,您构建的 Web 应用程序是否专为 Android WebView 设计?如果是的话,您可以考虑使用此处解释的 JavaScript 接口。[链接:http://developer.android.com/guide/webapps/webview.html#UsingJavaScript] - Manish Mulimani
@MatthewRuno 在 onJsAlert 方法中触发了设置的断点吗? - Manish Mulimani
没有这样做,但我认为你的回答最好。这个Webview并不是为了便于Android或iOS应用程序集成而设计的,我们只是在破解它。你是对的——正确的方法是通过你所概述的JavaScript接口来实现。我将不得不针对拥有此功能的人员提交一些票据,以便在未来的更新中使用它。 - Matthew Runo
显示剩余2条评论

2
你不能在一个Activity之外显示一个AlertDialog

不过,你可以构建一个自定义的View,它看起来像你想要展示的对话框,并通过WindowManager在窗口中显示它。

例如:

WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT, 
                WindowManager.LayoutParams.WRAP_CONTENT
                WindowManager.LayoutParams.TYPE_PHONE,
                0,
                PixelFormat.TRANSLUCENT);

params.gravity = Gravity.CENTER;

windowManager.addView(yourView, params);

上面的代码将你自定义视图显示在屏幕中央,位于其他所有内容之上。你可以通过LayoutInflater来填充视图。

你还需要在清单文件中添加权限才能显示视图。

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

我该如何从Webview中触发此视图,而不是尝试创建JavaScript AlertDialog? - Matthew Runo
我不明白为什么你需要一个WebView。你可以像处理普通视图一样处理通过WindowManager添加的自定义视图。 - Alessandro Roaro
我真的很想能够在没有使用Webview的情况下完成这个任务,但是我们正在使用的服务要求必须使用Webview =\ - Matthew Runo
你尝试过使用我上面描述的方法添加 WebView 吗? - Alessandro Roaro
是的,这实际上就是当前的显示方式。基于活动的问题在于当用户离开活动时,Webview 会重置/被移除。因此,例如,在此功能处于活动状态时,用户必须能够在我们的应用程序中导航以执行其他操作。这就是为什么我选择了服务路线 - 活动生命周期不会影响它。 - Matthew Runo

1
我想你可以创建一个JavaScript接口,用于活动和WebView之间的双向通信。我自己没有尝试过这个解决方案,但之前也遇到过这个问题。在这里发布的SO问题可能会对您有所帮助。
我想你的WebView也将驻留在一个活动中,您可以使用活动的上下文来弹出AlertDialog。您只需要在要在webview中调用的活动中添加一个方法(我会在addJavascriptInterface方法中传递Activity对象)。
另一种方法是使用服务并启动实现Theme.dialog的新活动,以用作AlertDialog。
如果无法解决您的问题,请告诉我。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接