博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WebView
阅读量:6614 次
发布时间:2019-06-24

本文共 15161 字,大约阅读时间需要 50 分钟。

hot3.png

WebView是一个用来展示web页面的控件。

1.WebSetting

WebView mWebView = (WebView)findViewById(R.id.webview);        WebSettings webSettings = mWebView.getSettings();        //支持获取手势焦点,输入用户名、密码或其他        mWebView.requestFocusFromTouch();        //支持JS        webSettings.setJavaScriptEnabled(true);        //支持插件,没有该方法,,?        //webSettings.setPluginsEnabled(true);        //提高渲染的优先级        webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);        //设置自适应屏幕,两者合用        webSettings.setUseWideViewPort(true);//将图片调整到合适webview的大小        webSettings.setLoadWithOverviewMode(true);//缩放至屏幕的大小        //支持缩放,默认为true,是下面那个的前提        webSettings.setSupportZoom(true);        //设置内置的缩放控件,若上面是false,则该webview不可缩放,这个不管设置什么都不能缩放        webSettings.setBuiltInZoomControls(true);        //隐藏原生的缩放控件        webSettings.setDisplayZoomControls(false);        //支持内容重新布局        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);        //多窗口        webSettings.supportMultipleWindows();        //关闭webView中缓存        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);        //设置可以访问文件        webSettings.setAllowFileAccess(true);        //当webView调用rewuestFocus时为webView设置节点        webSettings.setNeedInitialFocus(true);        //支持通过JS打开新窗口        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);        //支持自动加载图片        webSettings.setLoadsImagesAutomatically(true);        //设置编码格式        webSettings.setDefaultTextEncodingName("utf-8");

缓存模式:

  • LOAD_CACHE_ONLY:不适用网络,只读取本地缓存数据;
  • LOAD_DEFAULT:(默认)根据cache-control决定是否从网络上取数据;
  • LOAD_NO_CACHE:不适用缓存数据,只从网络获取数据;
  • LOAD_CACHE_ELSE_NETWORK:只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
    结合使用(理线加载):
if (有网){            //根据cache-control决定是否从网络上获取数据            webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);        }else {            //没网,则从本地获取,即离线加载            webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);        }        //开启DOM storage API功能        webSettings.setDomStorageEnabled(true);        //开启database storage API功能        webSettings.setDatabaseEnabled(true);        //开启Application Cache功能        webSettings.setAppCacheEnabled(true);        String cacheDirPath = getFilesDir().getAbsolutePath()+"应用缓存路径名APP_CACAHE_DIRNAME";        //设置Application cache缓存目录        webSettings.setAppCachePath(cacheDirPath);

注意:每个Application只调用一次WebSettings.setAppCachePath(),WebSetting.setAppCacheMaxSize()。

2.加载方式

(1)加载一个网页:

mWebView.loadUrl("http://www.google.com/");

(2)加载apk包中的一个html页面:

mWebView.loadUrl("file:///android_asset/test.html");

(3)加载手机本地的一个html页面的方法:

mWebView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");

3.WebViewClient

WebViewClient就是帮助WebView处理各种通知、请求事件的。

打开网页时,不调用系统浏览器,而是在本WebView中显示:

mWebView.setWebViewClient(new WebViewClient(){            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                view.loadUrl(url);                return true;            }        });

WebViewClient的方法:

