0


展开说说: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的属性和状态的方法

@SuppressLint("SetJavaScriptEnabled")
private void initWebSettings() {
    WebSettings settings = webView.getSettings();
    //如果要与加载页面中的JavaScript交互,必须设置;
        settings.setJavaScriptEnabled(false);
    }else {
        settings.setJavaScriptEnabled(true);
    }
    //关闭密码保存提醒
    settings.setSavePassword(false);
    //设置自适应屏幕,将图片调整到适合webView的大小,缩放至屏幕的大小
    settings.setUseWideViewPort(true);
    settings.setLoadWithOverviewMode(true);

    //特别注意:5.1以上禁止https和http混用,以下是开启,一般是用于测试环境是http生产是https的场景。如果要都支持就得开启
    if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP){
        settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    }
}

*1.2 WebChromeClient辅助WebView处理Javascript对话框*感觉是浏览器级别的相关方法

onProgressChanged、onJsAlert、onJsPrompt、onJsConfirm

*1.3 WebViewClient处理各种通知,事件请求webview组件加载页面的相关回调属于加载请求相关的*

shouldOverrideUrlLoading 用于拦截URL请求,可对制定url进行处理。比如网页内在跳转其他地址这里可以拦截并打印****或者重定向再次请求加载。

onPageStarted 页面开始加载时调用

onPageFinished 页面加载结束时调用

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

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

onScaleChanged 页面缩放

   @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        Uri url = request.getUrl();
        Log.e(TAG, "shouldOverrideUrlLoading:  url= "+url+"    Method="+request.getMethod()+"     Headers="+request.getRequestHeaders() );
//        return super.shouldOverrideUrlLoading(view, request);
        return false;
    }

    /**
     * 页面开始加载时
     */
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        Log.e(TAG, "onPageStarted: url="+url );
    }

    /**
     * 页面加载结束时调用
     * @param view
     * @param url
     */
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Log.e(TAG, "onPageFinished: url="+url );
            }

    /**
     * 页面加载出错-1
     */
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        switch (errorCode){
            case 404:
                //todo 加载错误页面
                break;
        }
    }

    /**
     * 页面加载出错时-2
     * @param view
     * @param request
     * @param error
     */

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        Log.e(TAG, "onReceivedError: ErrorCode="+error.getErrorCode()+"    Description="+error.getDescription() );
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        super.onReceivedSslError(view, handler, error);
        Log.e(TAG, "onReceivedSslError: " );

        handler.proceed();
          // 等待证书响应
//        handler.cancel();
            // 挂起连接,默认方式
//        handler.handleMessage(null);
        // 可做其他处理
    }

    @Override
    public void onScaleChanged(WebView view, float oldScale, float newScale) {
        super.onScaleChanged(view, oldScale, newScale);
        Log.e(TAG, "onScaleChanged: " );
    }

里说一下上面几个方法的调用顺序

onPageStarted是在onProgressChanged****执行之后才会执行;

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

onReceivedError如果执行一定是在onPageFinished****之后

还需要注意Android原生调用js需要在onPageFinished回调之后调用否则不生效,因为B页面还没加载完你喊破嗓子也不理你.

以下是加载一个网页的结合了WebChromeClientWebviewClient的完整****运行日志:

 2024-02-20 14:16:05.971 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=10
         * 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/
         * 2024-02-20 14:16:06.093 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=70
         * 2024-02-20 14:16:06.247 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=100
         * 2024-02-20 14:16:06.247 24004-24004/com.example.testdemo3 E/com.example.testdemo3.webview.MyWebChromeClient: onProgressChanged: newProgress=100
         * 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/
         * 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加载网页

//加载网页-加载方式一,加载互联网地址
webView.loadUrl(URL);
//加载网页-加载方式二:apk内本地html文件  我assets文件中放了一个javascriptTest.html文件,文章末尾贴出了代码
webView.loadUrl("file:///android_asset/javascriptTest.html");//加载本地文件
                //加载网页-加载方式三:手机内存本地html文件
//                webView.loadUrl("content://com.android.htmlfileprovider/sdcard/javascriptTest.html");
                //加载网页-加载方式三:加载html中某一段代码
 webView.loadData(String data, String mimeType, String encoding);

