WebView用法简介

一、WebView基本用法

mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
mWebView.setWebChromeClient(new MyWebChromeClient());
mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");
mWebView.loadUrl("file:///android_asset/demo.html");
复制代码

1. 支持Js

mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebSettings.setJavaScriptEnabled(true);// 支持js
复制代码

2. 缩放设置

// 设置是否构建缩放工具,如果该属性设置为false,则不论其他属性如何设置,均不支持缩放。
mWebSettings.setBuiltInZoomControls(true);
mWebSettings.setSupportZoom(true);
// 不显示缩放控件
mWebSettings.setDisplayZoomControls(false);
复制代码

3. WebView适应屏幕大小

方法1:(推荐使用)

mWebSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
mWebSettings.setUseWideViewPort(true);  //将图片调整到适合webview的大小
复制代码

方法2:(deprecated)

mWebSettings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
复制代码

LayoutAlgorithm是一个枚举用来控制页面的布局,有四个类型:

  1. NARROW_COLUMNS:可能的话使所有列的宽度不超过屏幕宽度(deprecated)
  2. NORMAL:正常显示不做任何渲染
  3. SINGLE_COLUMN:把所有内容放大webview等宽的一列中(deprecated)
  4. TEXT_AUTOSIZING:

方法3:主要针对平板设备

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int mDensity = metrics.densityDpi;
if (mDensity == 120) { //mdpi
    settings.setDefaultZoom(ZoomDensity.CLOSE);
}else if (mDensity == 160) { //hdpi
    settings.setDefaultZoom(ZoomDensity.MEDIUM);
}else if (mDensity == 240) { //xhdpi
    settings.setDefaultZoom(ZoomDensity.FAR);
}
复制代码

4. WebViewClient

WebViewClient主要帮助处理各种通知请求事件等,比如页面开始加载,加载完成等。 用法:

webview.setWebViewClient(new MyWebViewClient());
复制代码

在此只介绍一些通用的方法,其他方法具体参见WebViewCLient源代码

public class MyWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);//WebView自己打开新的页面,不调用系统浏览器
        return true;
        //return super.shouldOverrideUrlLoading(view, url);
    }

    //页面加载完毕之后调用,在此可以做一些js注入
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
    }

   //页面开始加载时回调
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
    }

    //当接收到错误时回调,通常是网络不通
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        view.loadUrl("file:///android_asset/network_warning.htm");
    }

    //服务器返回错误时回调,例如返回400
    @Override
    public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
        view.loadUrl("file:///android_asset/service_error.htm");
    }
}
复制代码

5. WebChromeClient

WebChromeClient主要辅助WebView处理javascript对话框,网站图标,网站标题,加载进度等等。

webView.setWebChromeClient(new MyWebChromeClient());
复制代码
public class MyWebChromeClient extends WebChromeClient {
    //接收到网站标题时回调,在此可以设置title
    @Override
    public void onReceivedTitle(WebView view, String title) {
        super.onReceivedTitle(view, title);
    }

    @Override
    public void onReceivedIcon(WebView view, Bitmap icon) {
        super.onReceivedIcon(view, icon);
    }

    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        progressbar.setProgress(newProgress);
    }


}
复制代码

6. 缓存机制

WebView提供了两种缓存:

  1. 数据缓存:分为AppCache和DOM Storage(Web Storage)两种;
  2. 网页缓存。是指加载一个网页时html、JS、CSS等页面或者资源数据。

缓存路径

WebView将缓存保存在内部存储的缓存目录中:/data/data/packageName/app_webview/。

WebView缓存路径: !

/shared_prefs/WebViewChromiumPrefs.xml里面保存了一些WebView的偏好设置 /app_webview中则保存了网页缓存。

WebView网页缓存文件 !

其中,在cache目录下保存了网页数据(html,css,js,图片,文本等),在访问缓存时,WebView会根据自己的缓存策略来查找缓存文件;其他文件保存了网页缓存。

WebView除了提供网页缓存之外,还有数据缓存,数据缓存由网页开发者控制,通常用来保存一些用户行为(例如:用户搜索记录)。我们只需要指定缓存的位置即可。

webview.getSettings().setAppCachePath(cachepath);
webview.getSettings().setAppCacheEnabled(true);
复制代码

注意:API版本不同,可能得到不同的结论,例如缓存路径可能为/data/data/packageName/cache/webviewCache,可能使用SQLite来保存缓存文件的索引等等,但唯一不变的是:WebView所有的缓存文件肯定都位于内部存储中,也即位于: /data/data/packageName/

