公众号:
欢迎关注我的个人公众号,来一起交流Android 开发知识
一、简介
本来不想专门找一节来介绍webview技术的,因为现在对于混合开发有很多的框架比如RN和FLutter,但是这些框架对于一些webview页面比较少的项目来说显得重量级了一些。因此还是单独整理一篇出来,供以后项目的参考及学习。写这篇文章确实花了很长的时间,一方面觉得很混乱,api很多都想说一点,另一方面觉得以后这些api到底能不能用到。因此有些章节说的比较笼统,我也给出了参考的博客地址,对于想深入了解的同学可以参考这些博客。
WebView在Android平台上用于显示网页。WebView是一个基于WebKit引擎、展现Web页面的控件,Android的WebView在低版本和高版本采用了不同的WebKit版本内。4.4后WebView内部实现并不是完全使用Chrome内核,而是部分使用了Chrome内核,其他都是与Chrome不相同的。
二、WebView的使用
webview的使用有两种方式:一种是直接显示网页内容;另一种就是与JS进行交互。
2.1基本使用
2.1.1、webview加载在线的URL地址 。
public class MainActivity extends AppCompatActivity {
private WebView mWebView ;
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState) ;
setContentView(R.layout. activity_main ) ;
mWebView =(WebView)findViewById(R.id. webview ) ;
mWebView .loadUrl( " http://www.baidu.com" ) ;
mWebView .setWebViewClient( new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading (WebView view , String url) {
mWebView .loadUrl(url );
return true;
}
}) ;
}
################ 布局文件 ############################
xml version= "1.0" encoding= "utf-8" ?>
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"+ ===
tools :context= ".MainActivity" >
android :id= "@+id/webview"
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
app :layout_constraintBottom_toBottomOf= "parent"
app :layout_constraintLeft_toLeftOf= "parent"
app :layout_constraintRight_toRightOf= "parent"
app :layout_constraintTop_toTopOf= "parent" />
权限:
注意: 1、webview加载的url地址必须包含http://或者https://协议完整的域名地址,webview不会默认填充。
2、系统会默认通过手机浏览器去打开网页,为了能够直接通过webview显示网页,必须设置webviewclient.此
外还必须要添加相关权限。
2.1.2、加载本地的html文件。
加载本地的html文件有两种,一种是加载本地assets目录下的文件,这种html文件会打包到APK文件中,另一种是加载手机本地sdcard下的html文件。加载两种类型的html文件同样调用loadurl()方法,只不过url地址则需要加些前缀:
如果html文件存放在assets目录下则前缀为:file:///android_asset/+你的html文件名.html(注意这里有三个斜杠)
如果html文件存放在sdcard下,则前缀为:content://com.android.htmlprovider/sdcard/+你的html文件名.html(注意:content前缀可能会导致异常,可以使用file:///sdcard/+你的html文件.html)你可以在手机浏览器中将“ file:///sdcard/+你的html文件.html”复制到访问栏可以测试能不能访问到。
具体代码为:
webview.loadUrl("file:///android_asset/test.html ”);//加载assets夹下的html文件
webview.loadUrl(" file:///sdcard/test.html ”);//加载sdcard文件夹下的html文件
注意:
这里我们看出加载本地的html文件是不需要设置webviewclient的,而加载线上的html文件必须设置webviewclient。
三、webview的基本设置
/**
* 是否支持缩放,配合方法setBuiltInZoomControls使用,默认true
*/
setSupportZoom(boolean support)
/**
* 是否需要用户手势来播放Media,默认true
*/
setMediaPlaybackRequiresUserGesture(boolean require)
/**
* 是否使用WebView内置的缩放组件,由浮动在窗口上的缩放控制和手势缩放控制组成,默认false
*/
setBuiltInZoomControls(boolean enabled)
/**
* 是否显示窗口悬浮的缩放控制,默认true
*/
setDisplayZoomControls(boolean enabled)
/**
* 是否允许访问WebView内部文件,默认true
*/
setAllowFileAccess(boolean allow)
/**
* 是否允许获取WebView的内容URL ,可以让WebView访问ContentPrivider存储的内容。 默认true
*/
setAllowContentAccess(boolean allow)
/**
* 是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
*/
setLoadWithOverviewMode(boolean overview)
/**
* 是否保存表单数据,默认false
*/
setSaveFormData(boolean save)
/**
* 设置页面文字缩放百分比,默认100%
*/
setTextZoom(int textZoom)
/**
* 是否支持ViewPort的meta tag属性,如果页面有ViewPort meta tag 指定的宽度,则使用meta tag指定的值,否则默认使用宽屏的视图窗口
*/
setUseWideViewPort(boolean use)
/**
* 是否支持多窗口,如果设置为true ,WebChromeClient#onCreateWindow方法必须被主程序实现,默认false
*/
setSupportMultipleWindows(boolean support)
/**
* 指定WebView的页面布局显示形式,调用该方法会引起页面重绘。默认LayoutAlgorithm#NARROW_COLUMNS
*/
setLayoutAlgorithm(LayoutAlgorithm l)
/**
* 设置标准的字体族,默认”sans-serif”。font-family 规定元素的字体系列。
* font-family 可以把多个字体名称作为一个“回退”系统来保存。如果浏览器不支持第一个字体,
* 则会尝试下一个。也就是说,font-family 属性的值是用于某个元素的字体族名称或/及类族名称的一个
* 优先表。浏览器会使用它可识别的第一个值。
*/
setStandardFontFamily(String font)
/**
* 设置混合字体族。默认”monospace”
*/
setFixedFontFamily(String font)
/**
* 设置SansSerif字体族。默认”sans-serif”
*/
setSansSerifFontFamily(String font)
/**
* 设置SerifFont字体族,默认”sans-serif”
*/
setSerifFontFamily(String font)
/**
* 设置CursiveFont字体族,默认”cursive”
*/
setCursiveFontFamily(String font)
/**
* 设置FantasyFont字体族,默认”fantasy”
*/
setFantasyFontFamily(String font)
/**
* 设置最小字体,默认8. 取值区间[1-72],超过范围,使用其上限值。
*/
setMinimumFontSize(int size)
/**
* 设置最小逻辑字体,默认8. 取值区间[1-72],超过范围,使用其上限值。
*/
setMinimumLogicalFontSize(int size)
/**
* 设置默认字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。
*/
setDefaultFontSize(int size)
/**
* 设置默认填充字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。
*/
setDefaultFixedFontSize(int size)
/**
* 设置是否加载图片资源,注意:方法控制所有的资源图片显示,包括嵌入的本地图片资源。
* 使用方法setBlockNetworkImage则只限制网络资源图片的显示。值设置为true后,
* webview会自动加载网络图片。默认true
*/
setLoadsImagesAutomatically(boolean flag)
/**
* 是否加载网络图片资源。注意如果getLoadsImagesAutomatically返回false,则该方法没有效果。
* 如果使用setBlockNetworkLoads设置为false,该方法设置为false,也不会显示网络图片。
* 当值从true改为false时。WebView会自动加载网络图片。
*/
setBlockNetworkImage(boolean flag)
/**
* 设置是否加载网络资源。注意如果值从true切换为false后,WebView不会自动加载,
* 除非调用WebView#reload().如果没有android.Manifest.permission#INTERNET权限,
* 值设为false,则会抛出java.lang.SecurityException异常。
* 默认值:有android.Manifest.permission#INTERNET权限时为false,其他为true。
*/
setBlockNetworkLoads(boolean flag)
/**
* 设置是否允许执行JS。
*/
setJavaScriptEnabled(boolean flag)
/**
* 是否允许Js访问任何来源的内容。包括访问file scheme的URLs。考虑到安全性,
* 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的,
* 不会受到影响。ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本
* 以上默认为false
*/
setAllowUniversalAccessFromFileURLs(boolean flag)
/**
* 是否允许Js访问其他file scheme的URLs。包括访问file scheme的资源。考虑到安全性,
* 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的,
* 不会受到影响。如果getAllowUniversalAccessFromFileURLs为true,则该方法被忽略。
* ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本以上默认为false
*/
setAllowFileAccessFromFileURLs(boolean flag)
/**
* 设置存储定位数据库的位置,考虑到位置权限和持久化Cache缓存,Application需要拥有指定路径的
* write权限
*/
setGeolocationDatabasePath(String databasePath)
/**
* 是否允许Cache,默认false。考虑需要存储缓存,应该为缓存指定存储路径setAppCachePath
*/
setAppCacheEnabled(boolean flag)
/**
* 设置Cache API缓存路径。为了保证可以访问Cache,Application需要拥有指定路径的write权限。
* 该方法应该只调用一次,多次调用自动忽略。
*/
setAppCachePath(String appCachePath)
/**
* 是否允许数据库存储。默认false。查看setDatabasePath API 如何正确设置数据库存储。
* 该设置拥有全局特性,同一进程所有WebView实例共用同一配置。注意:保证在同一进程的任一WebView
* 加载页面之前修改该属性,因为在这之后设置WebView可能会忽略该配置
*/
setDatabaseEnabled(boolean flag)
/**
* 是否存储页面DOM结构,默认false。
*/
setDomStorageEnabled(boolean flag)
/**
* 是否允许定位,默认true。注意:为了保证定位可以使用,要保证以下几点:
* Application 需要有android.Manifest.permission#ACCESS_COARSE_LOCATION的权限
* Application 需要实现WebChromeClient#onGeolocationPermissionsShowPrompt的回调,
* 接收Js定位请求访问地理位置的通知
*/
setGeolocationEnabled(boolean flag)
/**
* 是否允许JS自动打开窗口。默认false
*/
setJavaScriptCanOpenWindowsAutomatically(boolean flag)
/**
* 设置页面的编码格式,默认UTF-8
*/
setDefaultTextEncodingName(String encoding)
/**
* 设置WebView代理,默认使用默认值
*/
setUserAgentString(String ua)
/**
* 通知WebView是否需要设置一个节点获取焦点当
* WebView#requestFocus(int,android.graphics.Rect)被调用的时候,默认true
*/
setNeedInitialFocus(boolean flag)
/**
* 基于WebView导航的类型使用缓存:正常页面加载会加载缓存并按需判断内容是否需要重新验证。
* 如果是页面返回,页面内容不会重新加载,直接从缓存中恢复。setCacheMode允许客户端根据指定的模式来
* 使用缓存。
* LOAD_DEFAULT 默认加载方式
* LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存
* LOAD_NO_CACHE 不使用缓存
* LOAD_CACHE_ONLY 只使用缓存
*/
setCacheMode(int mode)
/**
* 设置加载不安全资源的WebView加载行为。KITKAT版本以及以下默认为MIXED_CONTENT_ALWAYS_ALLOW方
* 式,LOLLIPOP默认MIXED_CONTENT_NEVER_ALLOW。强烈建议:使用MIXED_CONTENT_NEVER_ALLOW
*/
setMixedContentMode(int mode)
上述是所有的webview的设置方法,我们只需要按需通过webviewsetting设置即可。
四、JS互调
4.1 JS调用Java代码
js调用java代码是通过接口注入的方式实现的,主要用到的方法是:
public void addJavascriptInterface (Object obj , String interfaceName) { }
第一个参数是我们注入js中的对象,第二个参数为这个对象的别名。这个别名就是在html中引用的名称,来指代我们传入第一个参数的对象。什么意思呢?打个比喻第一个参数我们传的对象名称就张飞,他的别名可以随便起一个,都是指代张飞这个对象,我们可以传翼德。html就用翼德这个名字去实现自己的方法。
另外一定要开启js交互
WebSettings settings = mWebView .getSettings() ;
settings.setJavaScriptEnabled( true ) ;
这里实现一个简单的功能,js调用java本地代码,弹一个toast
@SuppressLint ({ "AddJavascriptInterface" , "SetJavaScriptEnabled" })
private void jsCallJava () {
WebSettings settings = mWebView .getSettings() ;
settings.setJavaScriptEnabled( true ) ;
settings.setSupportZoom( false ) ;
mWebView .addJavascriptInterface( new JsBridge(MainActivity. this ) , "AndroidWebView" ) ;
mWebView .loadUrl( "file:///android_asset/test2.html" ) ;
}
//JsBridge代码
package com.sheca.mystudydemo2 ;
import android.app.Activity ;
import android.util.Log ;
import android.webkit. JavascriptInterface ;
import android.widget.Toast ;
/**
* @author xuchangqing
* @time 2019/12/20 15:03
* @descript
*/
public class JsBridge {
private Activity mContext ;
public JsBridge (Activity mContext){
this . mContext =mContext ;
}
@JavascriptInterface
public void showInfoFromJs ( final String message){
mContext .runOnUiThread( new Runnable() {
@Override
public void run () {
Log. e ( "js" , message ) ;
Toast. makeText ( mContext , message + ”调用了", Toast. LENGTH_SHORT ).show() ;
}
}) ;
}
@JavascriptInterface
public int sub ( int first ,int second){
Toast. makeText ( mContext , second-first+ ”调用了" , Toast. LENGTH_SHORT ).show() ;
return second-first ;
}
}
我们看一下html中的代码:
html >
lang= "en" >
charset= "UTF-8" >
Title
我的博客
type= "button" value= "js调用java" οnclick= "f1()" >
type= "button" value= "js调用java减法" οnclick= "f2()" >
html中的AndroidWebView就是我们队注入对象起的别名,showInfoFromJs就是注入对象中的方法。
注意在android版本17以上必须在注入接口对象中,对html调用的方法加入
@JavascriptInterface
4.2 java调用JS
前面已经介绍了通过loadurl()来调用js中的方法,但是这种调用没有办法获取js的返回值,那么怎么拿到js调用的返回值呢?
在4.4也就是api版本17以前,我们调用js方法之后,js再通过接口注入调用java本地的方法,将结果回传过来。但是我们知道这种效率很低,很不方便。在4.4之后,提供了evaluateJavascript(),我们看一下示例代码:
在test2.html文件中我们定义一个函数,用于java调用。
function f3(){
return "我是谁?我在哪?";
}
看一下本地是如何调用的
//js返回值
@SuppressLint ({ "AddJavascriptInterface" , "SetJavaScriptEnabled" })
private void jsCallJavaForReturn () {
WebSettings settings = mWebView .getSettings() ;
settings.setJavaScriptEnabled( true ) ;
settings.setSupportZoom( false ) ;
// mWebView.addJavascriptInterface(new JsBridge(MainActivity.this),"AndroidWebView");
mWebView .loadUrl( "file:///android_asset/test2.html" ) ;
mWebView .setWebViewClient( new WebViewClient() {
@Override
public void onPageFinished (WebView view , String url) {
super .onPageFinished(view , url) ;
mWebView .evaluateJavascript( "javascript:f3()" , new ValueCallback() {
@Override
public void onReceiveValue (String value) {
Toast. makeText (MainActivity. this, value , Toast. LENGTH_SHORT ).show() ;
}
}) ;
}
}) ;
}
注意: 1、evaluateJavascript()这个方法必须保证在主线程中执行,另外回调onReceiveValue()这个方法也是在主线程中执行
的。
2、evaluateJvascript()第一次执行会收到null,再执行一次就能得到正确的返回结果。必须保证在网页加载完毕后再执
行这个方法,所以在onPageFinished()方法执行后执行。
3、上述例子返回值类型为String类型,对于复杂的数据类型我们可以采用Json的形式返回。
五、WebViewClient
5.1 shouldOverrideUrlLoading
上面我们介绍到加载在线的url必须设置webviewClient,所以我们通常的写法都是
mWebView.setWebViewClient(new WebViewClient());
并没有重写shouldOverrideUrlLoading()这个方法,那么我们看一下这个方法是做什么的。
官方文档给出的解释:
我们可以通过这个方法来控制访问新的url,如果没有设置webviewclient,那么webview就会通过ActivityManager
为这个url选择适当的处理方式,如果设置了webviewclient,返回true表示由APP层处理URL,如果返回false表示由
当前 webview处理url。对于使用post请求的,不会调用此方法。
简而言之,如果我们想拦截某个url的访问就可以重新这个方法。比如我们想拦截所有包含”blog.csdn.net“的地址,重定向访问”www.baidu.com“可以怎么写呢?
webview .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;
}
}
) ;
webview .loadUrl( " https://blog.csdn.net/FlyRabbit_1" ) ;
}
注意 :这里我们返回的是true,在之前我们已经知道true表示拦截了该url,由APP层自己处理URL。对于其他的url如果不包含
” https://blog.csdn.net/“这个地址的一定要在else中重写view.load(url)方法,否则出现点击链接没有效果的情况。如果返回的是false我们就可以不进行判断else中的view.loadUrl(url)的处理,原因我们前面已经说过了。
webview .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;
}
}
) ;
webview .loadUrl( " https://blog.csdn.net/FlyRabbit_1" ) ;
}
所以我们一般建议return false只关心拦截的url,对于其他的url不关心处理。
5.2 页面处理
5.2.1 loading动画
加载webview添加loading动画需要使用webviewclient的两个方法,onPageStarted();onPageFinished();
webview .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;
}
@Override
public void onPageStarted (WebView view , String url , Bitmap favicon) {
super .onPageStarted(view , url , favicon) ;
mProgress .show() ;
}
@Override
public void onPageFinished (WebView view , String url) {
super .onPageFinished(view , url) ;
mProgress .dismiss() ;
}
}
) ;
webview .loadUrl( " https://blog.csdn.net/" ) ;
}
5.2.2 错误页面加载
我们可以在本地自定义一个错误页面,调用onRecivedError()方法
这个方法需要我们传入四个参数,webview对象,错误码(加载url返回的错误码),错误描述,已经失败地址。
我们只需要在这个方法中加载我们自定义好的错误页面即可。
@Override
public void onReceivedError (WebView view , WebResourceRequest request , WebResourceError error) {
// super.onReceivedError(view, request, error);
view.loadUrl( "file:///android_asset/error.html" ) ;
}
5.2.3onRecivedSSLError();
这个方法是在当请求HTTPS通信的网址出现错误的时候的回调。默认的请求方式为super.onReceivedSslError(view, handler, error)。如果取消加载页面我们可以调用handler.cancle(),继续加载我们可以调用handler.proceed()来继续加载错误的页面。
还有一点要说明一下,当出现SSL错误的时候webview默认是取消加载页面的,只有我们设置handler.proceed()才能继续加载页面。另外当SSL发生错误的时候onRecivedError不会产生回调。
5.2.4webviewclient的其他函数
/**
* 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次
*/
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)
如果webview包含多个页面通常我们点击返回键,会直接finish掉app而不是返回上一个页面,我们希望回调上个页面而不是退出浏览器该怎么设置呢?在Activity中重写onKeyDown(int keyCoder,KeyEvent event)方法,返回上一个页面。
六、webviewChromeClient
webviewChromeClient与webviewClient是针对不同webview事件的回调,webviewClient处理各种通知与请求事件,而webviewChromeClient处理js对话框、网站图标、title、加载进度等等。
我们先看一下webviewChromeClient常用的函数有哪些
/**
* 当网页调用alert()来弹出alert弹出框前回调,用以拦截alert()函数
*/
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
/**
* 当网页调用confirm()来弹出confirm弹出框前回调,用以拦截confirm()函数
*/
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
/**
* 当网页调用prompt()来弹出prompt弹出框前回调,用以拦截prompt()函数
*/
public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result)
/**
* 打印 console 信息
*/
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
/**
* 通知程序当前页面加载进度
*/
public void onProgressChanged(WebView view, int newProgress)
/*
* 通知页面标题变化
*/
nReceivedTitle(WebView view, String title)
/*
* 通知当前页面网站新图标
*/
onReceivedIcon(WebView view, Bitmap icon)
/*
* 通知主程序图标按钮URL
*/
onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)
/*
* 通知主程序当前页面将要显示指定方向的View,该方法用来全屏播放视频。
*/
public interface CustomViewCallback {
// 通知当前页面自定义的View被关闭
public void onCustomViewHidden();
}
onShowCustomView(View view, CustomViewCallback callback)
/*
* 与onShowCustomView对应,通知主程序当前页面将要关闭Custom View
*/
onHideCustomView()
/**
* 请求主程序创建一个新的Window,如果主程序接收请求,返回true并创建一个新的WebView来装载Window,然后添加到View中,发送带有创建的WebView作为参数的resultMsg的给Target。如果主程序拒绝接收请求,则方法返回false。默认不做任何处理,返回false
*/
onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)
/*
* 显示当前WebView,为当前WebView获取焦点。
*/
onRequestFocus(WebView view)
/*
* 通知主程序关闭WebView,并从View中移除,WebCore停止任何的进行中的加载和JS功能。
*/
onCloseWindow(WebView window)
/**
* 告诉客户端显示离开当前页面的导航提示框。如果返回true,由客户端处理确认提示框,调用合适的JsResult方法。如果返回false,则返回默认值true给javascript接受离开当前页面的导航。默认:false。JsResult设置false,当前页面取消导航提示,否则离开当前页面。
*/
onJsBeforeUnload(WebView view, String url, String message, JsResult result)
/**
*通知主程序web内容尝试使用定位API,但是没有相关的权限。主程序需要调用调用指定的定位权限申请的回调。更多说明查看GeolocationPermissions相关API。
*/
onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback)
/*
* 通知程序有定位权限请求。如果onGeolocationPermissionsShowPrompt权限申请操作被取消,则隐藏相关的UI界面。
*/
onGeolocationPermissionsHidePrompt()
/**
*通知主程序web内容尝试申请指定资源的权限(权限没有授权或已拒绝),主程序必须调用PermissionRequest#grant(String[])或PermissionRequest#deny()。如果没有覆写该方法,默认拒绝。
*/
onPermissionRequest(PermissionRequest request)
/**
* 通知主程序相关权限被取消。任何相关UI都应该隐藏掉。
*/
onPermissionRequestCanceled(PermissionRequest request)
/**
* 通知主程序 执行的Js操作超时。客户端决定是否中断JavaScript继续执行。如果客户端返回true,JavaScript中断执行。如果客户端返回false,则执行继续。注意:如果继续执行,重置JavaScript超时计时器。如果Js下一次检查点仍没有结束,则再次提示。
*/
onJsTimeout()
/**
*当停止播放,Video显示为一张图片。默认图片可以通过HTML的Video的poster属性标签来指定。如果poster属性不存在,则使用默认的poster。该方法允许ChromeClient提供默认图片。
*/
getDefaultVideoPoster()
/**
* 当用户重放视频,在渲染第一帧前需要花费时间去缓冲足够的数据。在缓冲期间,ChromeClient可以提供一个显示的View。如:可以显示一个加载动画。
*/
getVideoLoadingProgressView()
/**
* 获取访问历史Item,用于链接颜色。
*/
getVisitedHistory(ValueCallback callback)
/**
* 通知客户端显示文件选择器。用来处理file类型的HTML标签,响应用户点击选择文件的按钮操作。调用filePathCallback.onReceiveValue(null)并返回true取消请求操作。
* FileChooserParams参数的枚举列表:
MODE_OPEN 打开
MODE_OPEN_MULTIPLE 选中多个文件打开
MODE_OPEN_FOLDER 打开文件夹(暂不支持)
MODE_SAVE 保存
*/
onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams)
/**
* 解析文件选择Activity返回的结果。需要和createIntent一起使用。
*/
parseResult(int resultCode, Intent data)
/**
* 创建Intent对象来启动文件选择器。Intent支持可访问的简单类型文件资源。不支持高级文件资源如live media capture媒体快照。如果需要访问这些资源或其他高级文件类型资源可以自己创建Intent对象。
*/
createIntent()
/**
* 返回文件选择模式
*/
getMode()
/**
* 返回可访问MIME类型数组,如audio/*,如果没有指定可访问类型,数组返回为null
*/
getAcceptTypes()
/**
* 返回优先的媒体快照类型值如Camera、Microphone。true:允许快照。false,禁止快照。使用getAcceptTypes方法确定合适的capture设备。
*/
isCaptureEnabled()
/**
* 返回文件选择器的标题。如果为null,使用默认名称。
*/
getTitle()
/**
*指定默认选中的文件名或为null
*/
getFilenameHint()
6.1 对话框
我们主要介绍一下通过webviewChromeClient处理一些webview的对话框:
常见的有三种类型的对话框:Alert、Confirm、Prompt对话框。
在这里我们只说一个alert对话框,剩余的两个实现方法是一样的。这三个函数的返回值类型都是boolean类型,默认情况下返回的是super()也就是父类的函数为false.返回类型为false是调用的是webview系统的对话框,表示我们没有拦截系统调用对话框的方法,如果返回值类型为true,表示我们拦截系统弹出的对话框,这个时候我们要注意调用jsResult.confirm()确认或者调用jsResult.cancle()来取消,注意如果我们不调用这两个方法中的一个,再次点击按钮的时候会导致点击按钮没有反应。
我们看一下实现的代码:
html代码
html >
lang= "en" >
charset= "UTF-8" >
Title
οnclick= "confirm('是否删除?')" > confirm
οnclick= "alert(' ⚠️ 警告!系统即将爆炸,立即撤离!')" > alert
οnclick= "prompt('请输入内容')" > prompt
java调用代码
package com.sheca.mystudydemo2 ;
import android.os.Bundle ;
import android.support.v7.app.AppCompatActivity ;
import android.webkit.JsPromptResult ;
import android.webkit.JsResult ;
import android.webkit.WebChromeClient ;
import android.webkit.WebSettings ;
import android.webkit.WebView ;
import android.webkit.WebViewClient ;
import android.widget.Toast ;
public class DialogWebView extends AppCompatActivity {
private WebView mDialogWebView ;
@Override
protected void onCreate (Bundle savedInstanceState) {
super .onCreate(savedInstanceState) ;
setContentView(R.layout. activity_dialog_web_view ) ;
initView() ;
}
private void initView () {
mDialogWebView =(WebView)findViewById(R.id. webview_dialog ) ;
WebSettings settings = mDialogWebView .getSettings() ;
settings.setJavaScriptEnabled( true ) ;
mDialogWebView .setWebViewClient( new WebViewClient()) ;
mDialogWebView .setWebChromeClient( new WebChromeClient(){
@Override
public boolean onJsAlert (WebView view , String url , String message , JsResult result) {
// return super.onJsAlert(view, url, message, result);
Toast. makeText (DialogWebView. this, "url" +url+ "msg" +message , Toast. LENGTH_SHORT ).show() ;
result.confirm() ;
return true;
}
@Override
public boolean onJsPrompt (WebView view , String url , String message , String defaultValue , JsPromptResult result) {
return super .onJsPrompt(view , url , message , defaultValue , result) ;
}
@Override
public boolean onJsConfirm (WebView view , String url , String message , JsResult result) {
return super .onJsConfirm(view , url , message , result) ;
}
}) ;
mDialogWebView .loadUrl( "file:///android_asset/dialog.html" ) ;
}
}
6.2webview的优化
这部分的知识点比较多。
可以从缓存、性能等方面进行优化
可以参考以下博文:
美团技术团队: https://tech.meituan.com/2017/06/09/webviewperf.html
任玉刚: https://juejin.im/post/5b94ca52e51d450e7d097f38
今日头条: https://www.jianshu.com/p/85e4f982cbdf
6.3webivew调试:
手机端和PC端都要安装Chrome浏览器,手机端的浏览器版本要比PC端的版本低。在Android4.4版本以上调用setWebContentsDebuggingEnabled启用webView调试,设置代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
在浏览器中输入:Chrome://inspect进入调试页面,点击inspect即可进行调试了。
关于Webview的用到的知识点先介绍到这里。