【问题标题】:Is it possible to call addJavascriptInterface on a WebView created by onCreateWindow?是否可以在 onCreateWindow 创建的 WebView 上调用 addJavascriptInterface?
【发布时间】:2014-02-27 06:20:08
【问题描述】:

我有一个简单的浏览器应用程序,我的onCreateWindow 看起来像这样:

if (userGesture) {
            WebView childView = new WebView(webBrowserActivity);
            WebSettings settings = childView.getSettings();
            settings.setJavaScriptEnabled(true);
            settings.setSupportZoom(true);
            settings.setJavaScriptCanOpenWindowsAutomatically(true);
            settings.setBuiltInZoomControls(true);
            settings.setSupportMultipleWindows(true);
            settings.setLoadWithOverviewMode(true);
            settings.setUseWideViewPort(true);
            childView.addJavascriptInterface(new MyInterface(),"NAME");
            <--- code in here to add the view to a ViewPager.
            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
            transport.setWebView(childView);
            resultMsg.sendToTarget();
            Log.v(TAG, "Opening popup for " + childView.getUrl());
            webBrowserActivity.invalidateOptionsMenu();
            return true;
        } else {
            return false;
        }

我稍后尝试添加此接口,我还尝试在页面加载后调用reload()loadUrl(),因为文档说必须在加载页面之前添加 javascript 接口。这些都没有帮助。有没有人成功做到这一点?

谢谢。

编辑:我应该提到我在 4.4 上看到了更多,我正在使用 Chrome 的桌面调试器,我可以进入控制台并在第一个 webview 而不是第二个 webview 上看到 window.NAME 对象。在 4.3 上,它似乎经常工作。

我编辑了上面的代码以显示我正在使用的设置。我添加到 WebView 的 javascript 界面在添加到 Activity 启动时创建的第一个 WebView 时工作正常。

【问题讨论】:

  • 您使用的是哪个版本的 Android?
  • 在 4.4 上,我确定这是正在发生的事情,因为我可以附加桌面 Chrome 以调试移动浏览器。在 4.3 上,我遇到了同样的问题,但只是在一些弹出窗口上,但因为我无法轻松调试,所以我不知道那里到底发生了什么。
  • 我只是在 4.3 上玩了一段时间,它似乎总是在那里工作,一定是新的 4.4 更改的问题。
  • 您能否保留对子视图的引用并在 将 resultMsg 发回后添加 javascript?我认为 sendToTarget 将异步运行,因此之后立即执行可能还不够。
  • 我尝试过这样做,我尝试过刷新页面并读取界面,加载新的 url,无论我尝试什么,如果 WebView 是使用 onCreateWindow 创建的,它就不会工作。我确实有一个讨厌的解决方法,我创建一个新的 WebView 并使用相同的 url,效果很好。

标签: android android-webview chromium webviewclient


【解决方案1】:

不幸的是,KitKat WebView 中存在一个错误,导致无法在弹出窗口上注册 JavaScript 界面。恐怕这个问题没有已知的解决方法,除了你建议的那样,保留弹出窗口的 URL,从 onCreateWindow 返回 false,然后创建一个全新的 web 视图并将弹出 URL 加载到其中。

【讨论】:

  • 不是错误,有一个解决方法。见我的answer
【解决方案2】:

是的。它应该工作。我希望你这样做:

mWebView.getSettings().setJavaScriptEnabled(true);

【讨论】:

  • 是的,我正在这样做,抱歉,我在发帖时忘记复制那段代码。我还应该提到我在第一个 WebView 上对此问题为零。
【解决方案3】:

在 onCreateWindow 创建的 webview 之后使用 JS 时我遇到了同样的问题。 挖了资源,感觉不可能。

final WebView.WebViewTransport transport = (WebView.WebViewTransport) msg.obj;
if(transport!=null){
    transport.setWebView(mCustomWebView);
}
msg.sendToTarget();

