LoginSignup
0
1

More than 1 year has passed since last update.

FlutterのDartからWebViewへ画像を送るにはData URIを使う

Last updated at Posted at 2021-06-22

最近FlutterをはじめましたがWidgetの挙動がよくわからず困ってます。仕方ないので邪道だけどFlutterアプリにWebViewを貼り、Dartプログラムで生成したHtmlを表示するようにしてしのぎました。そのときに使ったDart側からWebViewに画像を渡す方法を紹介します。

DartからWebViewへのテキスト転送

WebViewクラスにセットされるWebViewControllerのevaluateJavascriptを使うと、WebViewで表示しているhtmlテキスト中のJavascript関数を実行することができます。evaluateJavascriptは送った文字列をそのまま解釈して実行するので、パラメータ込みの文字列を送ればテキスト情報をWebView側に送ることができます。

たとえばWebView側に次のような関数がセットされていたとします。idで指定されたimgタグのsrcを書き換えるものです。

<script>
function putimg( id, url ){
    document.getElementById( id ).src = url;
}
</script>

これをDartから次のようにコールしてやると、WebView上のid:img00の画像を書き換えることができます。

 webviewcontroller.evaluateJavascript("putimg('img00','http://example.com/icon.jpg');");

Data URI

HTTPサーバーにある画像ならこれでOKです。Dart内部データとか外部サーバーでもAPI経由でないと取得できないような場合は、Dartのプログラムで取得したバイナリーデータをData URIに変換すれば送ることができます。Data URIとは詳しくはWikiなど見て欲しいのですが、バイナリーデータをBase64でテキスト化して、"data:image/jpeg;base64," などのヘッダをつける処理です。FlutterにはUri.dataFromBytesというメソッドあります。
 WebViewにDartで作成したHtmlを送るときもData URIに変換する必要がありますが、テキストをData URIに変換するには、Uri.dataFromString というメソッドを使います。メソッドを間違えるとVSCodeごと落ちたりするのでご注意ください。

    var response = await http.get(uri);
    var dataurl = Uri.dataFromBytes(response.bodyBytes, mimeType: 'image/jpeg');
    webviewcontroller.evaluateJavascript("putimg('img00','"+ dataurl +"');");

WebView表示と画像取得を並行して行う

Dartで表示するHtmlを生成するときに、最初からData URI形式で画像を埋めこんでおくことも可能です。ただし、画像の取得に時間がかかったり、しかもそれが複数あるような場合は、全部の画像の取得が終わってからようやくHtmlが転送されるので画面が真っ白な状態が長く続きます。まずHtmlを表示させておいて、後から順に画像にアクセスし、取得できたタイミングでevaluateJavascriptで漸次WebViewに画像を転送するようにすると、とりあえず画面に何かでるまでの時間を短くできます。

以下のようなJSON形式の画像のリストが itemlistに入っているとします。
[
{id:'a01', src:'http://example.com/a01.jpg'},
{id:'a02', src:'http://example.com/a02.jpg'},
]
この画像一覧をWebViewに表示するには、WebViewのonWebViewCreated:パラメータで指定するコールバックの中で以下のように処理します。

onWebViewCreated: (WebViewController webViewController) async {
        // まずHtmlを作成
        String html = "<html><head><script>function putimg(id,src){document.getElementById(id).src=src;}</script></head><body>";
        for( var item in itemlist){
          html = html + item['id'] +" <img id='"+item['id']+"' /> <br/>\n";
        }
        html = html + "</body></html>";
        // HtmlをData URIに変換してサーバー経由しないで取得できるようにする
        final fileurl = Uri.dataFromString(
            html,
            mimeType: 'text/html',
            encoding: Encoding.getByName('utf-8')
        ).toString();
        // それをWebViewで表示
        webviewcontroller.loadUrl( fileurl );

        // 一覧から画像をダウンロードし、Data URIでWebViewに転送
        for( var item in itemlist){
          http.get(Uri.parse(item['src'])).then((response) { 
            var dataurl = Uri.dataFromBytes(response.bodyBytes, mimeType: 'image/jpeg').toString();
            webviewcontroller.evaluateJavascript("putimg('"+ item['id'] +"','"+ dataurl +"');");
          });
        }
}

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1