Android WebView技术详解和经验分享

WebViewJS相互通信

WebView调用JS函数

通用方式,不能获取JS函数的返回值:

webView.loadUrl("javascript:alert('hello world');");

 

Android 4.4.及以上系统的WebView专用方式,可以获取JS函数的返回值:

webView.evaluateJavascript("javascript:add(2,3)", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
        Log.i("tag",value);
    }
});

 

JS调用Native函数

首先,需要通过WebView提供的函数注册JS对象
public class AndroidJSInterface {
    @JavascriptInterface //注意,所有可被JS调用的函数,一定要加上@JavascriptInterface,否则JS无法调用
    public String handler(String action, String value){
        return "";
    }
}

 

webView.addJavascriptInterface(new AndroidJSInterface(),"Android");
JS调用Native提供的handler函数的代码示例如下:
window.Android.handler("sayHello","hello world");
 
其中Android对象就是我们通过addJavascriptInterface()函数注册的JS对象
JS调用Native对象,支持有返回值的函数和没有返回值的函数
JS调用Native函数的时候,建议通过JSON数据来传值,不然的话,可能会出现调用失败的情况
比如:
window.Android.handler("sayHello",JSON.stringify(obj));
JS不再使用Native对象时,可以把Native对象注销掉
webView.removeJavascriptInterface("Android");

WebView加载URLHTML字符串的方法

WebView加载指定的url

不带http header
webView.loadUrl(mUrl);
http header
Map<String,String> httpHeaders=new LinkedHashMap<>();
httpHeaders.put("userName","kgdwbb");
webView.loadUrl(mUrl,httpHeaders);

WebView加载html片段

webView.loadData("<h1>title</h1>","text/html; charset=utf-8", null);

这里有一个问题,就是当webView.loadData()函数第三个参数传入页面的字符编码的时候,不起作用,可能是这个函数本身的问题

我的解决方法就是在第二个参数里面传入页面的字符编码,比如charset=utf-8,如果不显示指定页面的字符编码,在显示中文的时候可能会出现乱码的情况

WebView 发送POST请求

代码示例:

webView.loadUrl(mUrl);
byte[]data="hello world".getBytes();
webView.postUrl(mUrl,data);

WebView Cookie设置

WebView cookie设置一定要在LoadUrl函数之前调用,也就是说在WebView发送网络请求之前设置。

Android通过CookieManager类来设置Cookie,通过CookieSyncManager类把CookieManager类设置的Cookie数据保存到应用程序/data/data/databases/目录下的webviewCookiesChromium.db数据库的cookies表中,这个数据库属于全局公共数据库,对这个数据库的操作会影响所有WebView,所以在使用完这个数据库之后,一定要记得清除设置的Cookie数据,以免对其它使用WebView的APP造成影响。

 

下面是设置WebViewCookie的代码示例:

public static void synCookies(Context context, String url,Stringcookie) {
   
CookieManager cookieManager =CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
   
cookieManager.setCookie(url, cookie);
    CookieSyncManager.getInstance().sync();
}

其中cookie是键值对类型的字符串,比如cookie="userName=kgdwbb"

 

下面是清除WebViewCookie的代码示例:

public static void removeCookie() {
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.removeAllCookie();
    CookieSyncManager.getInstance().sync();
}

 

WebView缓存设置

设置WebView缓存的代码示例如下:

WebSettings webSettings=webView.getSettings();

webSettings.setAppCacheEnabled(true);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);

 

清除WebView缓存的代码如下:

webView.clearCache(true);

WebView历史堆栈

代码示例如下:

后退

if(webView.canGoBack()){
    webView.goBack();
    return;
}
 
前进
if(webView.canGoForward()){
    webView.goForward();
}
 
 
前进或后退
int steps=2;
if(webView.canGoBackOrForward(steps)){
    webView.goBackOrForward(steps);
}
 
WebView的堆栈列表进行操作
int backForwardListSize= webView.copyBackForwardList().getSize();
for(int i=0;i<backForwardListSize;i++){
    WebHistoryItem item=webView.copyBackForwardList().getItemAtIndex(i);
    Log.i("tag",item.getUrl());
}
 
清除WebView历史堆栈
webView.clearHistory();

WebView启用文件下载功能

示例代码如下:

webView.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType,long contentLength) {
        //在这里写真正的文件下载的代码,WebView是不会自动下载文件的
    }
});

onDownloadStart函数参数说明

url:就是服务器上文件的url地址或者文件流的地址

