You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android WebView加载固定耗时30秒问题排查求助

Android WebView 固定30秒加载超时排查与解决

问题背景

我们的Android应用采用原生登录页,登录后进入带WebView的菜单Activity,每个菜单对应独立Activity且都有专属WebView,所有相关Activity均继承自SPBaseWebActivity基类。

此前运行正常,但一年前开始出现WebView加载固定耗时30秒的问题,通过WebViewClient统计指标确认耗时始终为30秒。

关键现象

  • HTML无远程依赖(所有资源打包在APK内),无AJAX请求
  • 仅保留"Hello world"的极简HTML可瞬间加载
  • 只要包含基础标签外的内容(如CSS链接),加载就卡30秒
  • 30秒内UI和logcat完全阻塞,无网络请求(Network Inspector确认)

已尝试无效操作

  • 开启/关闭硬件加速
  • 清空HTML内容
  • 禁用WebView调试模式
  • 移除WebViewClient
  • 加载google.com替代本地文件
  • 精简HTML内容
  • 卸载/更新Android System WebView
  • 开启/关闭Cookie管理

相关代码

OptionActivity.java

public class OptionActivity extends SPBaseWebActivity
{

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_web_calendar);

    this.webview = (WebView) findViewById(R.id.webview);
    DebugManager.log("Entered calendar activity");

    DebugManager.clearPerformanceCheckpoints("calendar_view");
    DebugManager.addPerformanceCheckpoint("calendar_view", "onCreate finished");
}

@Override
protected void onResume()
{
    super.onResume();

    DebugManager.addPerformanceCheckpoint("calendar_view", "onResume start");

    String url = "calendar.html";
    setupWebview(url);
    reloadOnResume = false;

    DebugManager.addPerformanceCheckpoint("calendar_view", "onResume finished - " + (System.currentTimeMillis() / 1000));
}

@Override
protected void onPageLoaded(WebView view, String url)
{
    super.onPageLoaded(view, url);

    DebugManager.addPerformanceCheckpoint("calendar_view", "onPageLoaded finished - " + (System.currentTimeMillis() / 1000));
}
}

SPBaseWebActivity.java

public class SPBaseWebActivity implements WebAppInterfaceDelegate
{
protected WebView webview = null;
protected WebAppInterface jsInterface = null;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

    //Remove title bar
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);

    if (this.webview == null)
        this.webview = (WebView)findViewById(R.id.webview);

    setupWebview(null);
}

protected void setupWebview(String url)
{
    if (this.webview != null)
    {
        if (url == null || url.length() == 0)
            url = "base/empty.html";
        else if (!url.contains("http"))
            url = "app/" + url;

        MVWebChromeClient mvwcc = new MVWebChromeClient();
        mvwcc.parentActivity = this;

        this.webview.setWebChromeClient(mvwcc);

        DebugManager.addPerformanceCheckpoint("webview_loading", "Webview client init - " + (System.currentTimeMillis() / 1000));

        this.webview.setWebViewClient(new WebViewClient()
        {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);

                DebugManager.addPerformanceCheckpoint("webview_loading", "onPageStarted - " + (System.currentTimeMillis() / 1000));
            }

            @Override
            public void onPageFinished(WebView view, String url)
            {
                if (android.os.Build.VERSION.SDK_INT >= 21)
                {
                    CookieManager.getInstance().setAcceptThirdPartyCookies(view, true);
                    CookieManager.getInstance().flush();
                }
                else
                    CookieManager.getInstance().setAcceptCookie(true);

                DebugManager.addPerformanceCheckpoint("webview_loading", "onPageLoaded - " + (System.currentTimeMillis() / 1000));
                onPageLoaded(view, url);
            }
        });

        DebugManager.addPerformanceCheckpoint("webview_loading", "Webview client created - " + (System.currentTimeMillis() / 1000));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WebView.setWebContentsDebuggingEnabled(Globals.DEBUG);
        }

        if (!url.contains("http"))
            this.webview.loadUrl("file:///android_asset/pages/" + url);
        else
            this.webview.loadUrl(url);

        this.webview.getSettings().setJavaScriptEnabled(true);
        this.webview.getSettings().setAllowFileAccessFromFileURLs(true);
        this.webview.getSettings().setAllowUniversalAccessFromFileURLs(true);
        this.webview.getSettings().setDomStorageEnabled(true);

        this.jsInterface = new WebAppInterface(this);
        this.jsInterface.delegate = this;
        this.jsInterface.parentActivity = this;

        if (android.os.Build.VERSION.SDK_INT >= 21)
        {
            CookieManager.getInstance().setAcceptThirdPartyCookies(this.webview, true);
            CookieManager.getInstance().flush();
        }
        else
            CookieManager.getInstance().setAcceptCookie(true);

        this.webview.addJavascriptInterface(this.jsInterface, "Android");
        this.webview.requestFocus();
    }
}
}

calendar.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <title>MV Reports - Agendamento</title>
    
    <link rel="stylesheet" href="../../mv/css/bootstrap.min.css" />
    <link rel="stylesheet" href="../../mv/addons/font-awesome/css/font-awesome.min.css" />
    <link rel="stylesheet" href="../../mv/addons/material2/css/materialdesignicons.min.css" />
</head>
<body>
    Takes 30 to load
</body>
</html>

排查与解决建议

  1. 验证本地资源路径有效性
    HTML中CSS使用相对路径../../mv/css/...,WebView加载本地asset文件时,相对路径以当前HTML所在位置为基准。确认file:///android_asset/pages/app/calendar.html对应的上级路径是否存在目标资源,若路径错误,WebView内部可能因尝试加载不存在的资源触发隐性超时,导致主线程阻塞。

  2. 调整WebView初始化顺序
    当前代码先调用loadUrl再配置WebSettings和JS接口,可能导致WebView未完成配置就开始加载,引发内部阻塞。建议修改setupWebview方法顺序:先配置WebSettings、设置客户端、添加JS接口,最后调用loadUrl。

  3. 抓取主线程调用栈定位阻塞点
    30秒固定超时+UI阻塞,大概率是主线程被WebView同步操作卡住。用Android Studio Profiler抓取阻塞期间的主线程调用栈,查看具体执行逻辑,定位是资源加载、JS引擎初始化还是其他同步操作导致的停滞。

  4. 禁用WebView自动资源加载
    部分WebView版本会自动预加载关联资源,若资源路径异常可能触发超时。可先禁用自动加载图片测试:

    webview.getSettings().setLoadsImagesAutomatically(false);
    webview.getSettings().setBlockNetworkImage(true);
    

    若加载恢复正常,再逐步排查具体是哪个资源导致的问题。

  5. 清理WebView缓存与数据
    本地资源加载异常可能与WebView缓存损坏有关,测试阶段可调用以下代码清理:

    WebStorage.getInstance().deleteAllData();
    webview.clearCache(true);
    CookieManager.getInstance().removeAllCookies(null);
    

内容的提问来源于stack exchange,提问作者Sagito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:50:24