Android开发之路之 webview

公众号:

欢迎关注我的个人公众号,来一起交流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"?>
<android.support.constraint.ConstraintLayout
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"+    ===
    tools:context=".MainActivity">
 
    <WebView
        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"/>
 
</android.support.constraint.ConstraintLayout>
 
 
权限:
<use-permission android:name=“android.permission.INTERNET”/>
注意: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中的代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <h1 >我的博客</h1>
</head>
 
<body>
<input type="button" value="js调用java" οnclick="f1()">
<input type="button" value="js调用java减法" οnclick="f2()">
<script type="text/javascript">
function f1() {
   AndroidWebView.showInfoFromJs("哈哈,i m webview msg");
}
 
function f2() {
   AndroidWebView.sub(2,1);
}
</script>
</body>
</html>
 
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<String>() {
                    @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)
 
5.2.5webview的响应事件的处理
 
如果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代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button οnclick="confirm('是否删除?')">confirm</button>
<button οnclick="alert('⚠️警告!系统即将爆炸,立即撤离!')">alert</button>
<button οnclick="prompt('请输入内容')">prompt</button>
</body>
</html>
 
 
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的优化
这部分的知识点比较多。 可以从缓存、性能等方面进行优化 可以参考以下博文:
 
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的用到的知识点先介绍到这里。
 
发布了16 篇原创文章 · 获赞 1 · 访问量 5958

猜你喜欢

转载自blog.csdn.net/FlyRabbit_1/article/details/103965001
今日推荐