学习大纲:
WebSettings
常用方法
WebViewClient
1、常用方法
不错的参考
https://blog.csdn.net/violetjack0808/article/details/52936157
1. 交互方式总结
Android与JS通过WebView互相调用方法,实际上是:
Android去调用JS的代码
JS去调用Android的代码
二者沟通的桥梁是WebView
对于Android调用JS代码的方法有2种:
1. 通过WebView的loadUrl()
2. 通过WebView的evaluateJavascript()
通过WebView的evaluateJavascript()
优点:该方法比第一种方法效率更高、使用更简洁。
因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。
Android 4.4 后才可使用
具体使用
// 只需要将第一种方法的loadUrl()换成下面该方法即可
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
}
使用建议
两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法
// Android版本变量
final int version = Build.VERSION.SDK_INT;
// 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断
if (version < 18) {
mWebView.loadUrl("javascript:callJS()");
} else {
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
}
对于JS调用Android代码的方法有3种:
1. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
2. 通过WebView的addJavascriptInterface
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息
第二种方式:
// 继承自Object类
public class AndroidtoJs extends Object {
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS调用了Android的hello方法");
}
}
在Android通过WebViewClient复写shouldOverrideUrlLoading ()
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
、
WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息在JS中,有三个常用的对话框方法:
方式3的原理:Android通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调
分别拦截JS对话框 (即上述三个方法),得到他们的消息内容,然后解析即可。
常用的拦截是:拦截 JS的输入框(即prompt()方法)
因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
步骤1:加载JS代码,如下:
javascript.html
以.html格式放到src/main/assets文件夹里
function clickprompt(){
// 调用prompt()
var result=prompt("js://demo?arg1=111&arg2=222");
alert("demo " + result);
}
当使用mWebView.loadUrl("file:///android_asset/javascript.html")加载了上述JS代码后,就会触发回调onJsPrompt(),具体如下:
如果是拦截警告框(即alert()),则触发回调onJsAlert();
如果是拦截确认框(即confirm()),则触发回调onJsConfirm();
步骤2:在Android通过WebChromeClient复写onJsPrompt()
public class MainActivity extends AppCompatActivity {
WebView mWebView;
// Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
// 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true);
// 设置允许JS弹窗
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// 先加载JS代码
// 格式规定为:file:///android_asset/文件名.html
mWebView.loadUrl("file:///android_asset/javascript.html");
mWebView.setWebChromeClient(new WebChromeClient() {
// 拦截输入框(原理同方式2)
// 参数message:代表promt()的内容(不是url)
// 参数result:代表输入框的返回值
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// 根据协议的参数,判断是否是所需要的url(原理同方式2)
// 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
//假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)
Uri uri = Uri.parse(message);
// 如果url的协议 = 预先约定的 js 协议
// 就解析往下解析参数
if ( uri.getScheme().equals("js")) {
// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
// 所以拦截url,下面JS开始调用Android需要的方法
if (uri.getAuthority().equals("webview")) {
//
// 执行JS所需要调用的逻辑
System.out.println("js调用了Android的方法");
// 可以在协议上带有参数并传递到Android上
HashMap
Set
//参数result:代表消息框的返回值(输入值)
result.confirm("js调用了Android的方法成功啦");
}
return true;
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述
// 拦截JS的警告框
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
// 拦截JS的确认框
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
}
);
}
}
方式三的调用demo:链接地址如下
webview的缓存机制
Android WebView自带的缓存机制有5种:
1.浏览器 缓存机制
2.Application Cache 缓存机制
3.Dom Storage 缓存机制
4.Web SQL Database 缓存机制
5.Indexed Database 缓存机制
6.File System 缓存机制(H5页面新加入的缓存机制,虽然Android WebView暂时不支持,但会进行简单介绍)
webview的那些坑:
1、内存泄漏问题,尤其注意Android 5.0系统的WebView移除不了的问题;
2、webcorethread的wait问题,不知道什么时候就会发生,完全束手无策。后果是什么?退出页面没有卵用,只能杀进程。
3、Android4.2以下手机的JavaScript interface的注入漏洞问题,完全不要太危险;
WebView中,主要漏洞有三类:
A. 漏洞产生原因
JS调用Android的其中一个方式是通过addJavascriptInterface
接口进行对象映射:
function execute(cmdArgs)
{
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {
if ("getClass" in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime")
// 步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
}
}
}
WebView默认开启密码保存功能 :
mWebView.setSavePassword(true)`
// 设置是否允许 WebView 使用 File 协议
webView.getSettings().setAllowFileAccess(true);
// 默认设置为true,即允许在 File 域下执行任意 JavaScript 代码
使用 file 域加载的 js代码能够使用进行同源策略跨域访问,从而导致隐私信息泄露
- 同源策略跨域访问:对私有目录文件进行访问
- 针对 IM 类产品,泄露的是聊天信息、联系人等等
- 针对浏览器类软件,泄露的是cookie 信息泄露。
如果不允许使用 file 协议,则不会存在上述的威胁;
webView.getSettings().setAllowFileAccess(true);
// 禁用 file 协议;
setAllowFileAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileU
4、弱鸡的一系列ui问题,滚动,滑动,兼容,把网页前端哥们苦不堪言,找Android前端同事投诉,Android同学很无奈,
完全不知道该怎么办。
参考:
https://www.jianshu.com/p/d2d4f652029d
https://www.jianshu.com/p/3a345d27cd42
https://blog.csdn.net/yyanjun/article/details/79918326