当前位置:  开发笔记 > 编程语言 > 正文

如何从android的webview中获取javascript的返回值?

如何解决《如何从android的webview中获取javascript的返回值?》经验,为你挑选了6个好方法。

我想从Android中的Javascript获取返回值.我可以用iPhone做到这一点,但我不能用Android.我使用了loadUrl,但它返回的是void而不是object.有谁能够帮我?谢谢.



1> Kirill Kulak..:

Keith更短的答案相同

webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");

并实现该功能

@JavascriptInterface
public void onData(String value) {
   //.. do something with the data
}

不要忘了删除onDataproguard列表(如果启用的ProGuard)



2> Felix Khazin..:

这是一个关于如何实现它的黑客攻击:

将此客户端添加到WebView:

final class MyWebChromeClient extends WebChromeClient {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    }

现在在你的javascript调用中执行:

webView.loadUrl("javascript:alert(functionThatReturnsSomething)");

现在在onJsAlert调用"message"中将包含返回的值.


这是一个非常有价值的黑客; 特别是当您构建一个您无法控制javascript的应用程序时,必须使用现有功能.请注意,您可以使用`public boolean onConsoleMessage(ConsoleMessage consoleMessage)`而不是`onJsAlert`来拦截JS警报,然后在javascript调用中执行`webView.loadUrl("javascript:console.log(functionThatReturnsSomething)) ");` - 这样你就可以单独留下JS警报了.
使用addJavascriptInterface的任何原因都不是更好的选择?

3> CommonsWare..:

使用addJavascriptInterface()Java对象添加到JavaScript环境.让您的Javascript调用该Java对象上的方法来提供其"返回值".


@PacMani:使用`loadUrl("javascript:...")`(API Level 1-18)或`evaluateJavascript()`(API Level 19+)在当前加载的Web页面的上下文中评估您自己的JavaScript .

4> Keith..:

这就是我今天想出的.它是线程安全的,合理有效的,并允许从Java WebView查看同步Javascript执行.

适用于Android 2.2及更高版本.(需要commons-lang,因为我需要将我的代码片段作为Javascript字符串传递给eval().您可以通过将代码包装在引号中来删除此依赖关系,但是在中function(){})

首先,将其添加到您的Javascript文件中:

function evalJsForAndroid(evalJs_index, jsString) {
    var evalJs_result = "";
    try {
        evalJs_result = ""+eval(jsString);
    } catch (e) {
        console.log(e);
    }
    androidInterface.processReturnValue(evalJs_index, evalJs_result);
}

然后,将其添加到您的Android活动中:

private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map jsReturnValues = new HashMap();
private final Object jsReturnValueLock = new Object();
private WebView webView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    webView = (WebView) findViewById(R.id.webView);
    webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}

public String evalJs(final String js) {
    final int index = evalJsIndex.incrementAndGet();
    handler.post(new Runnable() {
        public void run() {
            webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
                                    "\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
        }
    });
    return waitForJsReturnValue(index, 10000);
}

private String waitForJsReturnValue(int index, int waitMs) {
    long start = System.currentTimeMillis();

    while (true) {
        long elapsed = System.currentTimeMillis() - start;
        if (elapsed > waitMs)
            break;
        synchronized (jsReturnValueLock) {
            String value = jsReturnValues.remove(index);
            if (value != null)
                return value;

            long toWait = waitMs - (System.currentTimeMillis() - start);
            if (toWait > 0)
                try {
                    jsReturnValueLock.wait(toWait);
                } catch (InterruptedException e) {
                    break;
                }
            else
                break;
        }
    }
    Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
    return "";
}

private void processJsReturnValue(int index, String value) {
    synchronized (jsReturnValueLock) {
        jsReturnValues.put(index, value);
        jsReturnValueLock.notifyAll();
    }
}

private static class MyJavascriptInterface {
    private MyActivity activity;

    public MyJavascriptInterface(MyActivity activity) {
        this.activity = activity;
    }

    // this annotation is required in Jelly Bean and later:
    @JavascriptInterface
    public void processReturnValue(int index, String value) {
        activity.processJsReturnValue(index, value);
    }
}


谢谢你上面的代码 - 我在我的Android项目中采用了它.但是,由于糟糕的Java API设计导致其中存在陷阱.行:jsReturnValueLock.wait(waitMs - (System.currentTimeMillis() - start)); wait()函数参数的值有时可能会计算为0.这意味着"无限等待" - 我偶尔会遇到"无响应"错误.我通过测试来解决它:if(elapsed> = waitMS)break; 而不是再次调用System.currentTimeMillis(),而是使用经过的值.最好编辑并修复上面的代码.

5> 小智..:

@Felix Khazin建议的解决方案有效,但有一个关键点缺失.

应该在WebView加载网页后进行javascript调用.将此添加WebViewClientWebView,以及WebChromeClient.

完整示例:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    WebView webView = (WebView) findViewById(R.id.web_view);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new MyWebViewClient());
    webView.setWebChromeClient(new MyWebChromeClient());
    webView.loadUrl("http://example.com");
}

private class MyWebViewClient extends WebViewClient {
    @Override
    public void onPageFinished (WebView view, String url){
        view.loadUrl("javascript:alert(functionThatReturnsSomething())");
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }
}

private class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    Log.d("LogTag", message);
        result.confirm();
        return true;
    }
}



6> David..:

在API 19+,要做到这一点的最好方法是调用evaluateJavascript您的WebView:

webView.evaluateJavascript("foo.bar()", new ValueCallback() {
    @Override public void onReceiveValue(String value) {
        // value is the result returned by the Javascript as JSON
    }
});

更详细的相关答案:https : //stackoverflow.com/a/20377857

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有