作者

大家好,我叫Jack冯;

自己20年硕士结业于广东工业大学,于2020年6月加入37手游安卓团队;

现在首要担任海外游戏发行安卓相关开发。

布景

最近在接触活动相关需求,其间涉及到一个安卓的WebView;

刚结业的我,对安卓知识堆集比较少,所以在这儿对Webview进行相关学习,希望自己能够在安卓方面逐步堆集。

Webview介绍

1、关于MockView

( 1 ) 在targetSdkVersion 28/29的工程里边查看WebView承继关系

java.lang.Object
  ↳	android.view.View
     ↳	android.view.ViewGroup
​     	  ↳	 android.widget.FrameLayout
  	      	↳	android.layoutlib.bridge.MockView
  	 	     	 ↳	android.webkit.WebView

( 2 ) 运用26/27等低版本SDK,查看源码中的WebView 承继关系

java.lang.Object
  ↳	android.view.View
   ↳  android.view.ViewGroup
  	   ↳	android.widget.AbsoluteLayout
  	 	   ↳	android.webkit.WebView

( 3 )比照

两种办法比照,AbsoluteLayout和FrameLayout都是重写ViewGroup的办法,如与布局参数装备相关的 generateDefaultLayoutParams()、checkLayoutParams()等。两种办法明显不同的是多了一层MockView 。这儿来看看MockView是什么:

public class MockView extends FrameLayout{
...
//创立办法
public MockView(Context context) {...}
public MockView(Context context,AttributeSet attrs) {...}
public MockView(Context context,AttributeSet attrs,int defStyleRes) {...}
//重写增加view办法
@Override
public void addView(View child){...}
@Override
public void addView(View child,int index){...}
@Override
public void addView(View child,int width,int height){...}
@Override
public void addView(View child,ViewGroup.LayoutParams params){...}
@Override
public void addView(View child,int index,ViewGroup.LayoutParams params){...}
public void setText(CharSequence text){...}
public void setGravity(int gravity){...}
}

MockView,译为”虚伪的view”。

谷歌发布的Sdk其实只是为了供给App开发运转接口,实际运转时分替换为当时体系的Sdk。

详细说便是当谷歌在新的体系(Framework)版本上准备对WebView完成机制进行改动,同时又希望把新的sdk提前发出来,不影响用到WebView的App开发,所以谷歌供给给Android开发的sdk中让WebView承继自MockView,这个WebView只是暴露了接口,没有详细完成;这样当谷歌关于WebView新的完成做好,利用WebView,app也就做好了

2、基本运用

(1)创立

①一般办法:

WebView webView = findViewById(R.id.webview);

②主张办法:

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
mWebView = new WebView(getApplicationContext());
mWebView.setLayoutParams(params);

好处:构建不用依赖本地xml文件,自定义页面参数;手动销毁防止内存泄露;

③更多办法 : 承继Webview和首要API等进行拓展

public class BaseWebView extends WebView {...}
public class BaseWebClient extends WebClient {...}
public class BaseWebChromeClient extends WebChromeClient {...}

(2)加载

① 加载某个网页

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

②新建assets目录,将html文件放到目录下,经过路径加载本地页面

 webView.loadUrl("file:///android_asset/loadFailed.html");

③运用evaluateJavascript(String script, ValueCallback resultCallback)办法加载,(Android4.4+)

mWebView.evaluateJavascript("file:///android_asset/javascript.html",new ValueCallback<String>() {
	@Override
	public void onReceiveValue(String value) {
		Log.e("测验", "onReceiveValue:"+value );
	}
});

3、WebViewClient

当URL行将加载到当时窗口,假如没有供给WebViewClient,默许情况下WebView将运用Activity管理器为URL挑选适当的处理器。

假如供给了WebViewClient,按自定义装备要求来继续加载URL。

(1)常用办法

//加载进程对url的处理(webview加载、体系浏览器加载、其他操作等)
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
	super.shouldOverrideUrlLoading(view, url);
}
//加载失利页面
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
	view.loadUrl("file:///android_asset/js_error.html");
}
//证书错误处理
@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
}
//开端加载页面(可自定义页面加载计时等)
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
	super.onPageStarted(view, url, favicon);
	Log.e(TAG, "onPageStarted:" + url);
}
//完毕加载页面
@Override
public void onPageFinished(WebView view, String url) {
	super.onPageFinished(view, url);
	Log.e(TAG, "onPageFinished: " + url);
}

(2)关于shouldOverrideUrlLoading

假如在点击链接加载进程需求更多的操控,就能够在WebViewClient()中重写shouldOverrideUrlLoading()办法。

涉及shouldOverrideUrlLoading()的情形,大约分为三种:

(1)没有设定setWebViewClient(),点击链接运用默许浏览器翻开;

(2)设定setWebViewClient(new WebViewClient()),默许shouldOverrideUrlLoading()回来false,点击链接在Webview加载;

(3)设定、重写shouldOverrideUrlLoading()

回来true:可由运用代码处理该 url,WebView 中止处理(若重写办法没加上view.loadUrl(url),不加载);

