WebView与Javascript交互及JS的注入

简介: 本篇目录前言本篇讲解Java代码和Javascript代码的相互调用以及JS代码在Java中是如何动态的注入WebView中。一些通用配置在第一部分中说明。
img_132368f26e10968755fca86391911733.png
本篇目录

前言

本篇讲解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);
        }
    }

}

最后

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

目录
相关文章
|
6月前
|
资源调度 JavaScript 前端开发
Day.js极简轻易快速2kB的JavaScript库-替代Moment.js
dayjs是一个极简快速2kB的JavaScript库,可以为浏览器处理解析、验证、操作和显示日期和时间,它的设计目标是提供一个简单、快速且功能强大的日期处理工具,同时保持极小的体积(仅 2KB 左右)。
372 24
|
9月前
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
210 32
|
8月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
11月前
|
数据采集 人工智能 自然语言处理
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
Midscene.js 是一款基于 AI 技术的 UI 自动化测试框架,通过自然语言交互简化测试流程,支持动作执行、数据查询和页面断言,提供可视化报告,适用于多种应用场景。
2839 1
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
195 3
springboot解决js前端跨域问题,javascript跨域问题解决
|
JavaScript 前端开发
Moment.js与其他处理时间戳格式差异的JavaScript库相比有什么优势?
Moment.js与其他处理时间戳格式差异的JavaScript库相比有什么优势?
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
435 5
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
331 4
下一篇
oss云网关配置