【问题标题】:Android WebView inconsistent when activity is in the background活动在后台时Android WebView不一致
【发布时间】:2015-03-01 04:10:09
【问题描述】:

我正在使用 WebView 通过 JavaScript 接收 Google Cloud 频道消息(请参阅下面的代码)。 WebView 托管在登录期间使用的 Activity 中,然后保留在后台。

compileSdkVersion 即使 Activity 在后台,JavaScript 也会继续运行并接收事件。

compileSdkVersion >= 19(使用基于 Chrome 的 WebView)-> 在 SDK >= 19 的合适设备上,即使 Activity 在后台,JavaScript 也会继续运行并接收事件,但是在 SDK

尽管 Google 已宣布 http://www.zdnet.com/article/google-why-we-wont-patch-pre-kitkat-android-webview/ 不会在旧设备上修复 WebView 的 XSS 漏洞,但在我看来,当 compileSdkVersion 设置为 19 或更高版本时,Google 会干扰旧设备。较旧的设备似乎以某种兼容模式运行,这似乎与预期的行为不兼容。 Google 谈到升级 WebView https://developer.android.com/guide/webapps/migrating.html,但没有提到 WebView 在旧设备上的行为不同。而且我也不相信这是故意的。我读到 Google 对 Lollypop 进行了进一步的更改,但我没有可用于测试的设备。

换句话说,我们都在 Android 中预料到了一个巨大的不一致的 beta 混乱。任何人在 compileSdkVersion >= 19 的旧设备上使用 WebView 在后台运行或知道解决方法?

这是html代码:

<html>
    <head>
        <script src='{{ channelurl }}jsapi'></script>
    </head>
    <body>
        <div>WebView for ChannelService</div>

        <script type="text/javascript">

            onOpen = function() {
                ChannelListener.onOpen();
            };
            onMessage = function(message) {
                ChannelListener.onMessage(message.data);
            };
            onError = function(error) {
                ChannelListener.onError(error.code, error.description);
            };
            onClose = function() {
                ChannelListener.onClose();
            };

            var token = '{{ token }}';
            var channel = new goog.appengine.Channel(token);

            var handler = {
                'onopen': onOpen,
                'onmessage': onMessage,
                'onerror': onError,
                'onclose': onClose
            };

            var socket = channel.open(handler);

            socket.onopen = onOpen;
            socket.onmessage = onMessage;
            socket.onerror = onError;
            socket.onclose = onClose;

        </script>
    </body>
</html>

以及相关的Java代码:

public class ChannelService {

    private class ChannelListenerJavascriptInterface { // receive channel message from App Engine
        @JavascriptInterface public void onOpen() {
            requestOpen();
        }
        @JavascriptInterface public void onMessage(String message) {
            requestMessage(message);
        }
        @JavascriptInterface public void onError(Integer code, String description) {
            requestError(code, description);
        }
        @JavascriptInterface public void onClose() {
            requestClose();
        }
    }



    public ChannelService() throws IOException { // use a hidden WebView to host JavaScript code
        if (Session.exists()) {

            final Activity activity = (Activity) Session.getContext(); // retrieve the activity context in which the web view is hosted

            activity.runOnUiThread(new Runnable() { // ensure WebView is running on UI thread
                @Override public void run() {

                    WebView webView = (WebView) activity.findViewById(R.id.channel_webview); // listen to remote channel while Session exists; otherwise only to local channels

                    webView.getSettings().setJavaScriptEnabled(true);

                    webView.addJavascriptInterface(new ChannelListenerJavascriptInterface(), "ChannelListener");

                    String html = null;
                    try {
                        html = AssetsHelper.assetToString(Session.getContext(), "channel.html");
                    } catch (IOException e) {
                        throw new RuntimeException("Cannot read assets/channel.html file.", e);
                    }

                    html = html.replaceAll("\\{\\{ channelurl \\}\\}", MobileService.getChannelEndpoint());
                    html = html.replaceAll("\\{\\{ token \\}\\}", Session.getId());

                    webView.loadData(html, "text/html", "UTF-8");

                }
            });

        }
    }

    // Callback
    private OnMessageListener onMessageListener; public void setOnMessageListener(OnMessageListener onMessageListener) { this.onMessageListener = onMessageListener; }
    public interface OnMessageListener {
        public void onOpen();
        public void onMessage(String message);
        public void onClose();
        public void onError(Integer errorCode, String description);
    }

    private void requestOpen() {
        if(onMessageListener != null) { onMessageListener.onOpen(); }
    }
    private void requestMessage(String message) {
        if(onMessageListener != null) { onMessageListener.onMessage(message); }
    }
    private void requestError(Integer code, String description) {
        if(onMessageListener != null) { onMessageListener.onError(code, description); }
    }
    private void requestClose() {
        if(onMessageListener != null) { onMessageListener.onClose(); }
    }

}

【问题讨论】:

    标签: java javascript android google-chrome android-webview


    【解决方案1】:

    关于棒棒糖:

    我了解到 Google 对 Lollypop 进行了进一步的更改,但我没有可用于测试的设备。

    我们对基于 Chromium 的 WebView 的测试表明,App Engine 通道不适用于 Android 5.02 版(Lollipop API 级别 21)。

    compileSdkVersion 22, buildToolsVersion "22.0.1", minSdkVersion 17, targetSdkVersion 22

    已提出以下问题:

    https://code.google.com/p/android/issues/detail?id=172262

    https://code.google.com/p/chromium/issues/detail?id=485749

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多