在我们向目标发送消息后,WebViewChromium 执行此操作

        mUiThreadHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case NEW_WEBVIEW_CREATED:
                    WebView.WebViewTransport t = (WebView.WebViewTransport) msg.obj;
                    WebView newWebView = t.getWebView();
                    if (newWebView == mWebView) {
                        throw new IllegalArgumentException(
                                "Parent WebView cannot host it's own popup window. Please " +
                                "use WebSettings.setSupportMultipleWindows(false)");
                    }

                    if (newWebView != null && newWebView.copyBackForwardList().getSize() != 0) {
                        throw new IllegalArgumentException(
                                "New WebView for popup window must not have been previously " +
                                "navigated.");
                    }

                    **WebViewChromium.completeWindowCreation(mWebView, newWebView);**
                    break;
                default:
                    throw new IllegalStateException();
            }
        }

然后,它读取到addPossiblyUnsafeJavascriptInterface

public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
        Class<? extends Annotation> requiredAnnotation) {
    if (mNativeContentViewCore != 0 && object != null) {
        mJavaScriptInterfaces.put(name, object);
        nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation,
                mRetainedJavaScriptObjects);
    }
}

出于安全原因,似乎禁止通过 onCreateWindow 在 webview 上添加 JS。

评论说

/** * 此方法将提供的 Java 对象注入 ContentViewCore。 * 对象被注入到主框架的 JavaScript 上下文中, * 使用提供的名称。这允许从以下位置访问 Java 对象 * JavaScript。请注意,注入的对象不会出现在 * JavaScript,直到页面下一次(重新)加载。例如: *

 view.addJavascriptInterface(new Object(), "injectedObject");
     * view.loadData("", "text/html", null);
     * view.loadUrl("javascript:alert(injectedObject.toString())");
*

重要提示: *

    *
  • addJavascriptInterface() 可用于允许 JavaScript 控制 *主机应用程序。这是一个强大的功能,但也提供了一个 * 安全风险。在包含的 ContentViewCore 中使用此方法 * 不受信任的内容可能允许攻击者操纵主机 * 应用程序以非预期方式执行具有权限的 Java 代码 * 主机应用程序。在使用此方法时要格外小心 * ContentViewCore 可能包含不受信任的内容。特别照顾 * 应注意避免无意访问继承的方法,例如 * 作为 {@link Object#getClass()}。为了防止访问继承的方法, * 为 {@code requiredAnnotation} 传递一个注解。这将确保 * 只有带有 {@code requiredAnnotation} 的方法才会暴露给 * Javascript层。 {@code requiredAnnotation} 将传递给所有 * 如果任何方法返回一个对象,则随后注入 Java 对象。这 * 表示将适用相同的限制(或没有限制)。或者, * 可以调用 {@link #addJavascriptInterface(Object, String)} * 自动使用 {@link JavascriptInterface} 注释。 *
  • JavaScript 在私有背景上与 Java 对象交互 * ContentViewCore 的线程。因此需要小心维护 * 线程安全。
  • *

有一个难题。您可以通过从创建 onCreateWindow 的 webview 获取 url 并使用该 url 创建新的 webview 来使用 JS。我试过了,当链接是简单的超链接时它可以工作。但这样一来,某些页面,尤其是由 javascript 打开的页面,将无法正常工作。

到目前为止,我得到了这个,但我的时间很短。请有人分享更多。谢谢。

【讨论】:

    【解决方案4】:

    方法addJavascriptInterface有安全警告:

    对于面向 API 级别 JELLY_BEAN_MR1 及更高级别的应用程序,仅限 使用 JavascriptInterface 注释的公共方法可以是 从 JavaScript 访问。

    所以,如果你真的需要它,你的代码应该是这样的:

    @JavascriptInterface
    public void yourJavaFunction() 
    {
        //do you stuff
    }
    

    请注意,这样做会导致您面临安全风险,如note 中所述。

    【讨论】:

    • 很抱歉给了无用的投票。我对@JavascriptInterface 表示法有同样的问题。由 Activity 或 Fragment 创建的自定义 webview 可以很好地与 JS 配合使用。由 onCreateWindow 创建的 webview 出现问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    相关资源
    最近更新 更多