Flutter + WebView
最近FlutterのWebViewを触るようなことをやっている。 WebViewのプラグインにはいくつか実装があるが、大きく分けるとするとPlatformViewを使わないか使うかによって分けれる。
PlatformView を使わないか使うか
PlatformViewを使わないとネイティブのViewをFlutterWidgetの上に被せて表示する実装になるので、FlutterのWidget(SnackBarなど)をWebViewの上にかぶせるなどができない。また大きさの変更もContainerなどのWidgetを利用して変更できない。launchするときにrectを指定すれば大きさの変更はできる。さらに1画面に1個のWebViewしか利用できない。このように制限はあるが、PlatformViewを経由しないため、それなりに動く。(キーボードが出てきてもViewの大きさが変わらない問題(仕様?)はある)
PlatformViewを使うとFlutterのWidgetとして扱えるので、WebViewの上にSnackBarを出したりWebViewの大きさをContainerに囲んで変更したり複数のWebViewを表示したり制限なく使える。しかし、後述するがAndroidのキーボードまわりでバグにぶちあたる。
PlatformView を使う
今回の要件的には上記のような制限を受けたくないので、PlatformViewを利用する選択をした。 PlatformViewを利用するプラグインは探せばたぶん無限にあるけど、この2択っぽい。
webview_flutterに関しては、公式のプラグインで安心感がある。利用者も多く大体の問題はイシューになっている。ただあまり実装は進んでおらず、onPageStartedなどのコールバックもほとんど実装されていないようだった。(プルリクはあるが… #1389, #1788)
flutter_inappbrowser のほうはCookieManagerやコールバックもある。ただ、リリースはされてないが2.0.0でAPIが大きく変わりそう。また、大きな実装だなという印象で、InAppWebView.javaの実装を見るとJSがめっちゃ書かれていて、それって我々に必要なのか?みたいな気持ちになる。
今回は、公式のwebview_flutterで確認することにする。
webview_flutterを使ってぶちあたった壁
webview_flutterを利用する選択をしたはいいが、触っていたところAndroidのキーボードまわりで結構バグっていることに気づいた。全部イシューになっているけど、WebView起因というよりはPlatformViewが原因なのが多い気がしていて、シュッとは直せなさそうだと思った。 自分が遭遇しただけでも以下がある。
webview_flutter Keyboard persists after tapping outside text field · Issue #36478 · flutter/flutter · GitHub
TextFieldをタップしてキーボードを表示したあとTextField以外をタップしてもキーボードが出っぱなし。
WebView’s text selection dialog is not responding to touch events · Issue #24585 · flutter/flutter · GitHub
TextFieldをタップしてもコピーなどの項目が表示されない。 Flutter 1.9以降で動かないようになったらしく、なおしてるところとのこと。 https://github.com/flutter/flutter/issues/24585#issuecomment-513950478
WebView’s text selection handles are not showing on Android · Issue #24584 · flutter/flutter · GitHub
TextFieldだけではなくウェブページのテキストをコピペしようと長押ししても動かない。 そもそもLongTapが無効化されている。 https://github.com/flutter/plugins/blob/f31d16a6ca0c4bd6849cff925a00b6823973696b/packages/webview_flutter/lib/src/webview_android.dart#L31
webview_flutter Keyboard suggestions can be lost · Issue #37989 · flutter/flutter · GitHub
日本語を打つと強制的に確定されてしまい、サジェストが出ずキーボードが英字に変わってしまう。 Chromiumが原因かも?と言っている。ネイティブアプリでWebViewを使ってみてもならないので違うような気もするけどよくわからず。
サイズ変更が原因らしいので、サイズを変更しなければ起きない。
FlutterがつくるAndroidアプリは、キーボードを出すとViewの大きさを変える設定になっているので、それをやめればよい。AndroidManifest.xmlのandroid:windowSoftInputMode="adjustSize"
をandroid:windowSoftInputMode="adjustPan"
に変える。
ただ、この設定をするとFlutterで作った画面すべてに影響し(つまりWebViewを利用していない画面でキーボードが出てもViewのサイズは変更されない)、Viewの大きさが変わらないとキーボードを出した状態で一番下までスクロールできなくなるため、あまり現実的な手段ではないと思う。
この問題は、flutter_inappbrowserだと実装が違いそうなので、動かして確認したところそもそも文字がなにも入力できなかったので確認できなかった………。
webview_flutter Soft keyboard not appearing on Q · Issue #38375 · flutter/flutter · GitHub
Android Qでキーボードが出なかった。beta channelだとなおっているのを確認した。
Text input on Q platform views results in log spam · Issue #40716 · flutter/flutter · GitHub
#38375をなおした影響でAndroid Qでログが出まくる。 Q未満は出ないので、Q未満でデバッグすることにした。
autofillが効かない?
動かないか確認できていないけど、ログが出てる。
W/cr_AwAutofillManager( 2953): WebView autofill is disabled because WebView isn't created with activity context.
ただPlatformViewは、VirtualDisplayを使うことで実現していてそのためには android.app.Presentation
を使う必要があるっぽくActivityのContextを利用するのは無理なのではと自己完結した。
まとめ
FlutterでWebViewを使いたいが、Androidのキーボードまわりで困っている。数カ月後にはなおってるかもしれないし、なおってないかもしれない。 せっかくFlutterを利用するのであれば、ネイティブでAndroid/iOSを書きたくないという思いがあるが、ネイティブで書くのがよいという決断をするかもしれない。
ちなみにiOSでは結構まともに動いていて「AndroidとFlutterは同じ会社が作ってるのでは…?」と思うなどした(大変そう)