ToB企服应用市场:ToB评测及商务社交产业平台

标题: 睁开说说:Android之WebView详解 [打印本页]

作者: 我爱普洱茶    时间: 2024-10-5 14:36
标题: 睁开说说:Android之WebView详解
WebView是基于webkit引擎展现web页面的控件。不同系统版本使用webkit版本不同,4.4后直接使用了chrome
作用:显示和渲染web页面加载url;直接使用html文件(网络上或assests中)做布局;可以和javaScript交互调用。
一个特殊的view除了具备一般view的属性,还可以对url请求、页面加载、渲染、Android与html页面交互进行强盛处理。


1、WebView三大件

1.1 WebSettings提供常用的设置WebView的属性和状态的方法

  1. @SuppressLint("SetJavaScriptEnabled")
  2. private void initWebSettings() {
  3.     WebSettings settings = webView.getSettings();
  4.     //如果要与加载页面中的JavaScript交互,必须设置;
  5.         settings.setJavaScriptEnabled(false);
  6.     }else {
  7.         settings.setJavaScriptEnabled(true);
  8.     }
  9.     //关闭密码保存提醒
  10.     settings.setSavePassword(false);
  11.     //设置自适应屏幕,将图片调整到适合webView的大小,缩放至屏幕的大小
  12.     settings.setUseWideViewPort(true);
  13.     settings.setLoadWithOverviewMode(true);
  14.     //特别注意:5.1以上禁止https和http混用,以下是开启,一般是用于测试环境是http生产是https的场景。如果要都支持就得开启
  15.     if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP){
  16.         settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
  17.     }
  18. }
复制代码
1.2 WebChromeClient辅助WebView处理Javascript对话框感觉是欣赏器级别的相关方法

onProgressChanged、onJsAlert、onJsPrompt、onJsConfirm

1.3 WebViewClient处理各种关照,变乱请求webview组件加载页面的相关回调属于加载请求相关的

   shouldOverrideUrlLoading 用于拦截URL请求,可对订定url进行处理。好比网页内涵跳转其他地址这里可以拦截并打印大概重定向再次请求加载。

onPageStarted 页面开始加载时调用

onPageFinished 页面加载结束时调用

onReceivedError 这个方法有两个,都是页面加载堕落时调用;在某些情况下方法二会调用上面一的重载方法,详见源码

onReceivedSslError SSL证书加载堕落时调用,应急情况可以选择绕过证书

onScaleChanged 页面缩放

  1.    @Override
  2.     public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
  3.         Uri url = request.getUrl();
  4.         Log.e(TAG, "shouldOverrideUrlLoading:  url= "+url+"    Method="+request.getMethod()+"     Headers="+request.getRequestHeaders() );
  5. //        return super.shouldOverrideUrlLoading(view, request);
  6.         return false;
  7.     }
  8.     /**
  9.      * 页面开始加载时
  10.      */
  11.     @Override
  12.     public void onPageStarted(WebView view, String url, Bitmap favicon) {
  13.         super.onPageStarted(view, url, favicon);
  14.         Log.e(TAG, "onPageStarted: url="+url );
  15.     }
  16.     /**
  17.      * 页面加载结束时调用
  18.      * @param view
  19.      * @param url
  20.      */
  21.     @Override
  22.     public void onPageFinished(WebView view, String url) {
  23.         super.onPageFinished(view, url);
  24.         Log.e(TAG, "onPageFinished: url="+url );
  25.             }
  26.     /**
  27.      * 页面加载出错-1
  28.      */
  29.     @Override
  30.     public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
  31.         super.onReceivedError(view, errorCode, description, failingUrl);
  32.         switch (errorCode){
  33.             case 404:
  34.                 //todo 加载错误页面
  35.                 break;
  36.         }
  37.     }
  38.     /**
  39.      * 页面加载出错时-2
  40.      * @param view
  41.      * @param request
  42.      * @param error
  43.      */
  44.     @RequiresApi(api = Build.VERSION_CODES.M)
  45.     @Override
  46.     public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
  47.         super.onReceivedError(view, request, error);
  48.         Log.e(TAG, "onReceivedError: ErrorCode="+error.getErrorCode()+"    Description="+error.getDescription() );
  49.     }
  50.     @Override
  51.     public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
  52.         super.onReceivedSslError(view, handler, error);
  53.         Log.e(TAG, "onReceivedSslError: " );
  54.         handler.proceed();
  55.           // 等待证书响应
  56. //        handler.cancel();
  57.             // 挂起连接,默认方式
  58. //        handler.handleMessage(null);
  59.         // 可做其他处理
  60.     }
  61.     @Override
  62.     public void onScaleChanged(WebView view, float oldScale, float newScale) {
  63.         super.onScaleChanged(view, oldScale, newScale);
  64.         Log.e(TAG, "onScaleChanged: " );
  65.     }
