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

Android WebView真机无法渲染ChartJs位图(模拟器正常)

问题:WebView加载ChartJs截图真机显示全白,模拟器正常

在WebView中使用ChartJs生成图表时,真机上截图得到全白画面,但模拟器完全正常。已尝试以下操作但无效:

  • AndroidManifest中设置android:hardwareAccelerated="true"
  • App初始化调用WebView.enableSlowWholeDocumentDraw()
  • 加载URL前开启binding.wvContent.settings.javaScriptEnabled = true
  • 尝试两种截图代码(见下文)

将hardwareAccelerated设为false后问题解决,但希望找到其他不关闭全局硬件加速的方案。


尝试过的截图代码

代码1:

fun screenshot (webView:WebView):Bitmap?{
    try {
        val bitmap = Bitmap.createBitmap(webView.width, webView.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        webView.draw(canvas)
        return bitmap
    }
    catch (e: Exception) {
        e.printStackTrace()
    }
    return null
}

代码2:

fun screenShot(mWebView:WebView) {
    // measure the webview
    mWebView?.measure(
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
        View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED)
    )

    //layout of webview
    mWebView?.layout(0, 0, mWebView!!.measuredWidth, mWebView!!.getMeasuredHeight())

    mWebView?.isDrawingCacheEnabled = true
    mWebView?.buildDrawingCache(true)//create Bitmap if measured height and width >0
    val bm = if (mWebView?.measuredWidth!! > 0 && mWebView?.measuredHeight!! > 0) {
        Bitmap.createBitmap(
            mWebView?.measuredWidth!!,
            mWebView?.measuredHeight!!,
            Bitmap.Config.ARGB_8888
        )
    }
    else null

    // Draw bitmap on canvas
    bm?.let {
        Canvas(bm).apply {
            drawBitmap(it, 0f, bm.height.toFloat(), Paint())
            mWebView?.draw(this)
        }
    }
}

可行替代方案

1. 仅对目标WebView禁用硬件加速

不全局关闭硬件加速,只给出现问题的WebView单独禁用:

binding.wvContent.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

建议在WebView初始化完成后调用,比如onViewCreated或WebView加载完成的回调中设置。

2. 等待ChartJs渲染完成后再截图

真机硬件加速下ChartJs渲染速度慢于模拟器,过早截图会导致画面未绘制完成。通过WebView的JS接口监听渲染完成事件:

步骤1:H5端监听ChartJs渲染事件

// 假设H5中Chart实例名为myChart,监听动画完成事件
myChart.on('animationComplete', function() {
    window.android.notifyChartReady();
});

注:部分ChartJs版本可能使用render事件替代animationComplete,需根据实际版本调整

步骤2:Android端定义JS接口并触发截图

class ChartJavascriptInterface(private val screenshotCallback: () -> Unit) {
    @JavascriptInterface
    fun notifyChartReady() {
        // 回到主线程执行截图
        Handler(Looper.getMainLooper()).post {
            screenshotCallback.invoke()
        }
    }
}

// 给WebView添加JS接口
binding.wvContent.addJavascriptInterface(
    ChartJavascriptInterface {
        // 调用你的截图方法
        val bitmap = screenshot(binding.wvContent)
        // 处理截图结果
    }, 
    "android"
)

3. 使用WebView原生截图方法(API 21+)

尝试WebView原生的截图API,硬件加速下兼容性更好:

API 21-28:使用capturePicture

fun captureWebView(webView: WebView): Bitmap? {
    return try {
        val picture = webView.capturePicture()
        val bitmap = Bitmap.createBitmap(picture.width, picture.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        picture.draw(canvas)
        bitmap
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

API 28+:使用异步截图API

binding.wvContent.captureBitmapAsync(webView.width, webView.height) { bitmap ->
    // 处理截图结果
}

4. 优化DrawingCache截图逻辑

依赖WebView的DrawingCache,确保渲染完成后再生成缓存:

fun screenshotWithCache(webView: WebView): Bitmap? {
    return try {
        webView.setDrawingCacheEnabled(true)
        webView.drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
        // 先清理旧缓存
        webView.destroyDrawingCache()
        // 重新构建缓存
        webView.buildDrawingCache()
        // 复制缓存生成Bitmap
        Bitmap.createBitmap(webView.drawingCache).also {
            // 用完清理缓存
            webView.destroyDrawingCache()
            webView.setDrawingCacheEnabled(false)
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:45:12