回来false:由 WebView 处理加载该 url。(即便没加上view.loadUrl(url),也会在当时Webview加载)

【一般运用】

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
	super.shouldOverrideUrlLoading(view, url);
	if (url != null) {
	if (!(url.startsWith("http") || url.startsWith("https"))) {
			return true;
	}
	//重定向到其他页面
	//view.loadUrl("file:///android_asset/javascript.html");
	//差异不同链接加载
	view.loadUrl(url);
	}
return true;
}

(3)常见误区

【误区1】 : 需求重写 shouldOverrideUrlLoading 办法才能阻止浏览器翻开页面。

解说:WebViewClient 源码中 shouldOverrideUrlLoading 办法已经回来 false,不设定setWebViewClient(),默许运用体系浏览器加载。假如重写该办法并回来true, 就能够完成在app页面中加载新链接而不去翻开浏览器。

【误区2】 : 每一个url加载进程都会经过 shouldOverrideUrlLoading 办法。

Q1:加载一定会触发shouldOverrideUrlLoading?

Q2:触发机遇一定在onPageStarted调用之前?

解说:关于shouldOverrideUrlLoading的触发

1)假如在点击页面链接时经过标签跳转,触发办法如下:

​ shouldOverrideUrlLoading() —> onPageStarted()—> onPageFinished()

2)假如运用loadUrl加载时,触发办法如下:

​ onPageStarted()—>onPageFinished()

3)假如运用loadUrl加载重定向地址时,触发办法如下:

​ shouldOverrideUrlLoadings—>onPageStarted —> onPageFinished

ps:多次重定向的进程,

onPage1Started

—>shouldOverrideUrlLoadings

—>onPage2Started —> xxx…

—> onPageNFinished

定论:shouldOverrideUrlLoading()办法不是每次加载都会调用,WebView的行进、撤退等不会调用shouldOverrideUrlLoading办法;非loadUrl办法加载 或者 是重定向的,才会调用shouldOverrideUrlLoading办法。

【误区3 】: 重写 shouldOverrideUrlLoading 办法回来true比false的差异,多调用一次onPageStarted()和onPageFinished()。

解说:回来True:运用代码处理url;回来False,则由 WebView 处理加载 url。

ps:低版本体系(华为6.0),测验 False比True会多调用一次onPageStarted()和onPageFinished(),这点还在求证中。

4、WebChromeClient

比照WebviewClient , 增加了处理JavaScript对话框,图标,标题和进展等。

处理对象 : 影响浏览器的事情

(1)常用办法:

//alert弹出框
public boolean onJsAlert(WebView view, String url, String message,JsResult result){
return true;//true表示阻拦
}
//confirm弹出框
public boolean onJsConfirm(WebView view, String url, String message,JsResult result){
return false;//false则答应弹出
}
 public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
//打印 console 信息。return true只显现log,不显现js操控台的输入;false则都显现出来
 public boolean onConsoleMessage(ConsoleMessage consoleMessage){
 Log.e("测验", "consoleMessage:"+consoleMessage.message());
 }
//告诉程序当时页面加载进展,结合ProgressBar显现
 public void onProgressChanged(WebView view, int newProgress){
 		if (newProgress < 100) {
			String progress = newProgress + "%";
			Log.e("测验", "加载进展:"+progress);
			webProgress.setProgress(newProgress);
		}
 }

(2)阻拦示例:

JsResult.comfirm() –> 确认按钮的调用办法

JsResult.cancle() –> 取消按钮

示例:阻拦H5的弹框,并显现自定义弹框,点击按钮后重定向页面到其他url

@Override
public boolean onJsConfirm(final WebView view, String url, String message, final JsResult result) {
	Log.e("测验", "onJsConfirm:"+url+",message:"+message+",jsResult:"+result.toString());
		new AlertDialog.Builder(chromeContext)
				.setTitle("阻拦JsConfirm显现!")
				.setMessage(message)
				.setPositiveButton(android.R.string.ok,
						new AlertDialog.OnClickListener() {
							public void onClick(DialogInterface dialog,int which) {
								//重定向页面
								view.loadUrl("file:///android_asset/javascript.html");
								result.confirm();
							}
						}).setCancelable(false).create().show();
	return true;
}

5、WebSettings

用于页面状况设置\插件支撑等装备.

(1)常用办法

WebSettings webSettings = webView.getSettings();
 /**
 * 设置缓存形式、支撑Js调用、缩放按钮、访问文件等
 */
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(true);
//答应WebView运用File协议,访问本地私有目录的文件
webSettings.setAllowFileAccess(true);
//答应经过file url加载的JS页面读取本地文件
webSettings.setAllowFileAccessFromFileURLs(true);
//答应经过file url加载的JS页面能够访问其他来历内容,包含其他的文件和http,https等来历
webSettings.setAllowUniversalAccessFromFileURLs(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setLoadsImagesAutomatically(true);
webSettings.setDefaultTextEncodingName("utf-8")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

完毕语

进程中有问题或者需求沟通的同学,能够扫描二维码加好友,然后进群进行问题和技术的沟通等;

安卓知识点-应届生扫盲安卓WebView