美文网首页iOS开发我爱编程@IT·互联网
WebView与Javascript交互及JS的注入

WebView与Javascript交互及JS的注入

作者: 路Promenade | 来源:发表于2017-01-11 23:44 被阅读2848次
    本篇目录

    前言

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


    一、Java 调用 JS 中函数

    1.添加权限(这里使用资源目录下写好的html文件)
    <uses-permission android:name="android.permission.INTERNET"/>
    
    2.webView配置
    ...
    // 省略掉findView..webview
    mWebView.getSettings().setJavaScriptEnabled(true);
    
    3.利用webViewloadUrl()方法调用JS中函数

    注意调用的函数前面添加javascript:

    ...
    btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // 调用JS中无参数的函数
            mWebView.loadUrl("javascript:javacalljs()");
            mWebView.loadUrl("javascript:javacalljswith(\"JAVA调用了JS的有参函数\")");
            }
        });
    ...
    

    二、JS 调用 Java 中方法

    1.添加js的回调接口

    第一个参数是接收回调的类,这里写成当前的类,接下来会在当前类中添加被js调用的方法。obj为别名,和js中保持一致。

    mWebView.addJavascriptInterface(this, "obj");
    
    2.java中添加被js调用的方法。

    <font color="red">注意一定不要忘记添加@JavascriptInterface</font>这里的方法和web.html中的window.obj.localMethods('Incoming parameters')保持一致。

    ...
    @JavascriptInterface
    public void localMethods(String arg) {
        Log.i(TAG, "This method is called!");
        Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
    }
    

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

    1.注入JS方法

    这里注入时机是onPageFinished()后;注入的JS是一个alert为例。

    public class JsInjectionActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...  
            InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();  
            mWebView.setWebChromeClient(new WebChromeClient());
            mWebView.setWebViewClient(mInsideWebViewClient);
            WebSettings webSettings = mWebView.getSettings();
            webSettings.setJavaScriptEnabled(true);
            mWebView.addJavascriptInterface(JsInjectionActivity.this, "obj");
            mWebView.loadUrl("file:///android_asset/web.html");
            ...
        }
        
        private class InsideWebViewClient extends WebViewClient {
    
            @Override
            public void onPageFinished(WebView view, String url) {
                mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
                super.onPageFinished(view, url);
            }
        }
    }
    ...
    

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

    2.(重点)注入的js导致的问题或可能出现的问题
    1. 注入js可能会导致加载的html5页面总是一直在加载中,加载很慢或干脆加载不出来,这个问题不是针对所有的html5可能在某些网页上会遇到这个问题;
    2. 注入JS后回调函数没有执行到;

    解决方法:

    @Override    
    protected void onPause(){    
        super.onPause();    
      
        mWebView.pauseTimers();    
        if(isFinishing()){    
            mWebView.loadUrl("about:blank");    
            setContentView(new FrameLayout(this));    
        }    
    }    
      
    @Override    
    protected void onResume(){    
        super.onResume();    
        mWebView.resumeTimers();    
    }    
    

    调用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

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=gb2312">
        <script type="text/javascript">
    
        function javacalljs(){
            document.getElementById("content").innerHTML = "<br>JAVA调用了JS的无参函数";
        }
    
        function javacalljswith(arg){
            document.getElementById("content").innerHTML = ("<br>"+arg);
        }
    
        </script>
    </head>
    <body>
    HTML 内容显示 <br/>
    <h1>
        <div id="content">内容显示</div>
    </h1>
    <br/>
    <input type="button" value="点击调用java代码" onclick="window.obj.localMethods('Incoming parameters')"/><br/>
    </body>
    </html>
    
    
    2. JsInjectionActivity.java文件
    public class JsInjectionActivity extends Activity {
        private static final String TAG = JsInjectionActivity.class.getSimpleName();
    
        private WebView mWebView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button btn_invoke_js1 = (Button) findViewById(R.id.btn_invoke_js1);
            Button btn_invoke_js2 = (Button) findViewById(R.id.btn_invoke_js2);
    
            mWebView = (WebView) findViewById(R.id.webview);
    
            InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient();
            mWebView.setWebChromeClient(new WebChromeClient());
            mWebView.setWebViewClient(mInsideWebViewClient);
            WebSettings webSettings = mWebView.getSettings();
            webSettings.setJavaScriptEnabled(true);
            mWebView.addJavascriptInterface(JsInjectionActivity.this, "obj");
            mWebView.loadUrl("file:///android_asset/web.html");
    
            btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mWebView.loadUrl("javascript:javacalljs()");
                }
            });
    
            btn_invoke_js2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mWebView.loadUrl("javascript:javacalljswith(\"JAVA调用了JS的有参函数\")");
                }
            });
        }
    
        @JavascriptInterface
        public void localMethods(String arg) {
            Log.i(TAG, "This method is called!");
            Toast.makeText(this, "This method is called!", Toast.LENGTH_SHORT).show();
        }
    
        private class InsideWebViewClient extends WebViewClient {
    
            @Override
            public void onPageFinished(WebView view, String url) {
                mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
                super.onPageFinished(view, url);
            }
        }
    
    }
    

    最后

    不懂得地方欢迎私信我,我会在第一时间给予回复,如阅读中发现写错的地方,欢迎纠正。

    相关文章

      网友评论

      • CAVS_嘉伟:你好,我想修改一个网页上的按钮让它隐藏起来 view.loadUrl("javascript:document.getElementById(\"fgtPayPwd_sendBtn\").style.display=\"none\";");这样写怎么不行
        CAVS_嘉伟:麻烦您了,我很困惑,fgtPayPwd_sendBtn是按钮的id
      • 番茄煎蛋卷:那个调用java的回掉的方式是有问题的,在手机4.4还是哪个会包cantmatchweb,,,,直接崩溃,不要用那种方式
        路Promenade:@番茄煎蛋卷 嗯嗯,谢谢提醒,我查看查看
        番茄煎蛋卷:@路国强 嗯,我现在是用内部类的方式实现回掉的,之前在友盟发现了那个bug也确认不了是哪里崩溃,定位不到具体哪行报错,后来是借的新测试机复现的,
        路Promenade:@番茄煎蛋卷 注解吗??
      • needrunning:这样操作的话能把用户的身份信息传到webview,这块有什么经验吗
      • 冰川孤辰js::joy: 被目录骗了,原来是图片...
        路Promenade::relaxed: 方便读者条理性阅读
      • c3b32a2528f2:哇塞,这么厉害
      • 75cfc2c856d8:写的不错:smile:

      本文标题:WebView与Javascript交互及JS的注入

      本文链接:https://www.haomeiwen.com/subject/eqqdbttx.html