📸
webview時の画像ダウンロード機能【React】
仕様
ネイティブ側と連携してwebview内のボタンを押下すると端末に画像が保存される機能の実装です。画像DL機能を実装する際、androidでは機能するもののiosとかで動作しなかったところがありました。下記のコードは直接関わりにないところは省いて記述しています。
コード
export const DLcomponent: FC () => {
const { dlState } = useGetState();
const DownloadAnchorLink = useRef<HTMLAnchorElement>(null);
const DownloadImage = useRef<HTMLImageElement>(null);
const setDownloadImage = () => {
if (!DownloadImage.current) return;
const canvas = document.createElement('canvas');
const setHrefAttr = () => {
if (!DownloadImage.current) return;
canvas.width = DownloadImage.current.clientWidth;
canvas.height = DownloadImage.current.clientHeight;
const context = canvas.getContext('2d');
if (!context) return;
context.drawImage(DownloadImage.current, 0, 0);
if (!DownloadAnchorLink.current) return;
DownloadAnchorLink.current.download = 'download.png';
DownloadAnchorLink.current.href = canvas.toDataURL('image/png');
};
setHrefAttr();
DownloadImage.current.addEventListener('load', () => {
setHrefAttr();
});
};
useEffect(() => {
setDownloadImage();
}, [DownloadImage.current]);
return (
<div>
<a ref={DownloadAnchorLink} href="" download="download.png">
保存
</a>
<img
crossOrigin="anonymous"
ref={DownloadImage}
src={dlState.image_url}
// emotionを使っています
css={css`
position: fixed;
top: 100vh;
left: 100vw;
`}
alt=""
/>
</div>
)
}
解説
最初にダウンロードさせる画像を画面外に隠すように表示しておいて、ボタンが押下された際に画像と同じサイズのcanvasにコピーします。
その後、canvasをbase64形式に変換しdownload属性が付与されたaタグのhrefに挿入し、そのリンクをもとにダウンロードが実行されます。あとはネイティブ側がダウンロードのイベントを監視して処理するかたちです。
ダウンロードする画像はドメインが違うため、一度base64形式にしないとダウンロードしてくれないようです。またios14では正常に動いたものの、ios13でloadイベントが発火されなかったため2回記述しています。osのバージョン分岐を作った方が良いのかもしれないですが、今ここではしていません。
Discussion