最近在做kotlin+compose 项目里内嵌webview渲染web页面的功能,但是遇到了不少麻烦问题,正好记录下。

问题: webview 的H5页面html的 高度始终为0,无法撑满页面,最后用浏览器调试发现是web项目有一个这样的样式定义,而webviw初始化的时候是拿不到内容的真实高度的

html, body {
    height: 100%
}

所以其实问题也不在web项目,是在kotlin compose自动计算webview高度的时候,会先获取内容高度去计算怎么适配大小,但是因为100%这时候又无法获取真实的高度,所以webview里的html实际高度为0(感觉根本应该是这个问题,有知道的大佬也可以分享一下)

解决:给webview一个真实的高度,有两种方式

第一种方式: 获取webview的父节点剩余高度并赋值给webview, 思路就是套一个Box上设置weight(1f), 就会占据父节点剩余的高度, 参考代码【当然,如果全占满就不需要包一个box了】

var availableHeight by remember { mutableIntStateOf(0) }

Column(modifier = modifier.fillMaxSize()) {
        Text(
            text = title,
            fontSize = 26.sp
        )

        // 用Compose剩余高度设置
        Box( modifier = Modifier
            .weight(1f)
            .onGloballyPositioned { coordinates ->
                availableHeight = coordinates.size.height
            }
        ) {

            if(availableHeight > 0) {
                AndroidView(
                    factory = { 
                        WebView(getApplication<Application>()).apply{
                            layoutParams = ViewGroup.LayoutParams(
                                ViewGroup.LayoutParams.MATCH_PARENT,
                                availableHeight  // 强制指定像素高度
                            )
                        }
                    },
                )
            }
        }
    }

第二种方式:获取屏幕高度减去安全区域高度和其他被占用的高度,参考代码

val configuration = LocalConfiguration.current
val screenHeight = with(LocalDensity.current) {
    configuration.screenHeightDp.dp.toPx().toInt()
}
// 减去系统栏(可选)
// val statusBar = WindowInsets.statusBars.getTop(density)
// val navBar = WindowInsets.navigationBars.getBottom(density)
// val safeHeight = screenHeightPx - statusBar - navBar

AndroidView(
    modifier = Modifier.fillMaxSize()
    factory = {
        WebView(getApplication<Application>()).apply{
           layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                screenHeight // 强制指定像素高度
        )
      }
    },
)

感觉还是第一种方式方便点,起码不用考虑减去其他高度

另外, 要让webview的内容高度正常,需要确认下面几步是否都正确:

  1. 确认H5页面在浏览器内可以正常打开
  2. 检查h5是否有定义viewport并且设置了width="device-width"
  3. 是否有可能的http请求报错(一般h5能打开 + 允许http配置是没有问题的)
  4. 对应的父compose节点是否有高度(一般是fillMaxSize或者fillMaxHeight)
  5. webview里的url不能是http(可以在Manifest文件里配置强制开通, 配置步骤附在后面)
  6. 写一段测试html查看webview是否能正确显示(测试代码附在后面)
  7. 用chrome浏览器辅助调试,查看H5页面的dom是否有正常显示(测试步骤附在后面)

附:

  1. 允许http本地调试的配置: 

如果需要http,需要在src/debug/res/xml文件夹下新建一个network_security_config.xml文件,在这里面设置允许http协议(注意: 放在debug文件下是因为只在

debug阶段本地测试,毕竟允许http是有风险的)。 然后src/debug/AndroidManifest.xml(没有的话就

新建)文件里引用该文件

network_security_config.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!-- 允许指定域名所有明文流量(仅限调试!) -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">线上测试http地址.com</domain>
    </domain-config>

    <!-- 允许本机所有明文流量(仅限调试!) -->
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

AndroidManifest.xml:文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application
        android:networkSecurityConfig="@xml/network_security_config">
    </application>
</manifest>

2. 测试代码,用于验证webview配置是否正确

LaunchedEffect(Unit) {
        val html = """
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="utf-8">
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <style>
                    body { background: lightblue; margin: 20px; }
                    h1 { color: red; font-size: 24px; }
                </style>
            </head>
            <body>
                <h1>✅ WebView 测试成功!</h1>
                <p>如果看到这个,说明 WebView 配置正确。</p>
            </body>
            </html>
        """.trimIndent()
        webview.loadDataWithBaseURL(null, html, "text/html", "utf-8", null)

3.  配置浏览器调试

  • Android 端进入到需要调试的界面
  • 浏览器打开chrome://inspect/#devices,点开Configure(配置)输入ip地址, 例如: http://192.160.0.0:4030/等一会就会出现你要调试的设备信息,点击inspect就可以像浏览器调试那样去调试了

更多推荐