userAgent:就是用户浏览器的默认userAgent

contentDisposition:url对应的文件类型,当url是服务器上的一个真实文件时,这个值为空,当url是服务器上可以访问的文件流时,这个值就会包涵这个文件流的一些基本信息,比如文件名等

mimeType:文件或文件流的类型,比如二进制文件流的mimeType是application/octet-stream

当WebView需要下载网页里面的文件时,会调用这个文件下载接口,我们只需要处理这个接口,就可以实现文件下载功能。文件下载功能需要我们自己来实现,WebView默认是不提供文件下载功能的。

WebView支持文件选择

WebView默认不支持表单的file标签,如果想让WebView支持表单的file标签,我们可以这样做:

webView.setWebChromeClient(new WebChromeClient(){
    //当WebView需要显示文件选择器时,回调这个函数,我们可以重写这个函数,加载我们自定义的文件选择器
    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
    }
});

自定义WebView的错误页面

当WebView在加载网页的时候如果出现网络错误或者指定的网页不存在的时候,就会显示默认的错误页面,如果我们想重写这个默认的错误页面,可以用下面的方法:

webView.setWebViewClient(new WebViewClient(){
    //当WebView发生任何请求错误的时候,都会回调这个函数
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
view.loadUrl("file:///android_asset/error.html");//加载自定义的错误页面,前提是这个错码页面一定要存在assets文件夹下面
    }
});

忽略WebViewSSL证书错误

当WebView在加载https网页的时候,如果网页存在SSL证书错误,比如12306网站的证书错误,我们可以忽略网页的错误证书,继续执行下面的网页,我们可以这样做:

webView.setWebViewClient(new WebViewClient(){
    //当接收到服务器返回的SSL错误时,回调这个函数
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        super.onReceivedSslError(view, handler, error);
        handler.proceed();//忽略SSL证书错误,继续执行
    }
});

拦截WebView的所有网络请求

要拦截WebView的网络请求,我们可以这样做:

webView.setWebViewClient(new WebViewClient(){
    //当WebView需要进行任何网络请求时,都会调用这个函数,我们可以拦截这个函数,做相应的处理
    //比如加载缓存的图片等,这个函数已经被Android 4.4以上的系统废弃,建议在Android 4.4.及以上的系统使用新的函数
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return super.shouldInterceptRequest(view, url);
    }

    //当WebView需要进行任何网络请求时,都会调用这个函数,我们可以拦截这个函数,做相应的处理
    //比如加载缓存的图片等,这个函数属于Android 4.4及以上的WebView提供的新的函数
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        WebResourceResponse response=super.shouldInterceptRequest(view,request);
        return response;
    }
});

重写WebView H5 video标签的默认属性

要想让WebView里面的所有H5 video标签都显示默认的加载进度和视频的默认图片,我们可以这样做:

webView.setWebChromeClient(new WebChromeClient(){
    //获取video加载时默认显示的第一张图片
    @Override
    public Bitmap getDefaultVideoPoster() {
        return super.getDefaultVideoPoster();
    }

    //获取视频加载进度View,所以我们可以在这里重写默认的video加载进度
    @Override
    public View getVideoLoadingProgressView() {
        return super.getVideoLoadingProgressView();
    }
});

捕捉WebView网页输出的所有日志

要监控网页输出的日志,我们可以这样做:

webView.setWebChromeClient(new WebChromeClient(){
    //当JS输出日志时,回调这个函数
    @Override
    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
        return super.onConsoleMessage(consoleMessage);
    }
});

 

WebView JS计时器设置

默认情况下,WebView的计时器在APP进入后台的时候还是会执行的。如果想让APP进入后台的时候暂时WebView的计时器,在APP进入前台的时候恢复WebView的计时器,代码如下:

@Override
protected void onPause() {
    super.onPause();
    //当Activity页面进入后台的时候,暂停WebView的计时器,这样WebView页面的JS计时器就会被暂停
    if(webView!=null)
        webView.pauseTimers();
}

@Override
protected void onResume() {
    super.onResume();
    //当Activity页面进入前台的时候,恢复WebView的计时器,这样WebView页面的JS计时器就会被恢复执行
    if(webView!=null)
        webView.resumeTimers();
}

WebView资源释放

默认情况下,在Activity销毁的时候,WebView是不会自动释放它占用的系统资源的,我们需要手动进行释放,否则会造成严重的内存泄露,

下面是释放WebView占用内存的代码:

