专栏首页技术小黑屋Android WebView 诊断与排查问题的方法和技巧

Android WebView 诊断与排查问题的方法和技巧

WebView,是安卓中很重要的一个组件,我们的应用中集成WebView后,可能会遇到各种各样的问题,这里简单介绍一些Android WebView 诊断与排查问题的方法,希望对于大家有这方面的问题的朋友有所帮助。

开启DiagnosableWebViewClient日志输出

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

package com.droidyue.webview.webviewclient import android.net.http.SslError import android.webkit.* import com.droidyue.common.debugMessage import com.droidyue.webview.ext.toSimpleString /** * 诊断(错误信息)的WebViewClient,会以日志输出形式输出错误信息,便于发现网页的问题 */ open class DiagnosableWebViewClient : WebViewClient() { override fun onReceivedError(view: WebView?, errorCode: Int, description: String?, failingUrl: String?) { super.onReceivedError(view, errorCode, description, failingUrl) debugMessage("onReceivedError", "errorCode", errorCode, "description", description, "failingUrl", failingUrl, "webview.info", view?.toSimpleString()) } override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { super.onReceivedError(view, request, error) debugMessage("onReceivedError", "request", request?.toSimpleString(), "error", error?.toSimpleString(), "webview.info", view?.toSimpleString()) } override fun onSafeBrowsingHit(view: WebView?, request: WebResourceRequest?, threatType: Int, callback: SafeBrowsingResponse?) { super.onSafeBrowsingHit(view, request, threatType, callback) debugMessage("onSafeBrowsingHit", "request", request?.toSimpleString(), "threatType", threatType, "webview.info", view?.toSimpleString()) } override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) { super.onReceivedHttpError(view, request, errorResponse) debugMessage("onReceivedHttpError", "request", request, "errorResponse", errorResponse?.toSimpleString(), "webview.info", view?.toSimpleString()) } override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) { super.onReceivedSslError(view, handler, error) debugMessage("onReceivedSslError", "error", error, "webview.info", view?.toSimpleString()) } }

举个例子

WebView页面出现了白屏,不展示任何内容,如下图

利用上面支持的内容,我们查看错误输出日志

1 2 3

D debugMessage: ConcreteWebViewClient;onReceivedSslError error primary error: 3 certificate: Issued to: CN=sni.cloudflaressl.com,O=Cloudflare\, Inc.,L=San Francisco,ST=CA,C=US; D debugMessage: Issued by: C=NZ,ST=Auckland,L=Auckland,O=XK72 Ltd,OU=https://charlesproxy.com/ssl,CN=Charles Proxy CA (4 Sep 2018\, bogon); D debugMessage: on URL: https://droidyue.com/ webview.info url=https://droidyue.com/;originalUrl=null

通过查找源码(SslError.java)我们了解到

  • errorCode 为 3,代表证书不信任。

这其中的缘由是

  • 我们在设备上安装的charles证书,属于用户添加的证书
  • 出于应用安全的目的,Android 7及之后默认不信任用户添加的证书(Android 7 之前是默认信任用户添加的证书)
  • 当我们将App的编译目标提到24及其以上,系统就会激活这一安全限制。

所以,我们按照这篇文章解决Android手机连接Charles Unknown问题的方案,允许App在debug版本下信任用户证书就可以解决问题了。

Console日志查看

比如,我们有这样一段Javascript代码处理console输出。

1 2 3 4 5

console.debug("console.debug"); console.log("console.log"); console.info("console.info"); console.warn("console.warn"); console.error("console.error")

我们使用

1

adb logcat | grep "chromium" --line-buffered --color=always | grep CONSOLE --color=always

可以过滤出WebView CONSOLE的日志输出

1 2 3 4 5

I chromium: [INFO:CONSOLE(2)] "console.debug", source: (2) I chromium: [INFO:CONSOLE(3)] "console.log", source: (3) I chromium: [INFO:CONSOLE(4)] "console.info", source: (4) I chromium: [INFO:CONSOLE(5)] "console.warn", source: (5) I chromium: [INFO:CONSOLE(6)] "console.error", source: (6)

但是这样也有一个不足,就是没有打印出Console的消息级别(都展示成了INFO:CONSOLE)。

如果想要解决上面的不足或者自定义日志输出关键字的话,可以重写实现WebChromeClient的onConsoleMessage方法

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

