如何从 android activity 调用现有的 javascript 函数

How to call existing javascript function from android activity

我正在制作一本电子书 reader,所以我有一个 webview,它正在加载一个页面,该页面存储在本地设备上,它从电子书本身检索到该页面。在此页面上,它有一个 javascript 函数 controls.nextPage() 可以加载并且 运行 很好;它过去并不实际导航到新网页,而是使用 javascript 重绘虚拟页面。我将此功能绑定到网页本身的一个按钮,以便我可以手动单击它进行测试,再次,当我触摸我的 webview 上的按钮时工作正常。

现在我正尝试从我的应用程序中触发这个确切的功能。理想情况下,我想通过手势滑动来完成此操作,但这对于这个特定问题来说太复杂了,因为我还有其他需要首先解决的手势问题。现在,我在导航抽屉中设置了一个按钮来触发它并测试它:

NavigationView navigationViewRight = (NavigationView) findViewById(R.id.nav_view_webview_right);
navigationViewRight.setNavigationItemSelectedListener(
    new NavigationView.OnNavigationItemSelectedListener() {
        @SuppressWarnings("StatementWithEmptyBody")
        @Override
        public boolean onNavigationItemSelected(MenuItem item) {
            // Handle navigation view item clicks here.
            int id = item.getItemId();

            if (id == R.id.nav_camera) {
                // *** - Focus here - *** //
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mWebview.evaluateJavascript("controls.pageNext()", null);
                    }
                });
            } else if (id == R.id.nav_share) {
            }

            drawer.closeDrawer(GravityCompat.END);
            return true;
        }
    }
);

请注意,我也试过拨打 window.controls.pageNext() 但无济于事。

所以我的页面已加载,我点击了页面内按钮来测试该功能;作品。我去点击应用程序中的导航抽屉按钮?错误(当使用 window.controls.pageNext():

[INFO:CONSOLE(1)] "Uncaught TypeError: Cannot read property 'pageNext' of undefined", source:  (1)

所以 evaluateJavascript() 似乎是 运行 一个新的 environment/thread。我怎么能告诉它不要呢?

为了解决这个问题,我尝试创建一个空的 javascript 接口,希望我可以简单地将我的页面 javascript 初始化到其中,从而能够从 Android.

mWebview.addJavascriptInterface(new TestInterface(), "TestInterface");

public class TestInterface {
    @JavascriptInterface
    public void test() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebview.evaluateJavascript("console.log('test')", null);
            }
        });
    }
}

从我的网络应用程序中,javascript 可以很好地调用接口。调用 TestInterface.test(); 产生:

[INFO:CONSOLE(1)] "test", source:  (1)

但是当我尝试从我的网络应用程序向该界面分配一个新功能时:

TestInterface.testTwo = function() {
    console.log('testTwo');
};
TestInterface.testTwo();

Android 没有:

[INFO:CONSOLE(674)] "testTwo", source: http://127.0.0.1:8080/js/main.js (674)

奇怪的是,它并没有真正给我提供太多继续下去的信息。我知道我的页面的其余部分在 testTwo() 尝试后加载有问题 test() 没有,所以我假设无法加载脚本的其余部分。

最后,出于好奇,我更改了导航抽屉按钮以尝试 运行 新功能如下:

mWebview.evaluateJavascript("TestInterface.testTwo()", null);

日志:

[INFO:CONSOLE(1)] "Uncaught TypeError: TestInterface.testTwo is not a function", source:  (1)

是的,但还有其他原因吗?我不知道。想法?谢谢。

所以我最终弄清楚了我的问题所在。通过 运行ning mWebview.evaluateJavascript("window.location", null);,我意识到我实际上并不在我认为的页面上。我的电子书页面被加载到 iframe 或其他类型的 skeleton/wrapper 中,因此在 运行 宁 evaluateJavascript().

时,webapp 功能实际上不可用

所以一旦弄明白了,我就可以确认一些我最初在上面质疑的事情:

So it seems to be that evaluateJavascript() is being run in a fresh environment/thread. How can I tell it not to?

没有。只需确保您知道实际加载的页面。

To get around this,I've tried to create an empty javascript interface in the hopes that I could simply initialize my page javascript into it and thus be able to call it from Android.

这确实有效。我不确定我之前的错误是什么,但是如果我在 Android 中创建一个 javascript 接口,它的功能对 webapp 可用并且我实际上可以从内部将新对象写入接口对象网络应用程序。因此,从 webapp 中将新对象初始化为 TestInterface 可以通过以下方式在 Android 应用程序中 运行: mWebview.evaluateJavascript("TestInterface.someNewFunctionFromWebapp()", null);

但是我无法覆盖该 javascript 接口对象的任何现有 objects/properties。所以 TestInterface.test() 是不可变的。