无尽码路

清凉夏日,您升官了吗?
Android的webview将容器改尺寸传给html以便html适配
at 2023-03-31 21:07:25, by 鹏城奋青

载有高德地图的html中,容器或其父级必须给定具体尺寸,否则在webview中嵌入时不会有任何显示。

因此我们在Android View确定尺寸时,调用外部js将尺寸传过去,实践发现得先转为dp值才正确。

@Composable
fun Map() {
    var progress by remember { mutableStateOf(0) }
    var lng by remember { mutableStateOf(0.0) }
    var lat by remember { mutableStateOf(0.0) }
    var done by remember { mutableStateOf(false) }
    var size by remember { mutableStateOf(IntSize.Zero) }
    Box(modifier = Modifier
        .fillMaxWidth()
        .weight(1f)) {
        AndroidView(
            factory = {
                WebView(it).apply {
                    wv = this
                    settings.javaScriptEnabled = true
                    settings.domStorageEnabled = true
                    settings.databaseEnabled = true
                    settings.blockNetworkImage = false
                    settings.blockNetworkLoads = false
                    settings.loadsImagesAutomatically = true
                    settings.allowUniversalAccessFromFileURLs = true
                    settings.allowFileAccessFromFileURLs = true
                    settings.allowFileAccess = true
                    settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                    webChromeClient = object : WebChromeClient() {
                        override fun onProgressChanged(view: WebView?, newProgress: Int) {
                            progress = newProgress
                        }
                    }
                    webViewClient = object: WebViewClient() {
                        override fun onPageFinished(view: WebView?, url: String?) {
                            super.onPageFinished(view, url)
                            done = true
                        }
                    }

                    class Bridge {
                        @JavascriptInterface
                        fun locationUpdate(lg: Double, lt: Double) {
                            lng = lg
                            lat = lt
                        }
                    }
                    addJavascriptInterface(Bridge(), "bridge")
                    loadUrl(
                        Chatty.getLocationChooseUrl(
                            longitude = locationData.longitude,
                            latitude = locationData.latitude
                        )
                    )
                }
            },
            modifier = Modifier
                .fillMaxSize()
                .onSizeChanged { size = it },
        ) {
            it.webChromeClient = object : WebChromeClient() {
                override fun onProgressChanged(view: WebView?, newProgress: Int) {
                    progress = newProgress
                }
            }
        }

        val density = LocalDensity.current
        LaunchedEffect(done, size) {
            if (done) {
                val w = with(density) { size.width.toDp().value.toInt() }
                val h = with(density) { size.height.toDp().value.toInt() }
                wv?.evaluateJavascript(
                    "onSizeChanged(${w},${h})",
                    null
                )
            }
        }
    }
}
<!DOCTYPE html>
<html lang="zh">
    <head>
        <meta charset="utf-8">
        <style>
            html, body, #container {
              margin: 0;
              background-color: gray;
              width: 100%;
              height: 100%;
            }
            
            #marker {
              position: fixed;
              width: 20px;
              height: 26px;
              z-index: 999;
              left: 50%;
              top: 50%;
              transform: translate(-10px, -26px);
            }
            
            #info {
              position: fixed;
              z-index: 1000;
              left: 50%;
              top: 50%;
              transform: translateY(30px);
            }
        </style>
    </head>
    <body id="body">
        <img id="marker" src="//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png"/>
        <div id="container"></div>
        <div id="info"></div>
        <script src="//webapi.amap.com/maps?v=2.0&key={{.key}}"></script>
        <script>
            const pos = new AMap.LngLat({{.longitude}},{{.latitude}});
            const map = new AMap.Map("container", {
                viewMode: '2D',
                center: pos,
                zoom: 15,
                keyboardEnable: false,
                jogEnable: false,
                pitchEnable: false,
                rotateEnable: false,
                animateEnable: false,
                keyboardEnable: false,
                doubleClickZoom: false,
                scrollWheel: false,
            });

            map.on('moveend', function () {
              try {
                const center = map.getCenter();
                window.bridge.locationUpdate(center.lng, center.lat);
              } catch (e) { }
            });
    
            function onSizeChanged(w,h) {
              // 必须这样设置才行,在android webview中将容器尺寸转为dp再调用这个函数
              const style = document.getElementById("body").style
              style.width = w+"px";
              style.height = h+"px";
            }
        </script>
    </body>
</html>