【问题标题】:Call Java function from JavaScript over Android WebView通过 Android WebView 从 JavaScript 调用 Java 函数
【发布时间】:2012-05-10 12:00:25
【问题描述】:

我想在我的 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 执行被破坏了还是什么?

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

【问题讨论】:

    标签: javascript android android-webview


    【解决方案1】:

    我认为这不是让 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);
        }
    }
    

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

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

    <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 或更高版本,则需要在要导出到Web 视图的每个方法上方添加注释@JavascriptInterface

    【讨论】:

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

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

    【讨论】:

      【解决方案3】:

      YourJavaScriptInterface”类中定义的方法,不要忘记用“@JavascriptInterface”注解你要暴露的每个方法,否则不会触发该方法。 p>

      例如,以下代码来自 Google 云打印 JavaScript 接口,用于从 web 视图页面调用:

              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();
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-15
        • 2013-06-06
        • 2011-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-31
        • 1970-01-01
        相关资源
        最近更新 更多