但是我们在关于android存储方案你所需要知道的一切一文中提到过:内部存储的缓存目录不应该超过一定的限制,比如1M,而且当系统内部存储紧张时,会在不通知用户的前提下,将缓存文件删除。所以我们应该尽量将WebView的缓存保存在外部存储的缓存文件中。

7. 用户代理User Agent

在Web开发中,user-agent用来标识浏览器的类型,一般由浏览器自己填写,例如Win10-Chrome浏览器是:

Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
复制代码

因此在移动开发中,我们可以使用user-agent来标识不同的设备,从而做出适配或统计分析,例如在华为荣耀7中UC浏览器的user-agent是:

Mozilla/5.0 (Linux; U; Android 6.0; zh-CN; PLK-UL00 Build/HONORPLK-UL00) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 UCBrowser/11.0.5.841 U3/0.8.0 Mobile Safari/534.30
复制代码

但是user-agent如此之长,不方便识别,因此我们通常会将user-agent设置为易分辨的字段,例如:"android"来表示该请求来自android手机

二、与Js交互

使用WebView可以调用html中的js代码,js也可以调用Java代码。两者要进行交互,那么就得有交互的接口。android中使用webView.addJavaScriptInterface(Object, String)方法来建立java与js之间的接口。

1. js调用Java代码

首先我们得定义js与java交互的接口,该接口只需要是一个Object对象即可

public class JavaScriptInterface{

    @JavascriptInterface
    public void callByJs(){
        Log.i(TAG, "this is called by js");
        webview.reload();
    }

}

//建立js与java的关系
webview.addJavaScriptInterface(new JavaScriptInterface(), "reload");//“reload”参数在js中用到,用以标识JavaScriptInterface对象

复制代码

然后在js中调用该目标方法即可,调用方式如下:

<html>

    <body>
        <!-- Calls into the javascript interface for the activity -->
        <a onClick="window.reload.callByJs()">
            <div style="width:80px;
                margin:0px auto;
                padding:10px;
                text-align:center;
                border:2px solid #202020;" >
                <img id="droid" src="android_normal.png"/><br>
                    Click me!
            </div>
        </a>
    </body>

</html>
复制代码

使用方法十分简单,但要注意在api及其17以上,只有将方法添加**@JavascriptInterface**注解才可以被js调用。

Java调用js代码

在java中调用js代码也很easy。在上一节,我们点击超链接标签之后会打印出一个log,我们将它改为点击之后更换img中的src,因此我们只需要将JavaScriptInterface中的callByJs修改如下:

public class JavaScriptInterface{
    @JavascriptInterface
    public void callByJs(){
        webView.loadUrl("javascript:callByJava()");
    }
}

复制代码

然后将html文档修改为:

<html>
     <script language="javascript">
        /* This function is invoked by the activity */
        function callByJava() {
            document.getElementById("droid").src="android_waving.png";
        }
    </script>

    <body>
        <!-- Calls into the javascript interface for the activity -->
        <a onClick="window.reload.callByJs()">
            <div style="width:80px;
                margin:0px auto;
                padding:10px;
                text-align:center;
                border:2px solid #202020;" >
                <img id="droid" src="android_normal.png"/><br>
                    Click me!
            </div>
        </a>
    </body>

</html>
复制代码

再点击超链接标签之后就会将img的图片更换为android_waving.png。

注意:通过[官方文档](https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)可知,当TargetApi大于等于17时,js仅能调用添加了JavaScriptInterface注解的public methods,当targetApi小于17时,即便没有JavaScriptInterface注解,所有的public method也可以被js调用(包括继承而来的public method)。因此当TargetApi小于17时,js就可以使用反射来访问注入到js中的public域,所以当访问某些不信任的网页时,宿主App就可能被攻击。 还有,一定要记住,即便TargetApi >= 17,但如果你的App运行在android17以下,那么App还是有可能会被攻击。 所以,使用js注入最安全的方式就是仅允许TargetApi>=17且android4.2及以后才允许js访问Java对象。

三、混淆

在注入js之后,如果混淆了注入js的类,则注入的js就无法正确运行了,所以必须防止混淆。

不熟悉代码混淆的伙伴可以去看看这儿

-keepclassmembers class com.codemperor.summary.TestActivity$JavascriptMethodClass { public *; }
# 以下两行为在Android4.2版本以上的手机必须加入的对注解进行处理的配置
-keepattributes *Annotation*
-keepattributes *JavascriptInterface*
复制代码

转载于:https://juejin.im/post/5a3d2b7ef265da432653087d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值