Android WebView使用简单介绍

一 Android客户端注入及清除Cookie

在Android应用程序中经常会加载一个WebView页,有时需要客户端存取访问网页时服务器传递过来的Cookie,在下次访问相同网页时通过Cookie中携带的Session来避免服务端的再次验证。Cookie信息一般是在发出http请求加载网页url时,通过http header传递过去。

1、客户端通过以下代码保存Cookie
public static void synCookies(Context context, String url) {  
        CookieSyncManager.createInstance(context);  
        CookieManager cookieManager = CookieManager.getInstance();  
        cookieManager.setCookie(url, "uid=1243432");                
        CookieSyncManager.getInstance().sync();  
    }
2、Cookie传递过程

CookieManager 会将这个Cookie存入该应用程序/data/data/databases/目录下的webviewCookiesChromium.db数据库的cookies表中; 打开网页时,WebView会从数据库中读取该cookie值,放在http请求的头部,传递到服务器。

3、客户端可以在注销时清除该应用程序用到的所有cookies
private void removeCookie(Context context) {
        CookieSyncManager.createInstance(context);  
        CookieManager cookieManager = CookieManager.getInstance(); 
        cookieManager.removeAllCookie();
        CookieSyncManager.getInstance().sync();  
    }

二 Android WebView缓存

当我们加载Html时候,会在我们data/应用package下生成database与cache两个文件夹。我们请求的Url记录是保存在webviewCache.db里,而url的内容是保存在webviewCache文件夹下。如图所示:

这里写图片描述

1、缓存构成:

/data/data/package_name/cache/webviewCache
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

2、WebView缓存模式介绍

缓存模式(四种)

  • LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据。
  • LOAD_NO_CACHE: 不使用缓存,只从网络获取数据。
  • LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据。
  • LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网络,只要本地有缓存,都使用缓存; 本地没有缓存时才从网络上获取。

如:www.taobao.com的cache-control为no-cache,在模式LOAD_DEFAULT下,无论如何都会从网络上取数据,如果没有网络,就会出现错误页面;在LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网络,只要本地有缓存,都使用缓存。本地没有缓存时才从网络上获取。
www.360.com.cn的cache-control为max-age=60,在两种模式下都使用本地缓存数据。

总结:根据以上两种模式,建议缓存策略为,判断是否有网络,有的话,使用LOAD_DEFAULT,无网络时,使用LOAD_CACHE_ELSE_NETWORK。

3、设置WebView缓存
/**
     * 设置WebView缓存
     * cacheDirPath:/data/data/package_name/files/app_webview
     */
    private void setWebviewCache(WebSettings webSettings){
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSettings.setDomStorageEnabled(true);
        webSettings.setDatabaseEnabled(true);
        String cacheDirPath = getFilesDir().getParent()+"/app_webview";
        //设置数据库缓存路径
        webSettings.setDatabasePath(cacheDirPath);
        //设置  Application Caches 缓存目录
        webSettings.setAppCachePath(cacheDirPath);
        //开启 Application Caches 功能
        webSettings.setAppCacheEnabled(true);
    }
4、清除WebView缓存
public static void clearWebviewCache(Context context){
        String webviewPath = context.getFilesDir().getParent() + "/app_webview";
        FileUtil.deleteDirectoryFiles(new File(webviewPath));
        /*context.deleteDatabase("webview.db");
        context.deleteDatabase("webviewCache.db");*/
        }

