iPhone/iPadで動くWebBluetoothアプリをp5.jsで作る方向けのメモ

# サマリ📱
`iPhone`/`iPad`で`WebBluetooth`を使ったWebアプリを動かすには、[Bluefy](https://apps.apple.com/jp/app/bluefy-web-ble-browser/id1492822055)というアプリを使うと便利なのですが、`p5.js`で作ったwebアプリを動かすうえで、少しハマった部分があるので、メモを残します。

# 成果物
👇このような`toio`のリモコンwebアプリを[p5.toio](https://tetunori.github.io/p5.toio/)を使って作りました。
[Webアプリ現物](https://tetunori.github.io/p5toio-samples/remoteControl/)と [ソースコード](https://github.com/tetunori/p5toio-samples)
<img width="600" alt="landscape_dialog.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/c2c9640b-a0bb-0e01-51c7-3f52daf01348.jpeg">

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">iPhoneで <a href="https://twitter.com/hashtag/WebBluetooth?src=hash&amp;ref_src=twsrc%5Etfw">#WebBluetooth</a> を使ったWebappを実行できる無料アプリ <a href="https://twitter.com/hashtag/Bluefy?src=hash&amp;ref_src=twsrc%5Etfw">#Bluefy</a> を試したが、既存アセットをそのまま使えてとても良い。<br>試しに <a href="https://twitter.com/hashtag/p5toio?src=hash&amp;ref_src=twsrc%5Etfw">#p5toio</a> を使った <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> のラジコンアプリを作ってサクッと公開。アプリの審査も無いし、iPhoneでJSのBTアプリを配布する方法としては最速&amp;最も簡単なのでは？ <a href="https://t.co/ZlJ9ES8HtI">pic.twitter.com/ZlJ9ES8HtI</a></p>&mdash; Tetsunori NAKAYAMA | 中山 哲法 (@tetunori_lego) <a href="https://twitter.com/tetunori_lego/status/1523108885506142208?ref_src=twsrc%5Etfw">May 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# メモ
## Webアプリとして使うための準備
タッチするたびにスクロールしたり拡縮されないようにするために、`html header`に下記の`meta`タグと`script`を追加
```html
  <head>
    <!-- ... -->
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, viewport-fit=cover" />
    <meta name="apple-mobile-web-app-capable" content="yes">

    <script>
      window.addEventListener("touchmove", function (event) { event.preventDefault(); }, { passive: false });
    </script>
    <!-- ... -->
  </head>
```

## ノッチ部分が目立たないように
何もしないと、こんな感じで`Canvas`の外側の白背景が目立ってしまいます。
<img width="300" alt="before_notch.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/b844706d-fe2d-16f6-c466-ff2f0f1146d2.png">
`css`に、`background`を追記します。ここを黒にしておくとノッチ部分も目立たないです。
```css
html, body {
  margin: 0;
  padding: 0;
  background: black; /* ここに追加 */
}
```
<img width="300" alt="after_notch.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/24186f60-efd9-9f12-8ace-686d5d67db57.png">

## `Canvas`のサイズ
縦横サイズは`windowWidth`, `windowHeight`とし、画面の回転で`Canvas`のリサイズを実施するのがよいです。なお不具合なのか、たまに回転にリサイズがついてこないことがあります。
```javascript
function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

function setup() {
  createCanvas(windowWidth, windowHeight);
  // ...
}
```

## `mouseClicked`関数は、`Canvas`のコールバックとして設定(ここ一番大事)
`WebBluetooth`は接続を開始する際にユーザーアクションを要求しますが、いつものように`mouseClicked`をオーバーライドして記載する方法ではなぜか`Bluefy`アプリの接続処理が走りませんでした。以下のように、`Canvas`の`mouseClicked`コールバックとして設定することで動作することが確認できました。
```javascript
function setup() {
  const cvs = createCanvas(windowWidth, windowHeight);
  cvs.mouseClicked(connectCube);
  // ...
}

function connectCube() {
  P5tCube.connectNewP5tCube().then((cube) => {
    cube.turnLightOn('white');
  });
}
```

## 横向きだと、Bluetooth接続ダイアログが表示されない
`iPhone`などの幅が狭い機種で横向きにすると接続ダイアログが表示されず、ただBlurがかかっただけの画面になってしまいます。
<img width="600" alt="landscape_dialog.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/c6bb42b4-2432-66f0-b64e-e80f8faa3ff1.png">
※ `iPad`は縦横どっちでも大丈夫でした。

これを縦向きに回転するとダイアログが表示される
<img width="300" alt="portrait_dialog.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/0f3f74c2-5e49-0af4-1a36-f6dcfb1836e4.png">
ので、必要に応じてその旨をユーザーに通知したいです。より厳密に向きや画面サイズを取得することもできますが、`Canvas`の縦横サイズでざっくり判定するのもありかと思います。
```javascript
  if (width > height) {
    text(`接続ダイアログが表示されない場合は画面を縦向きにしてください。`, width / 2, 20);
  }
```
<img width="600" alt="landscape_dialog.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542654/f6196b4c-e259-5137-cf30-3faa94117d79.png">

上記に気を付けると、あとは通常の`p5.js`のコードで動作してくれます。それでは～。