iOS/Android共通で使用しているHTMLがAndroidアプリのWebViewで意図通りに表示されなかったときの試行錯誤の記録。
WebViewで表示するHTMLはCSSでzoomなどもしておらず、widthも固定していないレスポンシブなページ。iOSアプリでは意図通りWebViewの幅いっぱいにHTMLが表示されていた。しかし、AndroidアプリのWebViewでは半分くらいのサイズで表示され、さらに謎の空白も加わり、HTMLと空白が横に並んでいるようなおかしな表示になっていた。(文章だと伝わりづらい)
先に結論を言うと、原因はHTML側でviewportが設定されておらず、WebViewでスケーリングができていなかったよう。また、WebViewのsettingsにもちょっとはまったのでメモ。
WebViewのSettings
private fun Init() {
val settings = this.settings
settings.useWideViewPort = true
settings.loadWithOverviewMode = true
}
useWideViewPortはHTMLのviewport
またはwide viewportを有効にする設定。指定がなければ端末に依存したサイズに調整される。(詳しい挙動はリンク先を参照)
これを有効にしていると、HTMLのwidthがWebViewより小さい場合、勝手にwidthが拡大されて不足している分の余計な空白ができてしまったりする。
また、loadWithOverviewModeを有効するとHTMLのwidthがWebViewより大きい時に全体を表示するようよしなに調整される。これを有効にしているとviewport
のスケールによる拡大がきかなくなるので注意。
Android側だけでの対処
iOSアプリでも使っているのでHTML側にあまり手を加えたくはない。
そこでとりあえず、useWideViewPort
をfalse
にすると余計な空白は消えた。だが、まだHTMLは小さいまま。
そこで、端末のDensity(1ピクセルに対する1dipの倍率)を取得し、それに合わせてスケーリングを行ってみた。
private fun Init() {
// setInitialScaleを使う場合はこの2つをfalseにしないといけない(referenceにも書いてある)
val settings = this.settings
settings.useWideViewPort = false
settings.loadWithOverviewMode = false
// Densityに合わせてスケーリング
var scale = this.context.resources.displayMetrics.density * 100
this.setInitialScale(scale)
}
これでひとまず意図通りの表示にはなった。
HTML側の対処
さらに調べたところ、そもそもWebView側でスケーリングするのはあまり推奨されていない様子。
setDefaultZoomでzoom densityの指定もできたりするのだが、API level 19以上ではdeprecatedになっている。
Migrating to WebView in Android 4.4でも言及されているが、基本的にはHTMLでviewport
を指定するのが望ましい。
というわけで、当然といえば当然だが深遠な理由がなければHTMLのviewport
でinitial-scale
を指定するのがよさそう。
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
</head>
</html>
その場合、useWideViewPort
とloadWithOverviewMode
の指定は不要だった。zoomとかscaleとかそれぞれの違いが理解しきれずもう少し調べたい所だけど、今回はここまで。