WebView на китайских устройствах игнорирует принудительно установленный размер представления

У меня есть WebView, который адаптируется к высоте его содержимого:

        with(this.settings) {
            javaScriptEnabled = true
            allowFileAccess = true
            displayZoomControls = false
            builtInZoomControls = false
            cacheMode = WebSettings.LOAD_NO_CACHE
            layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL // Tried the default one
            setSupportZoom(false)
        }
        isVerticalScrollBarEnabled = false
        isHorizontalScrollBarEnabled = false
        setBackgroundColor(Color.TRANSPARENT)
        setLayerType(View.LAYER_TYPE_HARDWARE, null)
        setWebViewClient(webViewClient)
        clearCache(true)


        addJavascriptInterface(this, "MathView")
    private val webViewClient = object : WebViewClient() {

        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)

            Timber.d("onPageFinished: $url")

            invalidate()

            loadUrl("javascript:MathView.resize(document.body.scrollHeight)")
        }

        override fun onPageCommitVisible(view: WebView?, url: String?) {
            super.onPageCommitVisible(view, url)
            // skip code
            invalidate()
        }
    }

Когда страница загружается, я вызываю JS-код с обратным вызовом, чтобы узнать высоту содержимого:

@JavascriptInterface
    fun resize(newContentHeight: Float) {
        runOnMain {
            val calculatedHeight = (newContentHeight * resources.displayMetrics.density).toInt()
            val webViewContentHeight = (this.contentHeight * resources.displayMetrics.density).toInt()

            Timber.d("Content height changed: $newContentHeight for content $htmlBody")
            Timber.d("Calculated height: $calculatedHeight; current height: $height; webview content height: $webViewContentHeight")

            if (calculatedHeight != lastCalculatedHeight) {
                lastCalculatedHeight = calculatedHeight

                Timber.d("Setting new height: $calculatedHeight")

                updateLayoutParams {
                    height = lastCalculatedHeight
                    requestLayout()
                    invalidate()
                }
            }
        }
    }

// Я также вызываю этот код раз в секунду в отладочной версии, чтобы проверить размеры.

На большинстве устройств работает нормально:

Calculated height: 252; current height: 252; webview content height: 252
  • Calculated height - высота содержимого, сообщаемая JS, умноженная на плотность экрана
  • Current height - Высота WebView (как представление Android)
  • webview content height - высота содержимого, сообщаемая самим WebView

Как видите, все значения равны, и это правильно.

Но на разных китайских устройствах (Xiaomi MiA1 Android 9, Lenovo P1a42 Android 6.0.1) он игнорирует обновления макета и устанавливает другую высоту просмотра:

// Note: this is different content then above, so calculated height is not equal to the above one

Calculated height: 315; current height: 567; webview content height: 567
  • Calculated heught сообщенный JS верен
  • Current height а также webview content height неверны и не изменяются при обновлении параметров макета.

Как исправить эту проблему?

1 ответ

Решение

Хорошо, это ошибка многих разных китайских устройств, по крайней мере, Xiaomi и Lenovo, начиная с Android 6.0 и заканчивая Android 10 (Android 5.0-5.1 в порядке).

Похоже, они скопировали тот же неправильный код в свои прошивки.

Другие вопросы по тегам