作者
大家好,我叫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);
}
完毕语
进程中有问题或者需求沟通的同学,能够扫描二维码加好友,然后进群进行问题和技术的沟通等;