編輯:關於Android編程
前言:生活的艱難,更會激發對夢想的渴望,但艱難的生活卻往往會成為夢想的絆腳石
上篇給大家簡單講了Webview中Native代碼與JS相互調用的方法,這篇我們再講講有關各種攔截與處理的東東。
mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.d(TAG,"onPageStarted");
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.d(TAG,"onPageFinished");
}
});
直接調用WebView.setWebViewClient方法即可設置WebViewClient回調,這裡重寫的兩個函數,onPageStarted會在WebView開始加載網頁時調用,onPageFinished會在加載結束時調用。這兩個函數就可以完成我們開篇時的需求:在開始加載時顯示進度條,在結束加載時隱藏進度條。
/**
* 在開始加載網頁時會回調
*/
public void onPageStarted(WebView view, String url, Bitmap favicon)
/**
* 在結束加載網頁時會回調
*/
public void onPageFinished(WebView view, String url)
/**
* 攔截 url 跳轉,在裡邊添加點擊鏈接跳轉或者操作
*/
public boolean shouldOverrideUrlLoading(WebView view, String url)
/**
* 加載錯誤的時候會回調,在其中可做錯誤處理,比如再請求加載一次,或者提示404的錯誤頁面
*/
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)
/**
* 當接收到https錯誤時,會回調此函數,在其中可以做錯誤處理
*/
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
/**
* 在每一次請求資源時,都會通過這個函數來回調
*/
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
return null;
}
上面的方法比較多,我們一個個來看
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl("http://blog.csdn.net/harvic880925");
mWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mWebView.loadUrl(url);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mProgressDialog.show();
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mProgressDialog.hide();
}
});
}
}
效果圖如下:
從效果圖中可以明顯看出,在加載頁面的時候會顯示圓形加載框,在加載成功以後會隱藏加載框。
public boolean shouldOverrideUrlLoading(WebView view, String url)這個函數會在加載超鏈接時回調過來;所以通過重寫shouldOverrideUrlLoading,可以實現對網頁中超鏈接的攔截;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient());
mWebView.loadUrl("http://blog.csdn.net/harvic880925");
}
}
效果圖如下:
從效果圖中可以看出即僅僅設置WebViewClient對象,使用它的默認回調就可以實現在WebView中加載在線URL了:
mWebView.setWebViewClient(new WebViewClient());

代碼如下:
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("blog.csdn.net")){
view.loadUrl("http://www.baidu.com");
}else {
view.loadUrl(url);
}
return true;
}
});
mWebView.loadUrl("http://blog.csdn.net/harvic880925");
}
}
最關鍵的位置在:
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("blog.csdn.net")){
view.loadUrl("http://www.baidu.com");
}else {
view.loadUrl(url);
}
return true;
}
如果在當前webview加載的url中包含“blog.csdn.net”,則將其轉換成”www.baidu.com”
mWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains("blog.csdn.net")){
view.loadUrl("http://www.baidu.com");
}
return false;
}
}
所以相對而言,我們使用return false好像更方便,只需要對需要攔截的URL進行攔截,攔截以後,讓WebView處理默認操作即可。
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)加載錯誤的時候會產生這個回調,在其中可做錯誤處理,比如我們可以加載一個錯誤提示頁面
mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
mWebView.loadUrl("file:///android_asset/error.html");
}
});
效果圖如下:
源碼在文章底部給出
/** * 當接收到https錯誤時,會回調此函數,在其中可以做錯誤處理 */ public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)WebView view:當前的WebView實例SslErrorHandler handler:當前處理錯誤的Handler,它只有兩個函數SslErrorHandler.proceed()和SslErrorHandler.cancel(),SslErrorHandler.proceed()表示忽略錯誤繼續加載,SslErrorHandler.cancel()表示取消加載。在onReceivedSslError的默認實現中是使用的SslErrorHandler.cancel()來取消加載,所以一旦出來SSL錯誤,HTTPS網站就會被取消加載了,如果想忽略錯誤繼續加載就只有重寫onReceivedSslError,並在其中調用SslErrorHandler.proceed()SslError error:當前的的錯誤對象,SslError包含了當前SSL錯誤的基本所有信息,大家自己去看下它的方法吧,這裡就不再展開了。
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
Log.e(TAG,"sslError:"+error.toString());
}
mWebView.loadUrl("https://www.12306.cn/");
}
}
在這裡僅僅重寫onReceivedSslError,並調用super.onReceivedSslError(view, handler, error);來調用默認的處理方式,然後把錯誤日志打出來:

mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// 一定要注釋掉!
// super.onReceivedSslError(view, handler, error);
handler.proceed();
Log.e(TAG,"sslError:"+error.toString());
}
});
這裡做了兩個改變:
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
handler.cancel();
}
所以默認是取消繼續加載的,所以我們必須注釋掉super.onReceivedSslError(view, handler, error)來取消這個默認行為!
mWebView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// super.onReceivedSslError(view, handler, error);
handler.proceed();
Log.e(TAG,"sslError:"+error.toString());
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
Log.e(TAG,"onReceivedError:"+errorCode+" "+description);
}
});

從日志中明顯可以看出,只有onReceivedSslError的接收日志,所以在SSL出錯時,是不會觸發onReceivedError回調的
所以對於onReceivedSslError結論來了:
當出現SSL錯誤時,WebView默認是取消加載當前頁面,只有去掉onReceivedSslError的默認操作,然後添加SslErrorHandler.proceed()才能繼續加載出錯頁面
當HTTPS傳輸出現SSL錯誤時,錯誤會只通過onReceivedSslError回調傳過來
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
return null;
}
該函數會在請求資源前調用,我們可以通過返回WebResourceResponse的處理結果來讓WebView直接使用我們的處理結果。如果我們不想處理,則直接返回null,系統會繼續加載該資源。
然後是Native代碼:
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient(){
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
if (url.equals("https://android.yunyiwangluo.com/Android/UploadFiles_5356/201702/2017022311492479.png")) {
AssetFileDescriptor fileDescriptor = getAssets().openFd("s07.jpg");
InputStream stream = fileDescriptor.createInputStream();
WebResourceResponse response = new WebResourceResponse("image/png", "UTF-8", stream);
return response;
}
}catch (Exception e){
Log.e(TAG,e.getMessage());
}
return super.shouldInterceptRequest(view, url);
}
});
mWebView.loadUrl("file:///android_asset/web.html");
}
這裡代碼比較容易理解,當發現當前加載資源的url是我們自定義的https://android.yunyiwangluo.com/Android/UploadFiles_5356/201702/2017022311492479.png時,就直接將本地的圖片s07.jpg作為結果返回。有關使用WebResourceResponse來構造結果的方法,我這裡就不再展開了,內容實在是太多了,想具體了解針對不同情況如何返回結果的話,自己搜下相關資料吧。
/** * 在加載頁面資源時會調用,每一個資源(比如圖片)的加載都會調用一次 */ public void onLoadResource(WebView view, String url) /** * (WebView發生改變時調用) * 可以參考http://www.it1352.com/191180.html的用法 */ public void onScaleChanged(WebView view, float oldScale, float newScale) /** * 重寫此方法才能夠處理在浏覽器中的按鍵事件。 * 是否讓主程序同步處理Key Event事件,如過濾菜單快捷鍵的Key Event事件。 * 如果返回true,WebView不會處理Key Event, * 如果返回false,Key Event總是由WebView處理。默認:false */ public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) /** * 是否重發POST請求數據,默認不重發。 */ onFormResubmission(WebView view, Message dontResend, Message resend) /** * 更新訪問歷史 */ doUpdateVisitedHistory(WebView view, String url, boolean isReload) /** * 通知主程序輸入事件不是由WebView調用。是否讓主程序處理WebView未處理的Input Event。 * 除了系統按鍵,WebView總是消耗掉輸入事件或shouldOverrideKeyEvent返回true。 * 該方法由event 分發異步調用。注意:如果事件為MotionEvent,則事件的生命周期只存在方法調用過程中, * 如果WebViewClient想要使用這個Event,則需要復制Event對象。 */ onUnhandledInputEvent(WebView view, InputEvent event) /** * 通知主程序執行了自動登錄請求。 */ onReceivedLoginRequest(WebView view, String realm, String account, String args) /** * 通知主程序:WebView接收HTTP認證請求,主程序可以使用HttpAuthHandler為請求設置WebView響應。默認取消請求。 */ onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) /** * 通知主程序處理SSL客戶端認證請求。如果需要提供密鑰,主程序負責顯示UI界面。 * 有三個響應方法:proceed(), cancel() 和 ignore()。 * 如果調用proceed()和cancel(),webview將會記住response, * 對相同的host和port地址不再調用onReceivedClientCertRequest方法。 * 如果調用ignore()方法,webview則不會記住response。該方法在UI線程中執行, * 在回調期間,連接被掛起。默認cancel(),即無客戶端認證 */ onReceivedClientCertRequest(WebView view, ClientCertRequest request)
public class MyActivity extends Activity {
private WebView mWebView;
private ProgressDialog mProgressDialog;
private String TAG = "qijian";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mWebView = (WebView)findViewById(R.id.webview);
mProgressDialog = new ProgressDialog(this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new WebViewClient());
mWebView.loadUrl("http://blog.csdn.net/harvic880925/");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//改寫物理返回鍵的邏輯
if(keyCode==KeyEvent.KEYCODE_BACK) {
if(mWebView.canGoBack()) {
mWebView.goBack();//返回上一頁面
return true;
} else {
System.exit(0);//退出程序
}
}
return super.onKeyDown(keyCode, event);
}
}
在未重寫onKeyDown前的效果圖:點擊回退按鈕,整個Activity就銷毀了
重寫onKeyDown後的效果圖:

可見在重寫onKeyDown後,點擊回退按鈕時,就會回退到WebView的上一個頁面。
public class MyWebView extends WebView {
private OnScrollChangedCallback mOnScrollChangedCallback;
public MyWebView(Context context) {
super(context);
}
public MyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mOnScrollChangedCallback != null) {
mOnScrollChangedCallback.onScroll(l,t,oldl,oldt);
}
}
public OnScrollChangedCallback getOnScrollChangedCallback() {
return mOnScrollChangedCallback;
}
public void setOnScrollChangedCallback(
final OnScrollChangedCallback onScrollChangedCallback) {
mOnScrollChangedCallback = onScrollChangedCallback;
}
public static interface OnScrollChangedCallback {
public void onScroll(int left,int top ,int oldLeft,int oldTop);
}
}
這段代碼難度不大,就不再細講了。
Uri uri = Uri.parse("http://www.example.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
Volley網絡請求框架簡析——Android網絡請求框架(三)
1、初始化一個消息請求隊列以及網絡請求工具類對象/** * Created by androidlongs on 16/7/1. * 網絡請求訪問框架
Android初識之簡易計算器
之前自己的編程完全是在PC上進行的,而且主要是在算法和數據結構上。由於某些需要加之認識到Android的重要性,且大學走到現在基本上沒什麼課了,空閒時間很多,於是就開始學
Android 異步Http框架簡介和實現原理
在前幾篇文章中《Android 采用get方式提交數據到服務器》《Android 采用post方式提交數據到服務器》《Android 采用HttpClient提交數據到服
Android中級:實現ViewPager的無線自動循環
無限自動循環 = 無限循環 + 自動循環無限循環 = 無限向左循環 + 無限向右循環接下來我們通過demo一步步的實現無限向右循環–>無限向左循環&nd
Android framework camera回顧-Camera CameraClient ICamera之間關系(1)-cl和c-)mCamera去哪兒
status_t Camera::connectLegacy(int c