こんにちは。株式会社ZOZOでAndroidエンジニアをしております@zzt-osamuhanzawaです。ZOZO Advent Calendar 2022の17日目の担当をさせていただきます。
本記事ではAndroidのWebViewでのWebGLで描画されたコンテンツの画面キャプチャをする際の課題とどう解決したかのお話の紹介をしたいと思います。
はじめに
まず、このWebViewの画面キャプチャというユースケース自体あまりないかもしれませんので軽くそこらへんの話をしたいと思います。現在、弊社ではZOZOFITというフィットネスアプリを米国向けに展開しております。少し前にZOZOSUITを使って体の部位を計測するサービスがありましたが、その技術をさらに応用し、ZOZOSUIT2という計測用のハードを着用し、より身体部位の詳細な計測ができるようになりました。その新しいZOZOSUITとZOZOZFITアプリと併せて使い、ボディマネジメントを実現するといったサービスです。そして、このZOZOFITでは計測を行った身体のデータを以下のような3Dメッシュで表示させてます。
この3Dメッシュはアプリ内部でWebGLを使って表示させています。このWebGLで表示させている3Dデータの画面をキャプチャし、外部へシェアしたいというユースケースが発生しました。
課題
Androidで画面のキャプチャを処理すると以下のようなコードになるかと思います。
val bmp = Bitmap.createBitmap(webView.width, webView.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)
webView.draw(canvas)
contaner
がWebGLで3Dメッシュを表示したWebViewのViewであり、通常であればこの処理でViewのキャプチャができるはずです。ただ、このままだとBitmapに肝心の3Dメッシュが入っていないという状態になりました。ちなみにiOSでは何も工夫なしにキャプチャができたとのことなのでAndroidのWebView特有の問題かと思っております。
どうしたか
WebGL(メッシュビューワー)の修正
結局、どうしたかというとアプリ内部で3Dメッシュを生成しているJavaScriptで実装されているビューワーの修正と一部WebViewの修正を行いました。
// 取得したイメージを表示するためのimg要素
let captureImg = document.createElement('img');
// containerは 下記 renderer に重ね合わせたHTML要素で、上記img要素を追加しておく
container.appendChild(captureImg);
// renderer は three.js の THREE.WebGLRenderer
renderer.domElement.toBlob(function(blob) {
// 要素をBlobデータとして取得し、URL文字列にする
let imgUrl = URL.createObjectURL(blob);
captureImg.onload = function() {
// URLオブジェクトの開放
URL.revokeObjectURL(imgUrl);
}
captureImg.onerror = function() {
URL.revokeObjectURL(imgUrl);
}
// 画像の読み込み
captureImg.src = imgUrl;
// rendererを非表示、img要素を表示に切り替える
renderer.domElement.style.visibility = "hidden";
captureImg.style.visibility = "visible";
});
上記が3Dメッシュを表示させているビューワーの一部に追加したコードとなっております。やっていることは
- DOM elementをJavaScriptでキャプチャ
- blob情報にしてimgタグに描画
して画面表示をさせています。
アプリ側の修正
Android WebViewでビューワー側の上記に挙げた関数を呼び出す必要があるためアプリ側も修正します。
evaluateJavascript
を実行し、先ほどのJSを呼び出します。そして2秒ぐらいまったあと、
webView.draw(canvas)
を実行することでWebGLの内容がキャプチャできます。
このようにすることでAndroid WebViewでのWebGLで描画されたコンテンツをキャプチャすることができるようになりました。
まとめ
WebViewでWebGLコンテンツのキャプチャというユースケースはほぼほぼないと思います。が、ネット上にもこの際の問題に関しての情報はなかったため本記事として上げさせてもらいました。何かの参考になれば嬉しいです。