通过 Android WebView 从 JavaScript 调用 Java 函数

IT技术 javascript android android-webview
2021-01-13 14:03:15

我想对我的 Android 应用程序中的一些 Java 代码进行同步调用。

我正在使用这个解决方案:https : //stackoverflow.com/a/3338656

我的Java代码:

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

我的 JavaScript 代码:

<html>
<script>
function java_request(){
    alert('test');
}
</script>
<body>
<h2>Welcome</h2>
<div id="area"></div>
<form>
<input type="button" value="java_call" onclick="java_request()">
</form>
</body>
</html>

当我点击java_call按钮时,按钮进入按下状态。我可以'test'在控制台日志中看到到这里一切正常。

问题是,按钮永远不会恢复到正常状态。它保持按下状态。也许 JavaScript 执行已损坏或什么?

为什么按钮永远不会恢复到正常状态?

3个回答

我认为这不是让 javascript 执行 java 代码的最佳解决方案。看这里:

如果您想将本机代码公开给 HTML 以通过 javascript 调用,请围绕您的 web 视图声明执行以下操作:

JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");

声明类JavaScriptInterface

public class JavaScriptInterface {
    private Activity activity;

    public JavaScriptInterface(Activity activity) {
        this.activity = activity;
    }

    @JavascriptInterface
    public void startVideo(String videoAddress){
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse(videoAddress), "video/3gpp"); 
        activity.startActivity(intent);
    }
}

我声明了一个用于播放视频的函数,但你可以做任何你想做的事情。

最后,您WebView通过简单的 javascript 调用内容中调用它:

<video width="320" height="240" controls="controls" poster='poster.gif'
       onclick="window.JSInterface.startVideo('file:///sdcard/test.3gp');" >
   Your browser does not support the video tag.
</video>

该示例取自我的另一个关于播放视频的答案,但应该足够解释了。

编辑根据@CedricSoubrie 的评论:如果应用程序的目标版本设置为 17 或更高版本,则需要在@JavascriptInterface要导出到 Web 视图的每个方法上方添加注释

感谢您的信息,我看到了这个解决方案。由于此解决方案在 2.3.X 中存在错误,因此我不想使用它。解决方法非常棒。
2021-03-24 14:03:15
@BorisStrandjev 非常明确的答案!请注意,您必须将“@JavascriptInterface”注释添加到您希望从 17 版或更高版本的 JavaScript 中可用的任何方法。来源:developer.android.com/guide/webapps/webview.html
2021-03-27 14:03:15
我想 'playVideo' 和 'startVideo' 应该是一样的吗?
2021-03-28 14:03:15
@ozkolonur 我一直在所有版本的 Android 2.2+ 上使用它,从未发现任何错误。能分享一下是什么吗。链接也很受欢迎。
2021-03-29 14:03:15
@Maarten:实际上这并不是我回答中唯一的错误。我现在已经改正了。
2021-03-29 14:03:15

您的函数返回“真”。这使得 HTML 代码的“onclick”属性等于 true,因此按钮保持“点击”状态。

在“ YourJavaScriptInterface ”类中定义的方法,不要忘记用“@JavascriptInterface”注释每个要公开的方法,否则不会触发该方法。

例如,以下代码来自 Google Cloud Print JavaScript 接口,用于从 webview 页面调用:

        final class PrintDialogJavaScriptInterface {
        @JavascriptInterface
        public String toString() { return JS_INTERFACE; }

        @JavascriptInterface
        public String getType() {
            return cloudPrintIntent.getType();
        }

        @JavascriptInterface
        public String getTitle() {
            return cloudPrintIntent.getExtras().getString("title");
        }

        @JavascriptInterface
        public String getContent() {
            try {
                ContentResolver contentResolver = getActivity().getContentResolver();
                InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                byte[] buffer = new byte[4096];
                int n = is.read(buffer);
                while (n >= 0) {
                    baos.write(buffer, 0, n);
                    n = is.read(buffer);
                }
                is.close();
                baos.flush();

                return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }

        @JavascriptInterface
        public String getEncoding() {
            return CONTENT_TRANSFER_ENCODING;
        }

        @JavascriptInterface
        public void onPostMessage(String message) {
            if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
                finish();
            }
        }
    }