WebView使用详解、H5网页视频全屏播放 、网页跳转空白

转载请注明出处:https://blog.csdn.net/mr_leixiansheng/article/details/81000035

内容:介绍webview的使用方法,介绍WebViewClient、WebChromeClient,H5网页视频全屏播放,网页跳转空白问题

最近做项目老爱和H5打交道,遇到了很多问题也踩了许多坑,今天在这儿总结下,方便后人乘凉。

关于安卓和H5交互可参考我之前的文章:原生与H5交互介绍

WebView基础设置

private void initWebView() {
		mWebView.setWebViewClient(new MyWebViewClient());		//设置在WebView中打开链接,不设置则调用自带浏览器。主要针对View进行拦截处理
		mWebView.setWebChromeClient(new MyWebChromeClient());

		WebSettings webSettings = mWebView.getSettings();
		webSettings.setJavaScriptEnabled(true);		//支持JS
		webSettings.setDomStorageEnabled(true);		  //启用dom内存,防止js加载失败
		webSettings.setAllowFileAccess(true);		//允许访问文件
		webSettings.setSupportZoom(true);		//支持缩放
		webSettings.setLoadWithOverviewMode(true);		//是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
		webSettings.setGeolocationEnabled(false);		//是否允许定位
		webSettings.setLoadsImagesAutomatically(true);		//是否加载图片
//		webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);		//设置缓存模式
//		webSettings.setDefaultTextEncodingName("UTF-8");		//设置页面的编码格式,默认UTF-8
	}

WebViewClient主要是对view一系列操作进行监听拦截。包括:网页加载开始、网页加载完成、错误拦截处理。(代码中注释会详解,再次不多做介绍)

WebChromeClient主要是对浏览器进行监听。例如弹窗、是否显示支持全屏播放等。(代码中注释会详解,再次不多做介绍)

网页加载空白问题,我只在7.0及以上遇到,貌似是说证书错误,可能越往上安全性越高吧,按照下面处理下就行了

/**
		 * HTTPS通信的网址(以https://开头的网站)出现错误时
		 * 证书错误拦截处理
		 * 安卓7.0需要
		 */
		@Override
		public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
			if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校验过程遇到了bug
				handler.proceed();		//忽略错误继续加载
			}else{
				handler.cancel();		//取消加载
			}
		}

视频全屏播放:安卓不像IOS一样可以直接全屏播放,需要在WebChromeClient对其进行设置,相当于是new 一个Fragment让其来进行全屏播放

	/*** 视频播放相关的方法 **/
		@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();
		}

   

代码如下:

<?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>
package com.example.leixiansheng.webviewtest;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ProgressBar;

import com.tbruyelle.rxpermissions2.Permission;
import com.tbruyelle.rxpermissions2.RxPermissions;

import java.util.function.Consumer;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

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;

	/** 视频全屏参数 */
	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());		//设置在WebView中打开链接,不设置则调用自带浏览器。主要针对View进行拦截处理
		mWebView.setWebChromeClient(new MyWebChromeClient());

		WebSettings webSettings = mWebView.getSettings();
		webSettings.setJavaScriptEnabled(true);		//支持JS
		webSettings.setDomStorageEnabled(true);		  //启用dom内存,防止js加载失败
		webSettings.setAllowFileAccess(true);		//允许访问文件
		webSettings.setSupportZoom(true);		//支持缩放
		webSettings.setLoadWithOverviewMode(true);		//是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
		webSettings.setGeolocationEnabled(false);		//是否允许定位
		webSettings.setLoadsImagesAutomatically(true);		//是否加载图片
//		webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);		//设置缓存模式
//		webSettings.setDefaultTextEncodingName("UTF-8");		//设置页面的编码格式,默认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) {
			//优先退出全屏播放
			if (customView != null) {
				hideCustomView();
				return true;
			} else {
				if (mWebView.canGoBack()) {
					mWebView.goBack();		//返回上个页面
					return true;
				} else {
					System.exit(0);		//退出程序
				}
			}
		}
		return super.onKeyDown(keyCode, event);
	}


	/**
	 * 针对网页进行拦截处理
	 */
	public class MyWebViewClient extends WebViewClient{

		/**
		 *可以实现对网页中超链接的拦截
		 */
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {

			//例:拦截电话网址,直接调用本地电话
			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);
		}

		/**
		 * 结束加载
		 */
		@Override
		public void onPageFinished(WebView view, String url) {
			super.onPageFinished(view, url);
			mPbLoading.setVisibility(View.GONE);
		}

		/**
		 * 加载错误的时候会产生这个回调
		 */
		@Override
		public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
			super.onReceivedError(view, errorCode, description, failingUrl);
			//TODO
		}

		/**
		 * HTTPS通信的网址(以https://开头的网站)出现错误时
		 * 证书错误拦截处理
		 * 安卓7.0需要
		 */
		@Override
		public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
			if(error.getPrimaryError() == android.net.http.SslError.SSL_INVALID ){// 校验过程遇到了bug
				handler.proceed();		//忽略错误继续加载
			}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);
		}

		/*** 视频播放相关的方法 **/
		@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);
	}
}

猜你喜欢

转载自blog.csdn.net/mr_leixiansheng/article/details/81000035