2、Android原生代码调用html

//调用一:C调用B方法并传值, 如果C调用B还想拿到B的返回值可以再执行一次B调C,因为loadUrl是一个无返回值的方法。success方法内传参也可以是一个json,B端用JSON.stringify(value)接收的
webView.loadUrl("javascript:success('真的成功了')");

 //C调B-调用二:  必须这样调用少一个单引号或双引号都不行,有点除了效率高之外还可以onReceiveValue回调方法接收C端的返回值
                webView.evaluateJavascript("success('" + "就是成功了" + "')", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        //这个value返回的是你调用的方法,中return的返回内容,如果无return默认返回都是null。我这里success方法会的是 "B给C的,接住咯"
                        Log.e(TAG, "onReceiveValue: value= "+value );
//                        2024-05-07 10:38:22.254 28435-28435/com.example.testdemo3 E/com.example.testdemo3.activity.WebViewActivity: onReceiveValue: value= "B给C的,接住咯"
                    }
                });

3、Html调用Android原生代码

*** BC方法:
*** 第一:addJavascriptInterface
,但是4.2有漏洞,4.2以上官方推荐
*** 第二:WebviewClientshouldOverrideUrlLoading,需要约定号url地址,C端拦截后做出不同操作
*** 第三:WebChromeClient
onJsAlertonJsConfirmonJsPrompt,和上一个类似都需要先约定再从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调用的方法

public class JsBridge {
    public static final String TAG = "JsBridge";

    @JavascriptInterface
    public void allowScreenShot(String value){
        Log.e(TAG, "allowScreenShot:   value= "+value );
        Toast.makeText(BaseApplication.getContext(),"C端接收到"+value,Toast.LENGTH_SHORT).show();
    }

    @JavascriptInterface
    public int takePhoto(int key,String status, int value){
        Log.e(TAG, "takePhoto:  key= "+key+"    status="+status+"     value= "+value);
        return key+value;
    }
}

5、assets文件夹中javascriptTest.html文件内容

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Carson</title>
    <script>

         function callAndroid(){
          //  var res = test.clientLog("js调用了android中的hello方法");
          //Native.faceDetect("s","fail")
            //Native.clientLog(res);
            //Native.saveData("test", "123");
            //var res = Native.loadData("test");
            //var res = Native.notifyLoginStatus(true,1)
            //alert(res)
            //var res = Native.encrypt("123");
            //alert(res);
            //Native.previewPdf("http://122.29.205.94:8080/afs/appDownLoad/test.pdf")
            //Native.previewWord("http://122.29.205.94:8080/afs/appDownLoad/text.docx")
            //B调用C端方法并传值
            var value = Native.takePhoto(2,"fail",3)
            alert("C端返回"+value);
            //Native.downloadPicture("http://122.29.205.94:8080/afs/appDownLoad/pic2.png","s","fail");
            //Native.allowScreenShot("0");
         }
          function  fail(){
                alert("失败了")
            }
          function  success(args){
                alert("成功了-"+JSON.stringify(args))
                return "B给C的,接住咯"
            }
         function callJs(arg){return arg+1}
        function callAndroid2(){
        //C端设置的两个别名都可以滴调用C端方法
            Native.allowScreenShot("1");
            B2CTest.allowScreenShot("1-1");
        }
    </script>
</head>
<body>
<button id="button1" style="font-size:60px;" onclick="callAndroid()" type="button">点击调用</button>
<button class="button" id="button2" onclick="callAndroid2()" type="button">点击调用2</button>

</body>

<style>
    .button {
        font-size:60px;
        margin-left:50px;
    }
</style>
</html>

javascriptTest.html文件有很多方法我都是调一个就注释了换下一个方法测试其他场景,辛苦您也动态的去换和调试。

才疏学浅,如有错误,欢迎指正,多谢。

标签: android

本文转载自: https://blog.csdn.net/Hidanchaofan/article/details/138589760
版权归原作者 老梁学Android&HarmonyOS 所有, 如有侵权,请联系我们删除。

“展开说说:Android之WebView详解”的评论:

还没有评论