复制代码
里说一下上面几个方法的调用顺序

onPageStarted是在onProgressChanged实行之后才会实行;

onPageFinished是在onProgressChanged加载到100之后才实行;

onReceivedError假如实行肯定是在onPageFinished之后

还需要注意Android原生调用js需要在onPageFinished回调之后调用否则不生效,因为B页面还没加载完你喊破嗓子也不理你.
以下是加载一个网页的结合了WebChromeClientWebviewClient的完整运行日志:
  1. 2024-02-20 14:16:05.971 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=10
  2.          * 2024-02-20 14:16:05.991 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebviewClient: onPageStarted: url=https://mp.weixin.qq.com/
  3.          * 2024-02-20 14:16:06.093 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=70
  4.          * 2024-02-20 14:16:06.247 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=100
  5.          * 2024-02-20 14:16:06.247 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=100
  6.          * 2024-02-20 14:16:06.247 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebviewClient: onPageFinished: url=https://mp.weixin.qq.com/
  7.          * 2024-02-20 14:16:06.300 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebviewClient: onReceivedError: ErrorCode=-10    Description=net::ERR_UNKNOWN_URL_SCHEME
复制代码
Android使用webView加载网页

  1. //加载网页-加载方式一,加载互联网地址
  2. webView.loadUrl(URL);
  3. //加载网页-加载方式二:apk内本地html文件  我assets文件中放了一个javascriptTest.html文件,文章末尾贴出了代码
  4. webView.loadUrl("file:///android_asset/javascriptTest.html");//加载本地文件
  5.                 //加载网页-加载方式三:手机内存本地html文件
  6. //                webView.loadUrl("content://com.android.htmlfileprovider/sdcard/javascriptTest.html");
  7.                 //加载网页-加载方式三:加载html中某一段代码
  8. webView.loadData(String data, String mimeType, String encoding);
复制代码
2、Android原生代码调用html

  1. //调用一:C调用B方法并传值, 如果C调用B还想拿到B的返回值可以再执行一次B调C,因为loadUrl是一个无返回值的方法。success方法内传参也可以是一个json,B端用JSON.stringify(value)接收的
  2. webView.loadUrl("javascript:success('真的成功了')");
  3. //C调B-调用二:  必须这样调用少一个单引号或双引号都不行,有点除了效率高之外还可以onReceiveValue回调方法接收C端的返回值
  4.                 webView.evaluateJavascript("success('" + "就是成功了" + "')", new ValueCallback<String>() {
  5.                     @Override
  6.                     public void onReceiveValue(String value) {
  7.                         //这个value返回的是你调用的方法,中return的返回内容,如果无return默认返回都是null。我这里success方法会的是 "B给C的,接住咯"
  8.                         Log.e(TAG, "onReceiveValue: value= "+value );
  9. //                        2024-05-07 10:38:22.254 28435-28435/com.example.testdemo3 E/com.example.testdemo3.activity.WebViewActivity: onReceiveValue: value= "B给C的,接住咯"
  10.                     }
  11.                 });
复制代码
3、Html调用Android原生代码


* BC方法:
* 第一:addJavascriptInterface,但是4.2有漏洞,4.2以上官方保举
* 第二:WebviewClientshouldOverrideUrlLoading,需要约定号url地址,C端拦截后做出不同操作
* 第三:WebChromeClientonJsAlertonJsConfirmonJsPrompt,和上一个类似都需要先约定再从C端拦截,4.2之前用的比力多

