UDN-企业互联网技术人气社区

板块导航

浏览  : 1332
回复  : 11

[原生js] WebView与JavaScript交互及JS的注入

[复制链接]
htmlman的头像 楼主
发表于 2017-2-10 10:43:40 | 显示全部楼层 |阅读模式

  前言

  本篇讲解 Java 代码和 JavaScript 代码的相互调用以及 JS 代码在 Java 中是如何动态的注入 WebView 中。一些通用配置在第一部分中说明。

  一、Java 调用 JS 中函数

  1.添加权限(这里使用资源目录下写好的html文件)
  1. <uses-permission android:name="android.permission.INTERNET"/>
复制代码

  2.webView配置
  1. ...
  2. // 省略掉findView..webview
  3. mWebView.getSettings().setJavaScriptEnabled(true);
复制代码

  3.利用 webView 的 loadUrl() 方法调用JS中函数

  注意调用的函数前面添加 JavaScript:
  1. ...
  2. btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
  3.     @Override
  4.     public void onClick(View view) {
  5.         // 调用JS中无参数的函数
  6.         mWebView.loadUrl("JavaScript:javacalljs()");
  7.         mWebView.loadUrl("JavaScript:javacalljswith(\"JAVA调用了JS的有参函数\")");
  8.         }
  9.     });
  10. ...
复制代码

  二、JS 调用 Java 中方法

  1.添加js的回调接口

  第一个参数是接收回调的类,这里写成当前的类,接下来会在当前类中添加被 js 调用的方法。 obj 为别名,和 js 中保持一致。
  1. mWebView.addJavaScriptInterface(this, "obj");
复制代码

  2.java中添加被js调用的方法。

  <font color="red">注意一定不要忘记添加@JavaScriptInterface</font>这里的方法和web.html中的 window.obj.localMethods('Incoming parameters') 保持一致。
  1. ...
  2. @JavaScriptInterface
  3. public void localMethods(String arg) {
  4.     Log.i(TAG, "This method is called!");
  5.     Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
  6. }
复制代码

  三、(重点)Java 中动态注入 JS

  1.注入JS方法

  这里注入时机是 onPageFinished() 后;注入的JS是一个 alert 为例。
  1. public class JsInjectionActivity {
  2.     @Override
  3.     protected void onCreate(Bundle savedInstanceState) {
  4.         ...  
  5.         InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();  
  6.         mWebView.setWebChromeClient(new WebChromeClient());
  7.         mWebView.setWebViewClient(mInsideWebViewClient);
  8.         WebSettings webSettings = mWebView.getSettings();
  9.         webSettings.setJavaScriptEnabled(true);
  10.         mWebView.addJavaScriptInterface(JsInjectionActivity.this, "obj");
  11.         mWebView.loadUrl("file:///android_asset/web.html");
  12.         ...
  13.     }

  14.     private class InsideWebViewClient extends WebViewClient {

  15.         @Override
  16.         public void onPageFinished(WebView view, String url) {
  17.             mWebView.loadUrl("JavaScript:" + "window.alert('Js injection success')" );
  18.             super.onPageFinished(view, url);
  19.         }
  20.     }
  21. }
  22. ...
复制代码

  注意:以上注入的 js 包含一个 alert ,写完后可能会发现 alert 没有弹出来。这时要去检查 myWebView.setWebChromeClient(new WebChromeClient()); 是否设置了。

  2.(重点)注入的js导致的问题或可能出现的问题

  注入 js 可能会导致加载的 html5 页面总是一直在加载中,加载很慢或干脆加载不出来,这个问题不是针对所有的 html5 可能在某些网页上会遇到这个问题;

  注入JS后回调函数没有执行到;

  解决方法:
  1. @Override   
  2. protected void onPause(){   
  3.     super.onPause();   

  4.     mWebView.pauseTimers();   
  5.     if(isFinishing()){   
  6.         mWebView.loadUrl("about:blank");   
  7.         setContentView(new FrameLayout(this));   
  8.     }   
  9. }   

  10. @Override   
  11. protected void onResume(){   
  12.     super.onResume();   
  13.     mWebView.resumeTimers();   
  14. }
