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

  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端拦截后做出不同操作
*** 第三: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调用的方法

  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文件有很多方法我都是调一个就注释了换下一个方法测试其他场景,辛苦您也动态的去换和调试。

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

标签: android

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

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

还没有评论