package com.droidyue.webview.chromeclient import android.webkit.ConsoleMessage import android.webkit.WebChromeClient import com.droidyue.common.debugMessage import com.droidyue.webview.ext.toSimpleString open class DiagnosableChromeClient: WebChromeClient() { override fun onConsoleMessage(message: String?, lineNumber: Int, sourceID: String?) { //不需要调用super方法 debugMessage("onConsoleMessage", "message", message, "lineNumber", lineNumber, "sourceID", sourceID) } override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean { debugMessage("onConsoleMessage", "message", consoleMessage?.toSimpleString()) //返回true,不再需要webview内部处理 return true } }

1 2 3 4 5

D debugMessage: ConcreteWebChromeClient;onConsoleMessage message messageLevel=TIP;message=console.debug;sourceId=;lineNumber=1 D debugMessage: ConcreteWebChromeClient;onConsoleMessage message messageLevel=LOG;message=console.log;sourceId=;lineNumber=2 D debugMessage: ConcreteWebChromeClient;onConsoleMessage message messageLevel=LOG;message=console.info;sourceId=;lineNumber=3 D debugMessage: ConcreteWebChromeClient;onConsoleMessage message messageLevel=WARNING;message=console.warn;sourceId=;lineNumber=4 D debugMessage: ConcreteWebChromeClient;onConsoleMessage message messageLevel=ERROR;message=console.error;sourceId=;lineNumber=5

开启 WebView 远程调试

从Android Kitkat(4.4)开始,WebView 支持与Chrome 连接执行远程调试。

开启很简单,如下代码

1 2 3 4 5

fun WebView.enableRemoteDebugging() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG) { WebView.setWebContentsDebuggingEnabled(true) } }

但需要注意两点

  • 一定要限定运行设备大于等于4.4系统
  • 强烈建议限定在Debug编译(或等同条件)包下开启,不建议Release包也启用该功能

配置完成后,启动App,打开Chrome,输入chrome://inspect

可以调试的功能有

  • 审查元素
  • 执行Javascript
  • 查看网页资源
  • 进行性能分析
  • 其他功能

具体内容可以访问https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews了解。

推荐阅读

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Kotlin编译调校之WarningsAsErrors

    这之前的文章中,我们介绍过如果通过Kotlin编译器参数实现将所有的warnings按照errors对待,主要的实现方法是这样

    技术小黑屋
  • 快速高效调试移动端前端代码

    通常,前端调试输出一些日志信息可以使用alert或者console, 当然在Desktop机器上很容易,很多浏览器都支持,如果是在手机上,可能比较麻烦,怎么得到...

    技术小黑屋
  • 深入剖析 Android中的 ArrayMap

    数据集合在任何一门编程语言中都是很重要的一部分,在 Android 开发中,我们会实用到ArrayList, LinkedList, HashMap等。其中Ha...

    技术小黑屋
  • 8张JavaScript思维导图

      思维导图小tips:思维导图又叫心智图,是表达发射性思维的有效的图形思维工具 ,它简单却又极其有效,是一种革命性的思维工具。思维导图运用图文并重的技巧,把各...

    前端迷
  • 跟着9张思维导图学习Javascript

    Sb_Coco
  • linux(十四)之linux NFS服务管理

    学到这里差不多就结束了linux的基础学习了,其实linux的内容并不难,我们要经常的反复的去操作它,多多和它去联络感情才能很好的掌握这个linux。 加油!今...

    用户1195962
  • Python - loguru日志库,高效输出控制台日志和日志记录

    loguru的PyPI地址为:https://pypi.org/project/loguru/

    小菠萝测试笔记
  • Java函数的传参机制

    最近的一个项目,里面各种返回void,参数用引用类型,那叫一个熟和多,但是也把我绕糊涂了。

    ydymz
  • 懒人神器 autoenv

    前言 每次去不同的项目下运行程序都要更改相对应的 Python 环境,那么有什么办法可以省去这繁琐的一步吗?答案肯定是有的,Kenneth Reitz 已经为我...

    木制robot
  • CentOS7.2中安装MongoDB

    MongoDB是由C++编写的NoSQL的分布式文件数据库,用的json格式的k-value存储方式。

    拓荒者

扫码关注云+社区

领取腾讯云代金券