WebViewClient mWebViewClient = new WebViewClient(){            //最常用的,比如上面的。在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作            //比如获取url,查看url.contains("add"),进行添加操作            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                return super.shouldOverrideUrlLoading(view, url);            }            //重写此方法才能够处理在浏览器中的按键事件            @Override            public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {                return super.shouldOverrideKeyEvent(view, event);            }            //这个时间就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                super.onPageStarted(view, url, favicon);            }            //在页面加载结束时调用,同样道理,我们可以关闭loading条,切换程序动作。            @Override            public void onPageFinished(WebView view, String url) {                super.onPageFinished(view, url);            }            //在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次            @Override            public void onLoadResource(WebView view, String url) {                super.onLoadResource(view, url);            }            //拦截替换网络请求数据,API 11开始引入,API 21弃用            @Override            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {                return super.shouldInterceptRequest(view, url);            }            //拦截替换网络请求数据,API 21开始引入            @Override            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {                return super.shouldInterceptRequest(view, request);            }            //报告错误信息            @Override            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {                super.onReceivedError(view, errorCode, description, failingUrl);            }                        //更新历史记录            @Override            public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {                super.doUpdateVisitedHistory(view, url, isReload);            }            //应用程序重新请求网页数据            @Override            public void onFormResubmission(WebView view, Message dontResend, Message resend) {                super.onFormResubmission(view, dontResend, resend);            }            //获取返回信息授权信息            @Override            public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {                super.onReceivedHttpAuthRequest(view, handler, host, realm);            }            //重写此方法可以让webview处理https请求            @Override            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {                super.onReceivedSslError(view, handler, error);            }            //webview发生改变时调用            @Override            public void onScaleChanged(WebView view, float oldScale, float newScale) {                super.onScaleChanged(view, oldScale, newScale);            }                        //key事件未被加载时调用            @Override            public void onUnhandledKeyEvent(WebView view, KeyEvent event) {                super.onUnhandledKeyEvent(view, event);            }        };

将上面定义的WebViewClient设置给WebView:

mWebView.setWebViewClient(mWebViewClient);

4.WebChromeClient

WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度条等。

方法中的代码都是有Android端自己处理。

WebChromeClient mWebChromeClient = new WebChromeClient(){            //获得网页的加载进度            @Override            public void onProgressChanged(WebView view, int newProgress) {               if (newProgress <100){                   String progress = newProgress+"%";               }else {                                  }            }                        //获取Web页中的title用来设置自己界面中的title            //当加载出错的时候,比如无网络,这时onReceivedTitle中获取的标题为找不到该网页,            //因此建议当触发onReceiveError时不时使用获取到的title            @Override            public void onReceivedTitle(WebView view, String title) {                MainActivity.this.setTitle(title);            }            @Override            public void onReceivedIcon(WebView view, Bitmap icon) {                //            }            @Override            public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {                //                return true;            }            @Override            public void onCloseWindow(WebView window) {                //            }                        //处理alert弹出框,html弹框的一种方式            @Override            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {                return true;            }            //处理prompt弹出框            @Override            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {                return true;            }                        //处理confirm弹出框            @Override            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {                return true;            }        };

同样,将上面定义的WebChromeClient设置给WebView:

mWebView.setWebChromeClient(mWebChromeClient);

5.WebView的其他方法

(1)前进、后退:

mWebView.goBack();//后退        mWebView.goForward();//前进        //以当前的index为起始点前进或者后退到历史纪录中指定的steps,        //如果steps为负数则后退,正数则为前进        mWebView.goBackOrForward(steps);                mWebView.canGoBack();//是否可以后退        mWebView.canGoForward();//是否可以前进

(2)清除缓存数据:

//清除网页访问留下的缓存,由于内核缓存是全局的,因此这个方法不仅仅针对webview而是针对整个应用程序        mWebView.clearCache(true);        //清除当前webView访问的历史纪录,只会清除webview访问历史纪录里的所有历史纪录除了当前访问记录        mWebView.clearHistory();        //这个API仅仅清除自动完成填充的表单数据,并不会清除webView清除到本地的数据        mWebView.clearFormData();

(3)webview的状态:

//激活WebView为活跃状态,能正常执行网页的响应        mWebView.onResume();        //当页面被失去焦点被切换到后台不可见状态,需要执行onPause动作,onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。        mWebView.onPause();        当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。        mWebView.pauseTimers();        恢复pauseTimers时的动作。        mWebView.resumeTimers();        //销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁。        mWebView.destroy();

注意:webview调用destory时,webview仍绑定在Activity上,这是由于自定义构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview。

RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.activity_main);        rootLayout.removeView(mWebView);        mWebView.destroy();

(4)判断WebView是否已经滚动到页面低端或者顶端:

  • getScrollY():方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离;
  • getHeight()或者getBottom():方法都返回当前WebView这个容器的高度;
  • getContentHeight():返回的是整个html的高度,但并不等同于当前整个页面的高度,因为WebView有缩放功能,所以当前整个页面的高度实际上应该是原始html的高度再乘上缩放比例,因此,更正后的结果,准确的判断方法应该是:
if (mWebView.getContentHeight() * mWebView.getScale() == (mWebView.getHeight() + mWebView.getScrollY())){            //已经处于底端        }                if (mWebView.getScrollY() == 0){            //处于顶端        }

(5)返回键

返回上一次浏览的页面:

@Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()){            mWebView.goBack();            return true;        }        return  super.onKeyDown(keyCode,event);    }