/**递归删除文件*/
public static void deleteDirectoryFiles(File directory){
        if(directory != null && directory.exists() && directory.isDirectory()){
            try{
                for(File child : directory.listFiles()){
                    if(child.isDirectory()){
                        deleteDirectoryFiles(child);
                    }else{
                        child.delete();
                    }
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }

三、向WebView注入Java对象

1、官方介绍Java与JS交互:

如果需要Java与页面Js进行交互,需要使用方法webView.addJavascriptInterface(Object, String) ,这个方法是把当前应用的Java对象注入到WebView页面的JS中,以至于JS能发起对该Java对象的调用。

Injecting Java objects into the WebView using the addJavascriptInterface(Object, String) method. This method allows you to inject Java objects into a page's JavaScript context, so that they can be accessed by JavaScript in the page.
2、官方对addJavascriptInterface()方法的补充解释,主要有四点:
oid addJavascriptInterface (Object object, 
                String name)
1、Injects the supplied Java object into this WebView.
2、 The object is injected into the JavaScript context of the main frame, using the supplied name. This allows the Java object's methods to be accessed from JavaScript.
3、 For applications targeted to API level JELLY_BEAN_MR1 and above, only public methods that are annotated with JavascriptInterface can be accessed from JavaScript. 
4、For applications targeted to API level JELLY_BEAN or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.

总结起来就是,在Android4.2版本之前,要实现Java与JS交互需要满足:

  1. 使用addJavascriptInterface (),向JS中注入Java对象;
  2. JS调用该对象的方法必须是Public;
  3. JS调用该对象的方法必须添加了@JavascriptInterface 注解;
3、@JavascriptInterface注解的作用:
Annotation that allows exposing methods to JavaScript.
4、在低版本4.2以前使用addJavascriptInterface ()存在的安全泄漏风险
With these older versions, JavaScript could use reflection to access an
   injected object's public fields. Use of this method in a WebView
    containing untrusted content could allow an attacker to manipulate the
      host application in unintended ways, executing Java code with the
      permissions of the host application. Use extreme care when using this
     method in a WebView which could contain untrusted content
JS会通过反射获取到注入的Java对象的成员变量;
For applications targeted to API level JELLY_BEAN or below, all public methods (including the inherited ones) can be accessed
webview可以拿到所有public的方法,包括父类的public方法,比如Object类的getClass方法。那么通过反射就可以获取任意类的对象,比如Runtime对象,这样的话太危险了。
5、在Android4.2以前,解决addJavascriptInterface ()的办法

使用WebChromeClient对象的onJsPrompt方法与js进行交互,onJsPrompt方法可以获取js传给本地的消息信息,同时可以返回消息给js,具体步骤为:

第一步:

if (Build.VERSION.SDK_INT >= 17) {
    // 在sdk4.2及以上的系统上继续使用addJavascriptInterface
    webView.addJavascriptInterface(new JSCallManager(), "Native");
} else {
    //4.2之前 addJavascriptInterface有安全泄漏风险
    //移除js中的searchBoxJavaBridge_对象,在Android 3.0以下,系统自己添加了一个叫searchBoxJavaBridge_的Js接口,要解决这个安全问题,我们也需要把这个接口删除;
jsCallManager = new JSCallManager();
webView.removeJavascriptInterface("searchBoxJavaBridge_");
}

第二步:

webView.setWebViewClient(new WebViewClient(){
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                view.loadUrl("JavaScript:if(window.Native == undefined){" +"window.Native={call:function(arg0,arg1){prompt('{\"methodName\":' + arg0 + ',\"jsonValue\":'+ arg1 + '}')}}};");
            }
        });

第三步:

//WebChromeClient的方法,当JS调用prompt()方法时会触发onJsPrompt方法回调;
        //message就是js传递给本地的消息;
        //result.confirm是回传给js的信息;
        webView.setWebChromeClient(new WebChromeClient(){

            @Override
            public boolean onJsPrompt(WebView view, String url, final String message, String defaultValue,final JsPromptResult result) {
                if(Build.VERSION.SDK_INT<17){
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try{
                                JSONObject jsonObject=new JSONObject(message);
                                String methodName=jsonObject.optString("methodName");
                                String jsonValue=jsonObject.optString("jsonValue");
                                String resultString=jsCallManager.call(methodName,jsonValue);
                                result.confirm(resultString);
                            }catch (Exception e){

                            }
                        }
                    }).start();
                }
                return true;
                //return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });

参考致谢:
1、Android客户端注入及清除Cookie
http://my.oschina.net/tingzi/blog/193697
2、Android okHttp网络请求之缓存控制Cache-Control(四)
http://www.cnblogs.com/whoislcj/p/5537640.html
3、Android WebView开发
http://blog.csdn.net/typename/article/details/39495409
4、Android4.2下 WebView的addJavascriptInterface漏洞解决方案
http://blog.csdn.net/zhouyongyang621/article/details/47000041
5、WebView addJavascriptInterface接口中的隐忧解决方法
http://blog.csdn.net/owillll/article/details/20996139
6、Android WebView的Js对象注入漏洞解决方案
http://blog.csdn.net/leehong2005/article/details/11808557

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值