WWDC 2020 Web Developer 向け情報

Web Developer 向けの WWDC 情報です。個人的には Safari Web Extension が追加されて、Safari を使ってる方にも自分の Web Extension が提供できるようになったのが一番嬉しかったです。
なんというかやっぱり色んなベンダーを超えたブラウザで同じような体験が提供できるのがウェブテクノロジーの強みなので、よかった。

# WWDC for Web Developer

ざっくりまとめ

1. Safari (WebKit) がアップデート
2. iOS のデフォルトブラウザを Safari 以外に変更可能に
3. App Clip が登場、ウェブページでもサポート
4. Safari Web Extension が登場
5. WKWebView のアップデート
6. (今回は省略) Sign in with Apple の強化
7. (今回は省略) Touch ID / Face ID の対応
8. (今回は省略) Web Inspector の強化

# Web デベロッパのための新機能

▶︎ [https://developer.apple.com/videos/play/wwdc2020/10663/](https://developer.apple.com/videos/play/wwdc2020/10663/)

- 新しいバージョンの Safari 14 について
    - パフォーマンスが向上(ページ読み込み、JavaScript の実行、その他もろもろ）
- Web Kit
    - Safari 13.1 の新機能について
        - Web Animations API
            - CSS アニメーション・トランジションを JavaScript でコントロールできる API
                - もう HTML 要素のプロパティを操作しなくてもいいという話
            - クリック起点でアニメーションを行う

            ```javascript
            // Web Animations API Code Example

            let needle = document.getElementById("needle");
            let logo = document.getElementById("logo");
            logo.addEventListener("click", () => {
                needle.animate({
                    transform: [
                        "rotateX(35deg) rotateZ(13deg)", 
                        "rotateX(35deg) rotateZ(733deg)",
                    ],
                    easing: ["ease-out"],
                }, 800);
            });
            ```

            - Web Inspector Graphics タブにアニメーションの解析ができるようになった。
            - [Web Animations in Safari 13.1 | WebKit](https://webkit.org/blog/10266/web-animations-in-safari-13-1/)
        - ResizeObserver
            - なんらかの要素のサイズが変更された時を検知する API
            - ウィンドウのリサイズ、HTML 要素のサイズが変更されたことを検知できる

            ```javascript
            // Resize Observer Example

            let formatPanelObserver = new ResizeObserver((entries) => {
                entries.forEach((entry) => {
                    let container = entry.target;
                    container.classList.toggle("small", entry.contentRect.width < 175);
               }
            });

            formatPanelObserver.observe(document.getElementById("format-panel"));
            ```

            - [ResizeObserver in WebKit | WebKit](https://webkit.org/blog/9997/resizeobserver-in-webkit/)
        - Async Clipboard API
            - コピーペーストできるボタンが作れるように

            ```javascript
            // Programmatic copy
            copyButtonElement.addEventListener("click", (event) => {
                navigator.clipboard.writeText("Plain text to copy.").then(() => {
                   // Successful copy
                }, () => {
                   // Copy failed
                });
            });

            // Programmatic paste
            pasteButtonElement.addEventListener("click", (event) => {
                navigator.clipboard.readText().then((clipText) => {
                    document.querySelector(".editor").innerText += clipText);
                });
            });
            ```

            - https かつ、ユーザーのインタラクション起因でないと使えない（セキュリティとのトレードオフ）
            - [Async Clipboard API | WebKit](https://webkit.org/blog/10855/async-clipboard-api/)
        - Event Target Constructor
            - ライブラリの作者向け。DOM 以外のオブジェクトにもカスタムイベントをディスパッチできるようになる
        - Web Component
            - CSS Shadow Parts
        - HTML enterkeyHint attributed
            - バーチャルキーボードのエンターキーの名前を設定できるようになる
            ![スクリーンショット 2020-07-07 16.43.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5542/3ba7d40c-c41a-eb99-8de2-1ada6557a924.png)

        - Web Authentication API
            - Touch ID と Face ID の認証に対応
- CSS の改良
    - System Font Family のサポート font-family: ui-sans などの追加
    - line-break: anywhere の追加
    - :is() 擬似セレクタの追加 (Safari 14)
    - :where() 擬似セレクタの追加 (Safari 14)
- メディア
    - webP 画像のサポート (Safari 14)

    ```html
    <picture>
      <source srcset="example.webp" type="image/webp">
      <img src="example.jpg" alt="Example Image">
    </picture>

    Accept: image/webp,image/png,image/svg+xml,image/*;…
    ```

    - Safari 13.4 から、img に width height を追加しておけば、その分ちゃんと画像サイズ分を確保してくれるようになる
    - EXIF 画像メタデータから画像の向きを取れる `image-orientation: from-image; or none;`
    - HDR ディスプレイの対応

    ```css
    <style>
    @media only screen (dynamic-range: high) {
        /* HDR-only CSS rules */
    }
    </style>

    <script>
    if (window.matchMedia("dynamic-range: high")) {
        // HDR-specific JavaScript
    }
    </script>
    ```

    - AirPlay サポート (Remote Playback API)

    ```html
    <video id="videoElement" src="https://site.example/video.mp4"></video>
    <button id="deviceButton">Send video to a remote device</button>

    <script>
        let videoElement = document.getElementById("videoElement");
        let deviceButton = document.getElementById("deviceButton");
        deviceButton.addEventListener("click", (event) => {
            videoElement.remote.prompt().then(updateRemotePlaybackState);
        });
    </script>
    ```

    - Picture in Picture API

    ```html
    <video id="videoElement" src="https://site.example/video.mp4"></video>
    <button id="pipButton">Enter picture-in-picture mode</button>

    <script>
        let videoElement = document.getElementById("videoElement");
        let pipButton = document.getElementById("pipButton");
        pipButton.addEventListener("click", (event) => {
            videoElement.requestPictureInPicture().then(handlePictureInPicture);
        });
    </script>
    ```

    - HLS で時間指定メタデータがサポート
    - 字幕とキャプションのための機能強化
- JavaScript
    - BigInt のサポート
        - JSON.stringifty には非対応
    - Nullish Coalescing (Null合体演算子)

    ```javascript
    class Person {
        constructor(firstName, lastName, age) {
            this.firstName = firstName ?? "Unknown";
            this.lastName = lastName ?? "Unknown";
            this.age = age ?? NaN;
       }
    }

    console.log(new Person());  
    // { firstName: "Unknown", lastName: "Unknown", age: NaN }

    console.log(new Person(false, false, true));
    // { firstName: false, lastName: false, age: true }

    console.log(new Person("John", "", 0));  
    // { firstName: "John", lastName: "", age: 0 }

    console.log(new Person("John", "Appleseed", 42));  
    // { firstName: "John", lastName: "Appleseed", age: 42 }
    ```

    - Optional Chaining

    ```javascript
    console.log(person?.name.firstName);
    ```

    - 論理演算子

    ```javascript
    a &&= b // and assignment operator
    a ||= b // or assignment operator
    a ??= b // nullish assignment operator

    // Nullish coalescing approach
    element.innerHTML = element.innerHTML ?? "Hello World!"

    // Logical assignment operator
    element.innerHTML ??= "Hello World!"
    ```

    - パブリッククラスフィールド

    ```javascript
    class Person {
        firstName = "";
        lastName = "";
        age = NaN;
        children = [];

        constructor(firstName, lastName, age) {
            this.firstName = firstName ?? "Unknown";
            this.lastName = lastName ?? "Unknown";
            this.age = age ?? NaN;
        }
    }
    ```

    - String replaceAll
        - 正規表現使わなくなくてよくなった

    ```javascript
    "Hello world, Hello baby".replaceAll("Hello", "Good night")
    > Good night world, Good night baby
    ```

- プラットフォームとの機能
    - AR Quick Look 表示に、広告バナーを表示することがでいるようになる
    - Apple Pay のボタン画像の種類が追加され、請求の詳細とかを表示できるようになった
    - AppClip
        - アプリをインストールすることなくユーザーにアプリ体験を提供することができる機能

        ![スクリーンショット 2020-07-08 9.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5542/2c084790-d310-c997-79c3-3ad2c0d766c3.png)

        ![スクリーンショット 2020-07-08 9.42.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5542/5f62105e-e99c-ee80-3766-8e52f4880570.png)

        - ウェブサイトに入った時にメタデータを定義しておくと、それを知らせることができる

        ```html
        <meta name="apple-itunes-app"
              content="app-id=myAppStoreID,
                       app-clip-bundle-id=clipBundleID,
                       affiliate-data=myAffiliateData,
                       app-argument=myURL">
        ```

        - Instant App は使われてるところ見たことなかったけどこれは一定使われそう

# WKWebView の強化のご紹介

▶︎ [https://developer.apple.com/videos/play/wwdc2020/10188/](https://developer.apple.com/videos/play/wwdc2020/10188/)

- WKWebView が例えば  Blink / Gecko になるとかそういうのではない
    - WebView は引き続き WKWebView (WebKit) が使われると思われる
    - [iPhoneではあらゆるWEBブラウザのエンジンがSafariと同じ? - いまさら聞けないiPhoneのなぜ](https://news.mynavi.jp/article/20190331-iphone_why/)
- WKWebView のデバッグが今までやりにくかったことがやりやすくなる
    - JavaScript のサンドボックス機能がついて (WKContentWorld) 、コンテンツ側のバグなのかどうなのか評価しやすくなった
    - CallAsyncJavascript API が導入されて非同期でネイティブアプリとメッセージングできるようになった
- インテリジェント・トラッキング・プリベンション (ITP) を WebView にも追加
    - Facebook, Google はサードパーティクッキーによる「ユーザーが何のサイトを見ているか」を追跡監視している（[クロスサイト・トラッキング](https://iphone-mania.jp/news-183876/)）
        - 主に広告、マーケティングに使用
    - WKWebView にも追加された（13.4）
    - ファーストパーティクッキーの保存期間が 24 時間以内となる
    - Google Chrome も 2022 年にはサードパーティーの Cookie を完全にブロック可能になる
- その他
    - 画面全体の pageZoom プロパティが追加された
    - 画面全体のキャプチャ機能が追加された
    - 画面全体の文字列検索機能が追加された
    - Web アーカイブの強化

# Safari Web Extensions の導入

▶︎ [https://developer.apple.com/videos/play/wwdc2020/10665/](https://developer.apple.com/videos/play/wwdc2020/10665/)

Chrome や Firefox 、Edge とかで使える拡張機能をポーティングできるようになった。

Firefox とか Opera もサポートされている Web 標準である [extension API](https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions) を実装したという感じ。

今まで Safari に拡張機能を入れる場合は Xcode + Swift で開発してた感じです。

[Safari Technology Preview](https://developer.apple.com/safari/technology-preview/release-notes/) をインストールして、[Xcode Beta](https://developer.apple.com/download/) を使って導入テストできます。

### Web Extension Safari ポーティング用の Commandline Tools が導入された

こいつがまだ私の環境だとなんかアレだった（隠語）

```terminal
% xcrun safari-web-extension-converter {path}
```

### Xcode から実行してインストール

Xcode Beta を使用して実行。Safari 14 の Develop タブで、Allow Unsigned Extensions をオンにしておく。

1. xcode のプロジェクト作成で Safari Extension App を選択
2. Type: Safari Web Extension を選択 (Safari App Extension ではない)
3. Resources の中身を置き換えて、ビルドする。
4. Safari の Extensions タブに拡張機能が追加される
5. URL バーの左に拡張機能がインストールされ、実行できる（んじゃないかな〜）

### その他

- moz/Chrome 拡張機能をハードコードしている場合 Safari では動かないので、スキームを browser.runtime と標準の API を使用するようにしなければならない
- 通知系 API はサポートされていない
- ネイティブメッセージング API を使ってネイティブアプリと通信することができたりする

```javascript
browser.runtime.sendNativeMessage // ネイティブにメッセージを送る
browser.runtime.connectNative // ネイティブと接続する
```

```swift
SFSafariExtensionManager.getstateOfSafariExtension // 拡張機能の状態を知る
SFSafariApplication.dispatchMessage // 拡張機能にメッセージを送る
```

- 配布はどうやるのかまだ言及されてない気もするけどいまのところの雰囲気だと [App Store からの配布](https://apps.apple.com/jp/story/id1456414021)になるのかな
    - Chrome Extension みたいに審査する感じですね