(6)调用JS代码:(待续。。。)

首先在assets文件夹下创建一个html文档:

    js中调用本地方法        

接下来是主要交互的java代码:

Button btn = (Button) findViewById(R.id.btn);        mWebView = (WebView) findViewById(R.id.webview);        WebSettings webSettings = mWebView.getSettings();        //设置编码        webSettings.setDefaultTextEncodingName("utf-8");        //支持JS        webSettings.setJavaScriptEnabled(true);        //设置背景颜色 透明        mWebView.setBackgroundColor(Color.argb(0, 0, 0, 0));        //设置本地调用对象及其接口        mWebView.addJavascriptInterface(new JavaScriptObject(JSActivity.this), "myObj");        //载入js        mWebView.loadUrl("file:///android_asset/test.html");        //点击调用js中方法        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mWebView.loadUrl("javascript:funFromjs()");                Toast.makeText(JSActivity.this, "调用javascript:funFromjs()", Toast.LENGTH_SHORT).show();            }        });

最后是上面代码中用到的JavaScriptObject对象:

public class JavaScriptObject {    private Context mContext;    public JavaScriptObject(Context context){        this.mContext = context;    }    @JavascriptInterface    public void fun1FromAndroid(String name) {        Toast.makeText(mContext, name, Toast.LENGTH_LONG).show();    }    @JavascriptInterface    public void fun2(String name){        Toast.makeText(mContext, "调用fun2:"+name, Toast.LENGTH_SHORT).show();    }}

Android调用JS有一个漏洞:

(7)Android5.0 WebView中Http和Https混合问题:

在Android 5.0上webview默认不允许加载Http与Https混合内容:
解决办法:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){            mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);        }

参数类型说明:

(1) MIXED_CONTENT_ALWAYS_ALLOW:允许从任何来源加载内容,即使起源是不安全的;
(2)MIXED_CONTENT_NEVER_ALLOW:不允许Https加载Http的内容,即不允许从安全的起源去加载一个不安全的资源;
(3)MIXED_CONTENT_COMPLTIBILITY_MODE:当涉及到混合式内容时,WebView会尝试去兼容最新Web浏览器的风格;
在5.0以下Android默认是全允许的。
但是到了5.0以上,就是不允许,实际情况下我们很难确定所有的网页都是Https的,所以我们就需要这一步的操作。

分享:

(8)Cookie相关

同步cookie只需要获得CookieManager的对象将cookie设置进去就可以了。
前提:从服务器的返回头中取出cookie根据Http请求的客户端不同,获取cookie的方式也不同,请自行获取。

  • 客户端通过一下代码设置cookie,如果两次设置相同,会覆盖上一次的。
/**     *将cookie设置到webView     * @param url 需要加载的url     * @param cookie 要同步的cookie     */    public static void syncCookie(String url,String cookie){        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){            CookieSyncManager.createInstance(context);        }        CookieManager cookieManager = CookieManager.getInstance();        //如果没有特殊需求,这里只需要将session id以“key=value”形式作为cookie即可        cookieManager.setCookie(url,cookie);    }

注意:

1.同步cookie要在WebView加载url之前,否则WebView无法获得相应的cookie,也就无法通过验证;
2.cookie应该被及时更新,否则很可能导致WebView拿的是就得session id和服务器进行通信。

  • CookieManager会将这个Cookie存入该应用程序data/data/package_name/app_WebView/Cookies.db
  • 打开网页,WebView从数据库中读取该cookie值,放到http请求的头部,传到服务器;
/**     * 获取指定url的cookie     */    public static String syncCookie(String url){        CookieManager cookieManager = CookieManager.getInstance();        return cookieManager.getCookie(url);    }
  • 清除Cookie:
//这两个在API level 21被抛弃        CookieManager.getInstance().removeSessionCookie();        CookieManager.getInstance().removeAllCookie();        //推荐使用这两个,level 21新加的        CookieManager.getInstance().removeSessionCookies();//移除所有过期的cookie        CookieManager.getInstance().removeAllCookies();//移除所有的cookie
private void removeCookie(Context context){        CookieManager.getInstance().removeAllCookies(new ValueCallback
() { @Override public void onReceiveValue(Boolean aBoolean) { //清除结果 } }); }

(9)避免WebView内存泄漏的一些方式

  • 可以将WebView的Activity新起一个进程,结束的时候直接System.exit(0),退出当前进程;
    启动新进程,主要代码:AndroidManifest.xml配置文件代码如下:

在新进程中启动Activity,里面传了一个Url:

Intent intent = new Intent("com.gjj.activity.htmlactivity");        Bundle bundle = new Bundle();        bundle.putString("url",url);        intent.putExtra("bundle",bundle);        startActivity(intent);

然后在Html5Activity的onDestroy()最后加上System.exit(0),杀死当前进程。

  • 不能在xml中定义WebView,而是在需要的时候创建,并且Context使用getApplicationContext,如下代码:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                ViewGroup.LayoutParams.MATCH_PARENT);        mWebView = new WebView(getApplicationContext());        mWebView.setLayoutParams(params);        mLayout.addView(mWebView);
  • 在Activity销毁的时候,可以先让WebView加载null内容,然后移除WebView,再销毁Webview,最后置空。
@Override    protected void onDestroy() {        if (mWebView != null){            mWebView.loadDataWithBaseURL(null,"","text/html","utf-8",null);            mWebView.clearHistory();            ((ViewGroup) mWebView.getParent()).removeView(mWebView);            mWebView.destroy();            mWebView = null        }        super.onDestroy();    }

参考文章:

亲,如果您感觉本文有用,请点个赞再走吧✌(>‿◠)!!

转载于:https://my.oschina.net/ZhenyuanLiu/blog/1841619

你可能感兴趣的文章
iOS 多线程 之 GCD(大中枢派发)(一)
查看>>
Myeclipse中打开接口实现类的快捷键
查看>>
使用JdbcTemplate和JdbcDaoSupport
查看>>
Glibc 和 uClibc
查看>>
Mysql学习第三课-分析二进制日志进行增量备份和还原
查看>>
HDU 6073 - Matching In Multiplication | 2017 Multi-University Training Contest 4
查看>>
如何检测域名是否被微信屏蔽 微信域名检测接口API是如何实现
查看>>
POJ1611-The Suspects
查看>>
Linux下安装Python-3.3.2【转】
查看>>
LeetCode OJ:Merge Two Sorted Lists(合并两个链表)
查看>>
功能测试
查看>>
【BZOJ 1901】Dynamic Rankings
查看>>
PAT (Advanced Level) 1028. List Sorting (25)
查看>>
【转】聚集索引和非聚集索引的区别
查看>>
Github-Client(ANDROID)开源之旅(二) ------ 浅析ActionBarSherkLock
查看>>
eclipse中如何去除警告:Class is a raw type. References to generic type Class<T> should be parameterized...
查看>>
k sum(lintcode)
查看>>
Android 控件属性
查看>>
React-Native 之 GD (十六)首页筛选功能
查看>>
SSISDB5:使用TSQL脚本执行Package
查看>>