@Override
protected void onDestroy() {
    //释放WebView资源,否则会造成内存泄露
    if(webView!=null){
        webView.destroy();
        webView=null;
    }
    super.onDestroy();
}

WebView常用设置功能汇总

WebView启用JS支持

WebSettingswebSettings=webView.getSettings();

webSettings.setJavaScriptEnabled(true);

WebView启用双指缩放功能

webSettings.setDisplayZoomControls(true);//true显示缩放控件,false隐藏缩放控件
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(
true);

 

WebView启用https支持

在android 5.0之前,WebView是可以在http环境中直接访问https资源和服务的,但是在android 5.0及以后,要想在http环境访问https资源和服务,就需求在WebView中开启对https的支持,代码如下:

WebSettingswebSettings=webView.getSettings();

if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
   
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

WebView启用本地存储功能

默认情况下,是无法使用JSlocalStorage,sessionStorage对象访问本地存储的,下面是开启WebView本地存储功能的代码:
WebSettings webSettings=webView.getSettings();

webSettings.setDomStorageEnabled(true);

 

WebView启用LBS定位功能

WebSettings webSettings=webView.getSettings();
webSettings.setGeolocationEnabled(true);

WebView调试设置

这个API只支持Android 4.4及以上的系统,Android 4.4以下的系统默认开启了WebView的调用功能。

代码如下:

if(Build.VERSION.SDK_INT>Build.VERSION_CODES.KITKAT){
    webView.setWebContentsDebuggingEnabled(true);
}

我们可以借助Chrome浏览器来对WebView进行调试

 

WebSettings类解析

WebSettings webSettings=webView.getSettings();
//开启WebView对JS脚本的支持
webSettings.setJavaScriptEnabled(true);

//设置允许在http环境中访问https资源和服务
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
    webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

//设置默认的网页编码
webSettings.setDefaultTextEncodingName("utf-8");

//设置JS是否可以打开WebView新窗口
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

//设置WebView是否支持多窗口,为true,需要重写WebChromeClient#onCreateWindow函数
webSettings.setSupportMultipleWindows(true);

//禁止WebView加载网络图片
webSettings.setLoadsImagesAutomatically(false);
webSettings.setBlockNetworkImage(true);

//显示WebView提供的缩放控件
webSettings.setDisplayZoomControls(true);//true显示缩放控件,false隐藏缩放控件
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);

//开启WebView对数据库的支持
webSettings.setDatabaseEnabled(true);

//开启WebView的Storage功能,这样JS的localStorage,sessionStorage对象才可以使用
webSettings.setDomStorageEnabled(true);

//打开WebView的LBS功能,这样JS的geolocation对象才可以使用
webSettings.setGeolocationEnabled(true);

//设置WebView是否自动保存表单数据
webSettings.setSaveFormData(true);

//设置WebView的默认userAgent字符串
webSettings.setUserAgentString("");

//设置是否打开WebView的桌面模式,true是桌面模式,false是移动模式
webSettings.setUseWideViewPort(false);

//设置WebView的默认字体,可以通过这个函数,改变WebView的默认字体
webSettings.setStandardFontFamily("");
//设置WebView默认字体的大小
webSettings.setDefaultFontSize(20);
//设置WebView支持的最小字体大小
webSettings.setMinimumFontSize(12);
//设置页面的文本缩放倍数
webSettings.setTextZoom(2);

 

WebViewClient类解析

