版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/53084703
这篇博客主要讲解一下问题 - webView 的 基本使用 - webView怎样配置缓存 - webView请求错误时候的处理 - webView cookie的同步与清除 - webView 下载文件的两种方法 - webView的 一些扩展使用
思路图如下
大概可以分为以下步骤 - 配置权限 - 创建webView - 配置webView(是否支持js,是否由系统浏览器打开) - 加载数据
<uses-permission android:name="android.permission.INTERNET"/>
在xml文件中
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:id="@+id/rl_head" android:layout_width="match_parent" android:layout_height="?android:actionBarSize" android:background="@color/colorAccent"> <ImageView android:id="@+id/iv_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:padding="10dp" android:src="@drawable/sel_back"/> <TextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:ellipsize="end" android:maxLength="200" android:maxLines="1" android:text="标题"/> </RelativeLayout> <ProgressBar android:id="@+id/progressBar" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/rl_head"/> <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/progressBar"></WebView> </RelativeLayout> </layout>
mWebView = bind.webView;
需要注意的是 这里我采用的是 databinding库,这个库可以很方便 地将我们减少findViewById 的代码,同时可以将数据与我们的View 绑定在一起,是Android支持MVVN的一个库,不了解这个库用法的用法的 请自行搜索,这里基本不涉及到这个库的 用法。
如果想在当前客户端打开浏览器的话,可以给webView 设置 setWebViewClient,并重写 shouldOverrideUrlLoading这个方法
WebSettings settings = mWebView.getSettings(); // 设置是够支持js脚本 settings.setJavaScriptEnabled(true); mWebView.setWebViewClient(new WebViewClient() { //重写这个方法 返回true,在当前 webView 打开,否则在浏览器中打开 @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { view.loadUrl(mUrl); return true; } });
如果想显示加载进度的话,可以给webView 设置setWebChromeClient,并重写onProgressChanged()方法,至于onReceivedTitle()这个方法是拿到网页加载中的 标题
mWebView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); // LUtils.i("newProgress=" + newProgress); if (newProgress != 100) { mProgressBar.setProgress(newProgress); } else { mProgressBar.setVisibility(View.GONE); } } @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); mTvTitle.setText(title); } }); }
想大多数APP的做法一样,如微信,按下返回键,只是想后退,并不是想销毁Activity,我们可以这样做,重写 Activity的 onKeyDown()方法 ,并监听按下的键,采取 相应的 操作。
public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); }
既然有后退操作,当然也有前进操作
//是够能够前进 mWebView.canGoForward(); //前进 mWebView.goForward();
调用该方法开始加载网页
mWebView.loadUrl(mUrl);
到此,webView的基本用法讲解到此。
缓存模式主要有一下几种:
我们可以通过以下方法设置缓存模式
WebSettings settings = mWebView.getSettings(); settings.setCacheMode(WebSettings.LOAD_DEFAULT);
因为系统自带的 错误页面太丑了,所以我们经常会对其 进行处理,目前本人了解到的主要有两种方法 - 加载本地的控件,显示 错误信息 - 加载自己 定义的 html页面
@SuppressWarnings("deprecation") @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); if (errorCode == 404) { //用javascript隐藏系统定义的404页面信息 //String data = "Page NO FOUND!"; // view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\""); mWebView.setVisibility(View.INVISIBLE); mErrorView.setVisibility(View.VISIBLE); } }
@SuppressWarnings("deprecation") @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); if (errorCode == 404) { //用javascript隐藏系统定义的404页面信息 String data = "Page NO FOUND!"; view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\""); } }
当然实际开发中为了给用户比较还要的体验,会做非常多的处理,包括有网络情况和没有网络情况的处理,对于没有网络情况的处理,这里我们跳转到打开WiFi界面,详情可以参照我的 上一篇博客android 监听网络状态的变化及实战,而对于有网络情况的处理,这里我们只处理404错误,其他错误请根据项目的需求自行处理。
@SuppressWarnings("deprecation") @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); // 没有网络连接 if (false == APP.getInstance().isConnected()) { APP.getInstance().showWifiDlg(NewsDetailActivity.this); } else { if (errorCode == 404) { //用javascript隐藏系统定义的404页面信息 String data = "Page NO FOUND!"; view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\""); mWebView.setVisibility(View.INVISIBLE); } else {//其他状态码错误的处理,这里就不罗列出来了 } } }
关于这个问题,我们主要分为两步, - 怎样获取cookie - 怎样将cookie与webView进行 同步
下面只给出核心代码
第一,使用DefaultHttpClient
DefaultHttpClient client = new DefaultHttpClient(); CookieStore store = client.getCookieStore(); List<Cookie> list = store.getCookies();
第二,使用HttpURLConnection
URLConnection con= (HttpURLConnection) url.openConnection(); // 取得sessionid. String cookieval = con.getHeaderField("set-cookie"); String sessionid; if(cookieval != null) { sessionid = cookieval.substring(0, cookieval.indexOf(";")); }
发送设置cookie:
URL url = new URL(requrl); HttpURLConnectioncon= (HttpURLConnection) url.openConnection(); if(sessionid != null) { con.setRequestProperty("cookie", sessionid); }
第三,使用Retrofit
Call<ResponseBody> call = tnGouAPi.getTest(test); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody body = response.body(); Headers headers = response.headers(); Set<String> names = headers.names(); for(String key:names){ String value = headers.get(key); } try { Logger.i("onResponse: body=" + body.string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Logger.i("onResponse: t=" + t.getMessage()); } });
/** * cookie同步 */ @SuppressWarnings("deprecation") private void syncCookieToWebView(String url,List<String> cookies) { CookieSyncManager.createInstance(this); CookieManager cm = CookieManager.getInstance(); cm.setAcceptCookie(true); if(cookies!=null) { for (String cookie : cookies) { cm.setCookie(url,cookie);//注意端口号和域名,这种方式可以同步所有cookie,包括sessionid } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { CookieManager.getInstance().flush(); } else { CookieSyncManager.getInstance().sync(); } }
@SuppressWarnings("deprecation") public void clearCookies(Context context) { CookieSyncManager.createInstance(context); CookieManager cookieManager = CookieManager.getInstance(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.removeAllCookies(null); } else { cookieManager.removeAllCookie(); } }
总共 有两种 方法, - 第一种,自己实现实现逻辑 ,下载,保存到相应目录; - 第二种,调用系统的下载方法
主要是给webView设置DownloadListener监听器
mWebView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { //第一种下载方式是 自定义的http工具类 // new HttpDownloadThread(url,contentDisposition,mimetype,contentLength).start(); //第二种下载方式是调用系统的webView,具有默认的进度条 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(url)); startActivity(intent); } });
HttpDownloadThread
public class HttpDownloadThread extends Thread { private String mUrl; private String mContentDisposition; private String mMimetype; private long mContentLength; public HttpDownloadThread(String url, String contentDisposition, String mimetype, long contentLength) { this.mUrl = url; this.mContentDisposition=contentDisposition; this.mContentDisposition=mimetype; this.mContentDisposition=contentDisposition; } @Override public void run() { URL url; try { url = new URL(mUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); conn.setDoOutput(true); InputStream in = conn.getInputStream(); File downloadFile; File sdFile; FileOutputStream out = null; if(Environment.getExternalStorageState().equals(Environment.MEDIA_UNMOUNTED)){ downloadFile = Environment.getExternalStorageDirectory(); sdFile = new File(downloadFile, "test.file"); out = new FileOutputStream(sdFile); } //buffer 4k byte[] buffer = new byte[1024 * 4]; int len = 0; while((len = in.read(buffer)) != -1){ if(out != null) out.write(buffer, 0, len); } //close resource if(out != null) out.close(); if(in != null){ in.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
// 设置是否支持画面缩放 settings.setBuiltInZoomControls(true); settings.setSupportZoom(true); // 设置是否显示缩放器 settings.setDisplayZoomControls(false); // 设置字体的大小 settings.setTextZoom(120);
关于webView 与js互相调用的,可以 参考这一篇文章webview与javascript交互回调与异步
关于如何监听网络简化及处理的 ,有兴趣的可以阅读我的这一篇博客android 监听网络状态的变化及实战
文章首发地址CSDN:http://blog.csdn.net/gdutxiaoxu/article/details/53084703
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句