1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

最近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 +"');");
          });
        }
}

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?