复制代码

  调用 webView.loadUrl("about:blank"); 该方法使得webView只回执一个白色背景,并且 释放之前加载页面时使用的资源,并停止之前JavaScript的执行 。

  pauseTimers , onPause 停止解析, JavaScript 执行等操作.区别是 onPause 只作用于调用它的WebView,而 pauseTimers 作用于当前应用中所有的 WebView

  resumeTimers , onResume 恢复解析, JavaScript 执行等操作.区别是 onResume 只作用于调用它的 WebView ,而 resumeTimers 作用于当前应用中所有的WebView。

  3.当压缩后的JS注入到webView中时,注入没有生效

  我的解决方式:

  把 JS 格式化后或是非压缩状态注入成功,不知道别人有没有遇到过类似问题,或者是其它原因,这里有疑问,如果有遇到相同问题的,欢迎一起交流。

  在线js格式化,缩进方式选择:4个空格缩进

  http://tool.oschina.net/codeformat/js

  四、完整代码
 
  完整代码,不包含js注入遇到的问题部分,自行加入。

  1. web.html 文件

  文件路径:..src/main/assets/web.html
  1. <html>
  2. <head>
  3.     <meta http-equiv="Content-Type" content="text/html;charset=gb2312">
  4.     <script type="text/JavaScript">

  5.     function javacalljs(){
  6.         document.getElementById("content").innerHTML = "<br>JAVA调用了JS的无参函数";
  7.     }

  8.     function javacalljswith(arg){
  9.         document.getElementById("content").innerHTML = ("<br>"+arg);
  10.     }

  11.     </script>
  12. </head>
  13. <body>
  14. HTML 内容显示 <br/>
  15. <h1>
  16.     <div id="content">内容显示</div>
  17. </h1>
  18. <br/>
  19. <input type="button" value="点击调用java代码" onclick="window.obj.localMethods('Incoming parameters')"/><br/>
  20. </body>
  21. </html>
复制代码

  2. JsInjectionActivity.java 文件
  1. public class JsInjectionActivity extends Activity {
  2.     private static final String TAG = JsInjectionActivity.class.getSimpleName();

  3.     private WebView mWebView;

  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.activity_main);
  8.         Button btn_invoke_js1 = (Button) findViewById(R.id.btn_invoke_js1);
  9.         Button btn_invoke_js2 = (Button) findViewById(R.id.btn_invoke_js2);

  10.         mWebView = (WebView) findViewById(R.id.webview);

  11.         InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();
  12.         mWebView.setWebChromeClient(new WebChromeClient());
  13.         mWebView.setWebViewClient(mInsideWebViewClient);
  14.         WebSettings webSettings = mWebView.getSettings();
  15.         webSettings.setJavaScriptEnabled(true);
  16.         mWebView.addJavaScriptInterface(JsInjectionActivity.this, "obj");
  17.         mWebView.loadUrl("file:///android_asset/web.html");

  18.         btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
  19.             @Override
  20.             public void onClick(View view) {
  21.                 mWebView.loadUrl("JavaScript:javacalljs()");
  22.             }
  23.         });

  24.         btn_invoke_js2.setOnClickListener(new View.OnClickListener() {
  25.             @Override
  26.             public void onClick(View view) {
  27.                 mWebView.loadUrl("JavaScript:javacalljswith(\"JAVA调用了JS的有参函数\")");
  28.             }
  29.         });
  30.     }

  31.     @JavaScriptInterface
  32.     public void localMethods(String arg) {
  33.         Log.i(TAG, "This method is called!");
  34.         Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
  35.     }

  36.     private class InsideWebViewClient extends WebViewClient {

  37.         @Override
  38.         public void onPageFinished(WebView view, String url) {
  39.             mWebView.loadUrl("JavaScript:" + "window.alert('Js injection success')" );
  40.             super.onPageFinished(view, url);
  41.         }
  42.     }

  43. }
复制代码

相关帖子

发表于 2017-2-10 10:44:38 | 显示全部楼层
Very Good!
使用道具 举报

回复

发表于 2017-2-10 11:22:37 | 显示全部楼层
感觉JavaScript很有前途
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部