第一种需要Android设置:

//这里设置多个别名,B页面可以使用任意一个来调用C端方法
webView.addJavascriptInterface(new JsBridge(),"Native");//4.2之前有漏洞,4.2以后官方保举,引入了@JavascriptInterface注解
webView.addJavascriptInterface(new JsBridge(),"B2CTest");//4.2之前有漏洞,4.2以后官方保举,引入了@JavascriptInterface注解


//假如要与加载页面中的JavaScript交互,必须设置;不设置的加载上面一片空白大概页面报错了,也没法和assets中的html里的script代码交互
//对于不想加载的地址可以在这里做限定。好比可以根据协议克制file协议加载JavaScript,制止域控制不严酷的漏洞
if (URL.startsWith("file://")){
    settings.setJavaScriptEnabled(false);
}else {

//假如与html交互这里必须为true
    settings.setJavaScriptEnabled(true);
}

4、Android原生使用@JavascriptInterface注解定义的供B断html调用的方法

  1. public class JsBridge {
  2.     public static final String TAG = "JsBridge";
  3.     @JavascriptInterface
  4.     public void allowScreenShot(String value){
  5.         Log.e(TAG, "allowScreenShot:   value= "+value );
  6.         Toast.makeText(BaseApplication.getContext(),"C端接收到"+value,Toast.LENGTH_SHORT).show();
  7.     }
  8.     @JavascriptInterface
  9.     public int takePhoto(int key,String status, int value){
  10.         Log.e(TAG, "takePhoto:  key= "+key+"    status="+status+"     value= "+value);
  11.         return key+value;
  12.     }
  13. }
复制代码
5、assets文件夹中javascriptTest.html文件内容

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="utf-8">
  5.     <title>Carson</title>
  6.     <script>
  7.          function callAndroid(){
  8.           //  var res = test.clientLog("js调用了android中的hello方法");
  9.           //Native.faceDetect("s","fail")
  10.             //Native.clientLog(res);
  11.             //Native.saveData("test", "123");
  12.             //var res = Native.loadData("test");
  13.             //var res = Native.notifyLoginStatus(true,1)
  14.             //alert(res)
  15.             //var res = Native.encrypt("123");
  16.             //alert(res);
  17.             //Native.previewPdf("http://122.29.205.94:8080/afs/appDownLoad/test.pdf")
  18.             //Native.previewWord("http://122.29.205.94:8080/afs/appDownLoad/text.docx")
  19.             //B调用C端方法并传值
  20.             var value = Native.takePhoto(2,"fail",3)
  21.             alert("C端返回"+value);
  22.             //Native.downloadPicture("http://122.29.205.94:8080/afs/appDownLoad/pic2.png","s","fail");
  23.             //Native.allowScreenShot("0");
  24.          }
  25.           function  fail(){
  26.                 alert("失败了")
  27.             }
  28.           function  success(args){
  29.                 alert("成功了-"+JSON.stringify(args))
  30.                 return "B给C的,接住咯"
  31.             }
  32.          function callJs(arg){return arg+1}
  33.         function callAndroid2(){
  34.         //C端设置的两个别名都可以滴调用C端方法
  35.             Native.allowScreenShot("1");
  36.             B2CTest.allowScreenShot("1-1");
  37.         }
  38.     </script>
  39. </head>
  40. <body>
  41. <button id="button1" style="font-size:60px;" onclick="callAndroid()" type="button">点击调用</button>
  42. <button class="button" id="button2" onclick="callAndroid2()" type="button">点击调用2</button>
  43. </body>
  44. <style>
  45.     .button {
  46.         font-size:60px;
  47.         margin-left:50px;
  48.     }
  49. </style>
  50. </html>
复制代码
javascriptTest.html文件有很多方法我都是调一个就注释了换下一个方法测试其他场景,辛苦您也动态的去换和调试。
才疏学浅,如有错误,欢迎指正,多谢。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4