image.png
內(nèi)容:介紹webview的使用方法,介紹WebViewClient邀层、WebChromeClient返敬,H5網(wǎng)頁視頻全屏播放,網(wǎng)頁跳轉(zhuǎn)空白問題
最近做項目老愛和H5打交道寥院,遇到了很多問題也踩了許多坑劲赠,今天在這兒總結(jié)下,方便后人乘涼秸谢。
關(guān)于安卓和H5交互可參考我之前的文章:原生與H5交互介紹
WebView基礎(chǔ)設(shè)置
private void initWebView() {
mWebView.setWebViewClient(new MyWebViewClient()); //設(shè)置在WebView中打開鏈接凛澎,不設(shè)置則調(diào)用自帶瀏覽器。主要針對View進行攔截處理
mWebView.setWebChromeClient(new MyWebChromeClient());
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); //支持JS
webSettings.setDomStorageEnabled(true); //啟用dom內(nèi)存估蹄,防止js加載失敗
webSettings.setAllowFileAccess(true); //允許訪問文件
webSettings.setSupportZoom(true); //支持縮放
webSettings.setLoadWithOverviewMode(true); //是否啟動概述模式瀏覽界面塑煎,當頁面寬度超過WebView顯示寬度時,縮小頁面適應(yīng)WebView臭蚁。默認false
webSettings.setGeolocationEnabled(false); //是否允許定位
webSettings.setLoadsImagesAutomatically(true); //是否加載圖片
// webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); //設(shè)置緩存模式
// webSettings.setDefaultTextEncodingName("UTF-8"); //設(shè)置頁面的編碼格式最铁,默認UTF-8
}
WebViewClient主要是對view一系列操作進行監(jiān)聽攔截。包括:網(wǎng)頁加載開始垮兑、網(wǎng)頁加載完成冷尉、錯誤攔截處理。(代碼中注釋會詳解系枪,再次不多做介紹)
WebChromeClient主要是對瀏覽器進行監(jiān)聽雀哨。例如彈窗、是否顯示支持全屏播放等嗤无。(代碼中注釋會詳解震束,再次不多做介紹)
網(wǎng)頁加載空白問題怜庸,我只在7.0及以上遇到,貌似是說證書錯誤垢村,可能越往上安全性越高吧割疾,按照下面處理下就行了
/**
* HTTPS通信的網(wǎng)址(以https://開頭的網(wǎng)站)出現(xiàn)錯誤時
* 證書錯誤攔截處理
* 安卓7.0需要
*/
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校驗過程遇到了bug
handler.proceed(); //忽略錯誤繼續(xù)加載
}else{
handler.cancel(); //取消加載
}
}
視頻全屏播放:安卓不像IOS一樣可以直接全屏播放,需要在WebChromeClient對其進行設(shè)置嘉栓,相當于是new 一個Fragment讓其來進行全屏播放
/*** 視頻播放相關(guān)的方法 **/
@Override
public View getVideoLoadingProgressView() {
FrameLayout frameLayout = new FrameLayout(MainActivity.this);
frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return frameLayout;
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
showCustomView(view, callback);
}
@Override
public void onHideCustomView() {
hideCustomView();
}
image.png
代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_load"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="LOAD"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
<ProgressBar
android:id="@+id/pb_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
@BindView(R.id.btn_load)
Button mBtnLoad;
@BindView(R.id.web_view)
WebView mWebView;
@BindView(R.id.pb_loading)
ProgressBar mPbLoading;
/** 視頻全屏參數(shù) */
protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
private View customView;
private FrameLayout fullscreenContainer;
private WebChromeClient.CustomViewCallback customViewCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initWebView();
}
private void initWebView() {
mWebView.setWebViewClient(new MyWebViewClient()); //設(shè)置在WebView中打開鏈接宏榕,不設(shè)置則調(diào)用自帶瀏覽器。主要針對View進行攔截處理
mWebView.setWebChromeClient(new MyWebChromeClient());
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); //支持JS
webSettings.setDomStorageEnabled(true); //啟用dom內(nèi)存侵佃,防止js加載失敗
webSettings.setAllowFileAccess(true); //允許訪問文件
webSettings.setSupportZoom(true); //支持縮放
webSettings.setLoadWithOverviewMode(true); //是否啟動概述模式瀏覽界面麻昼,當頁面寬度超過WebView顯示寬度時,縮小頁面適應(yīng)WebView馋辈。默認false
webSettings.setGeolocationEnabled(false); //是否允許定位
webSettings.setLoadsImagesAutomatically(true); //是否加載圖片
// webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); //設(shè)置緩存模式
// webSettings.setDefaultTextEncodingName("UTF-8"); //設(shè)置頁面的編碼格式抚芦,默認UTF-8
}
@OnClick(R.id.btn_load)
public void onViewClicked() {
mWebView.loadUrl("http://www.baidu.com");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//優(yōu)先退出全屏播放
if (customView != null) {
hideCustomView();
return true;
} else {
if (mWebView.canGoBack()) {
mWebView.goBack(); //返回上個頁面
return true;
} else {
System.exit(0); //退出程序
}
}
}
return super.onKeyDown(keyCode, event);
}
/**
* 針對網(wǎng)頁進行攔截處理
*/
public class MyWebViewClient extends WebViewClient{
/**
*可以實現(xiàn)對網(wǎng)頁中超鏈接的攔截
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//例:攔截電話網(wǎng)址,直接調(diào)用本地電話
if (url.contains("tel:")){
startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
return true;
}
if (url.startsWith("http:") || url.startsWith("https:")) {
view.loadUrl(url);
return true;
}
/* WebView.HitTestResult hitTestResult = view.getHitTestResult();
//hitTestResult==null解決重定向問題
if (!TextUtils.isEmpty(url) && hitTestResult == null) {
view.loadUrl(url);
return true;
}*/
return super.shouldOverrideUrlLoading(view, url);
}
/**
*開始加載
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mPbLoading.setVisibility(View.VISIBLE);
}
/**
* 結(jié)束加載
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mPbLoading.setVisibility(View.GONE);
}
/**
* 加載錯誤的時候會產(chǎn)生這個回調(diào)
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
//TODO
}
/**
* HTTPS通信的網(wǎng)址(以https://開頭的網(wǎng)站)出現(xiàn)錯誤時
* 證書錯誤攔截處理
* 安卓7.0需要
*/
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校驗過程遇到了bug
handler.proceed(); //忽略錯誤繼續(xù)加載
}else{
handler.cancel(); //取消加載
}
}
}
/**
* 針對瀏覽器攔截處理
*/
public class MyWebChromeClient extends WebChromeClient{
/**
* 彈窗攔截
*/
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
/**
* 彈窗攔截
*/
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
/**
* 彈窗攔截
*/
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
/**
* 加載進度攔截
*/
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
/**
* 文件選擇
*/
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
selectImage();
return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
}
/*** 視頻播放相關(guān)的方法 **/
@Override
public View getVideoLoadingProgressView() {
FrameLayout frameLayout = new FrameLayout(MainActivity.this);
frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return frameLayout;
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
showCustomView(view, callback);
}
@Override
public void onHideCustomView() {
hideCustomView();
}
}
/**
* 圖片選擇
*/
private void selectImage() {
//TODO
}
/**
* 視頻播放全屏
*/
private void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
// if a view already exists then immediately terminate the new one
if (customView != null) {
callback.onCustomViewHidden();
return;
}
getWindow().getDecorView();
//獲取虛擬按鍵高度迈螟,防止遮擋
if(ScreenUtils.hasNavBar(this)){
COVER_SCREEN_PARAMS.setMargins(0,0,0,ScreenUtils.getNavigationBarHeight(this));
}
FrameLayout decor = (FrameLayout) getWindow().getDecorView();
fullscreenContainer = new FullscreenHolder(this);
fullscreenContainer.addView(view, COVER_SCREEN_PARAMS);
decor.addView(fullscreenContainer, COVER_SCREEN_PARAMS);
customView = view;
setStatusBarVisibility(false);
customViewCallback = callback;
}
/**
* 隱藏視頻全屏
*/
private void hideCustomView() {
if (customView == null) {
return;
}
setStatusBarVisibility(true);
FrameLayout decor = (FrameLayout) getWindow().getDecorView();
decor.removeView(fullscreenContainer);
fullscreenContainer = null;
customView = null;
customViewCallback.onCustomViewHidden();
mWebView.setVisibility(View.VISIBLE);
}
/**
* 全屏容器界面
*/
static class FullscreenHolder extends FrameLayout {
public FullscreenHolder(Context ctx) {
super(ctx);
setBackgroundColor(ctx.getResources().getColor(android.R.color.black));
}
@Override
public boolean onTouchEvent(MotionEvent evt) {
return true;
}
}
private void setStatusBarVisibility(boolean visible) {
int flag = visible ? 0 : WindowManager.LayoutParams.FLAG_FULLSCREEN;
getWindow().setFlags(flag, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
贈人玫瑰叉抡,手有余香。您的支持是我創(chuàng)作最大的動力!