webView.setWebViewClient(new WebViewClient(){
    //当WebView需要加载新的url的时候会调用这个函数,在这个函数里面我们不能调用任何WebView的LoadUrl函数,
    //否则,会出现页面被多次加载,造成JS location.replace函数失效,还有看起来像302问题导致的WebView需要
    //多次点击才能返回的BUG
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return super.shouldOverrideUrlLoading(view, url);
    }

    //WebView页面已经开始加载指定的url
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
    }

    //WebView加载完指定的url
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Log.i("hello",url);
        view.loadUrl("javascript:window.android.handler('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
    }

    //当WebView需要进行任何网络请求时,都会调用这个函数,我们可以拦截这个函数,做相应的处理
    //比如加载缓存的图片等,这个函数已经被Android 4.4以上的系统废弃,建议在Android 4.4.及以上的系统使用新的函数
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return super.shouldInterceptRequest(view, url);
    }

    //当WebView需要进行任何网络请求时,都会调用这个函数,我们可以拦截这个函数,做相应的处理
    //比如加载缓存的图片等,这个函数属于Android 4.4及以上的WebView提供的新的函数
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        WebResourceResponse response=super.shouldInterceptRequest(view,request);
        return response;
    }

    //当WebView发生任何请求错误的时候,都会回调这个函数
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        view.loadUrl("file:///android_asset/error.html");//加载自定义的错误页面
    }

    //当WebView接收到服务器错误时,回调这个函数
    @Override
    public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
        super.onReceivedHttpError(view, request, errorResponse);
    }

    //当WebView表单重新提交时,回调这个函数
    @Override
    public void onFormResubmission(WebView view, Message dontResend, Message resend) {
        super.onFormResubmission(view, dontResend, resend);
    }

    //当WebView需要更新它的url访问数据库的时候,回调这个函数
    @Override
    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
        super.doUpdateVisitedHistory(view, url, isReload);
    }

    //当接收到服务器返回的SSL错误时,回调这个函数
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        super.onReceivedSslError(view, handler, error);
        handler.proceed();//忽略SSL证书错误,继续执行
    }

    //当WebView访问https服务器时,需要客户端提供对应的SSL证书时,回调这个函数
    @Override
    public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
        super.onReceivedClientCertRequest(view, request);
    }

    //当WebView接收到服务器的授权请求时,回调这个函数
    @Override
    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
        super.onReceivedHttpAuthRequest(view, handler, host, realm);
    }

    //当发生键盘事件时,回调这个函数
    @Override
    public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
        return super.shouldOverrideKeyEvent(view, event);
    }

    //当WebView的缩放值发生改变的时候,回调这个函数
    @Override
    public void onScaleChanged(WebView view, float oldScale, float newScale) {
        super.onScaleChanged(view, oldScale, newScale);
    }
});

WebChromeClient类解析

webView.setWebChromeClient(new WebChromeClient(){
    //当WebView加载进度改变时,回调这个函数
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);
    }

    //当通过JS改变html文档的标题时,回调这个函数
    @Override
    public void onReceivedTitle(WebView view, String title) {
        super.onReceivedTitle(view, title);
    }

    //当WebView开启多窗口模式时,需要处理这个函数,这位JS才可以打开多个WebView窗口
    @Override
    public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
        return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
    }

    //当JS关闭指定的WebView窗口时,回调这个函数
    @Override
    public void onCloseWindow(WebView window) {
        super.onCloseWindow(window);
    }

    //当JS调用alert函数时,回调这个函数
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        return super.onJsAlert(view, url, message, result);
    }

    //当JS调用confirm函数时,回调这个函数
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
        return super.onJsConfirm(view, url, message, result);
    }

    //当JS调用prompt函数时,回调这个函数
    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        return super.onJsPrompt(view, url, message, defaultValue, result);
    }

    //当JS使用geolocation API访问当前位置时,回调这个函数
    @Override
    public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
        super.onGeolocationPermissionsShowPrompt(origin, callback);
    }

    //当JS取消geolocation API访问的时候
    @Override
    public void onGeolocationPermissionsHidePrompt() {
        super.onGeolocationPermissionsHidePrompt();
    }

    //当JS输出日志时,回调这个函数
    @Override
    public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
        return super.onConsoleMessage(consoleMessage);
    }

    //获取video加载时默认显示的第一张图片
    @Override
    public Bitmap getDefaultVideoPoster() {
        return super.getDefaultVideoPoster();
    }

    //获取视频加载进度View,所以我们可以在这里重写默认的video加载进度
    @Override
    public View getVideoLoadingProgressView() {
        return super.getVideoLoadingProgressView();
    }

    //当JS获取访问历史记录时,回调这个函数
    @Override
    public void getVisitedHistory(ValueCallback<String[]> callback) {
        super.getVisitedHistory(callback);
    }

    //当WebView需要显示文件选择器时,回调这个函数,我们可以重写这个函数,加载我们自定义的文件选择器
    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
    }
});

WebView常用问题汇总

Android 7.0及以上系统WebView长按崩溃的解决方法

/**
 
* Android 7.0 WebView长按会崩溃,解决长按崩溃的办法,就是屏蔽掉Android7.0 WebView的长按事件
 */
privatevoid setWebViewLongClickListener(){
   
webView.setOnLongClickListener(new View.OnLongClickListener() {
       
@Override
       
public boolean onLongClick(View v) {
           
if(Build.VERSION.SDK_INT> Build.VERSION_CODES.N){//android 7.0 Nougat
               
return true;
           
}
            return false;
       
}
    });
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值