Web Share API Level2を使ってアプリ連携無しでTwitterに画像を投稿する

ブラウザから直接ネイティブにインストールされているアプリの共有機能（下の画像参照）を呼び出す、[Web Share API](https://w3c.github.io/web-share/)という機能があります。

<img width=200px src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142530/7f30ae22-38b0-426f-ce24-2a78d00c958f.png>


メッセージやURLなどのテキストの共有は、Web Share API Level1としてすでにiOS SafariとAndroid Chromeで利用することができます。

更に、Android Chrome75以降（2019/10/24現在最新版は78）ではファイルなどの共有も可能な[Web Share API Level 2](https://w3c.github.io/web-share/level-2/)が使えるので今回はこれを使ってTwitterとのアプリ連携なしにTwitterに画像を投稿できる仕組みを作ってみました。

それがこちらです
[No Login Image Share](https://tohutohu.github.io/no-login-image-share/)
<img width=200px src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142530/1278fd0c-61d8-d7c0-aa6e-91aa7778c2d0.png>



好きな文字をテキストボックスに入れてShareボタンを押すと、ネイティブの共有モーダルが表示され、アプリを選択するとそこに作成した吹き出しの画像が共有されるはずです。
<img width=200px src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142530/e7cb33d6-a723-9e2d-2d09-56f6af5a767c.png>


実際にツイートしたものが↓です。
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">アプリ連携無しで画像がシェアできました！ <a href="https://t.co/xQuf4H9JQb">https://t.co/xQuf4H9JQb</a> <a href="https://t.co/fdxUoeM6Um">pic.twitter.com/fdxUoeM6Um</a></p>&mdash; とーふとふ (@to_hutohu) <a href="https://twitter.com/to_hutohu/status/1187250777510727680?ref_src=twsrc%5Etfw">October 24, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この記事ではソースコードの中から重要な部分をかいつまんで説明します。
実際のソースコードは[tohutohu/no-login-image-share](https://github.com/tohutohu/no-login-image-share/)から確認してください。

## DOMからFileを作成する
吹き出しを含めたシェアされる部分全体のDOMは以下のようになっています。
この内、`div#message`内に入力したメッセージが挿入されます。

```html
<div id="image-container">
  <div id="message-container">
    <div id="message"></div>
  </div>
</div>
```

[tsayen/dom-to-image](https://github.com/tsayen/dom-to-image)というライブラリを使って、DOMからpng形式のBlobを取得しFileクラスに変換します。

```javascript
const blob = await domtoimage.toBlob(document.getElementById('image-container'))
const image = new File([blob], 'tmp.png', {type: 'image/png'})
```


## Fileを共有する
`navigator.share`にシェアしたいデータを渡すことで、シェアモーダルを表示させることができます。
また、`navigator.canShare`にシェアしたいデータを渡すことで、そのデータをシェアすることができるかどうかを知ることができます。

詳細は[Web Share API - Level 2](https://w3c.github.io/web-share/level-2/)を確認してください。


```javascript
navigator.share({
  text: 'アプリ連携無しで画像がシェアできました！',
  url: 'https://tohutohu.github.io/no-login-image-share/',
  files: [image]
}).then(() => {
  console.log('Share was successful.')
}).catch((error) => {
  console.log('Sharing failed', error)
})
```

たったこれだけで、画像のシェア機能を実装することが可能です。

## その他の画像投稿方法との比較

### 1. アプリ連携を行い、API経由で投稿する
Twitterとのアプリ連携を行い、アクセストークンを取得後サーバー側から画像を投稿する方法です。

- メリット
    - プラットフォームを選ばない
- デメリット
    - サーバーサイドの実装が必要
    - トークンなどの取り扱いに気をつけなければならない
    - Twitterと連携したらTwitterにしか投稿できない


### 2. 別のアカウントから画像を投稿した画像のURLを添付する
予め画像投稿用アカウントでトークンを取得しそこに画像つきツイートを行ったあと、そのツイートから画像URLを取得してそのURLをTwitter Intentなどでシェアする方法です。
極一部のアプリなどで実装されているのを見たことがあります。

- メリット
    - プラットフォームを選ばない
- デメリット
    - サーバーサイドの実装が必要
    - 実装が非常に煩雑
    - 規約的にOKなのか不明瞭

### 3. OGPで画像っぽく表示する
結果ごとに一意なURLを生成し、それに対応するOGPイメージを生成することで画像っぽく表示させる方法です。

- メリット
    - プラットフォームを選ばない
    - リンクをクリックすることで結果ごとのより詳しい内容を確認するのような導線を敷くことができる
- デメリット
    - サーバーサイドの実装が必要
    - シェア先がOGPの表示に対応している必要がある


## まとめ
Web Share APIが様々なプラットフォームで利用できるようになればWebアプリの画像のシェアという観点ではアプリ連携が必要なくなるのではないかと思っています。
〇〇メーカーのようなUGCをシェアしてもらうタイプのWebアプリではかなりシェアまでのハードルが下がってシェアされやすくなりそう。

CanvasをStreamとして取得しそれを動画ファイルとして取得できれば、ゲームのリプレイなども直接SNSにシェアできたりするんでしょうか……？

## 参考ページ
- [Web Share API - Level 1](https://w3c.github.io/web-share/)
- [Web Share API - Level 2](https://w3c.github.io/web-share/level-2/)
- [Chrome75に実装された「Web Share API Level 2」を使ってみた – One IT Thing](https://one-it-thing.com/1674/)