ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
WKWebViewの強化のご紹介
WKWebViewは、豊富でインタラクティブなWebコンテンツをApp内で適切に提示する最善の手段です。まったく新しい機能を追加しながら、WebViewsまたはUIWebViewsを使用してAppを変換できる新しいAPIをご紹介します。JavaScriptの管理、レンダリングプロセスの微調整、Webコンテンツのエクスポートなどの優れた手段をご覧ください。
リソース
関連ビデオ
WWDC21
WWDC20
-
ダウンロード
こんにちは WWDCへようこそ “WKWebViewの強化のご紹介” こんにちは セッションへようこそ WebKitアーキテクチャチームの ブレイディ・アイドソンです 今日はWKWebView APIの新機能をご紹介します 我々はWebが大好きです WebKitのフレームワークが高速で応答性が高く かつ安全で効率的であるよう気をつけています Safariで それらを実現するためです ブラウザでのWeb探索に限らず あらゆる面で使われるWeb技術が好きです 我々のプラットフォームはWebコンテンツと ネイティブ体験を統合できます 主にアプリケーション内のブラウザが必要で 複雑なカスタマイズが不要なら SFSafariViewControllerは最良の選択です 基本的なブラウザを実装する際の懸念点に すべて対処します リーダーやコンテンツブロッカー 自動入力などを利用でき― コンピュータでブラウザを使えます アプリケーションに追加しロードしてください SafariViewControllerが使いやすく強力なのは WKWebViewの上に構築されているからです 高度な設定が必要な時や閲覧とは別の方法で Webコンテンツを使用する時も WKWebViewの上に直接 構築できます WKWebViewはWebコンテンツを 別のプロセスに分離し アプリケーションのコードとデータを自動的に Webプラットフォームの複雑性から守ります 悪意のある攻撃者から守りながら― Webコンテンツの実行を高速化するのです それゆえにSafariViewControllerは WKWebViewを使用します 我々が長年 他の選択肢よりも WKWebViewを推奨してきた理由でもあります 他の選択肢といえば― WebViewとUIWebViewは Webコンテンツを組み込むためのAPIでした それらも役立ちましたがWKWebViewに比べ 欠点があったのです そのため数年前から非推奨とし― いずれは廃止する予定です それらはWKWebViewと まったく異なるため WKWebView APIを同じように 機能させることは不可能でした そのため 時にはユーザーがやり方を再考したり 我々がWKWebViewに 新機能を追加する必要があります WKWebViewへの移行に苦労する開発者側の声に 我々は耳を傾け WKWebView APIは発展を続けているのです 発表以来 改良を重ねており 今後も進化し続けます それを踏まえiOS 14と macOS Big Surに搭載された― WKWebViewの新機能を紹介します 困難だった作業を はるかに簡単にする機能や 非推奨のWebViewから復活させた機能 そして最新の機能もあります カバーすべきことは多いです まずアプリケーションとWebコンテンツを 分離するAPIについて話します 次にJavaScriptでWebコンテンツと やり取りする方法の改善点と― Webコンテンツのレンダリングの微調整を 助けるAPIについて説明します ネイティブ側のWebコンテンツから より価値を得る方法と― 重要性を増している プライバシーの尊重についても触れましょう 新機能を紹介するために― 多くの方に なじみのある話をします あるアプリケーションの話です 背景から話しましょう 多くのソフトウェアエンジニアリング組織と 同様に SafariとWebKitチームにも 重要な社内ツールが多数あります その1つであるWebサイト “WebKittens”は 部署のネコの最新情報を チームメンバーに通知するツールです iPhoneよりも長い付き合いですが iOSが登場すると― あるメンバーがUIWebViewで WebKittensのアプリケーションを書きました また多くの ソフトウェアエンジニアリング組織と同様に 我々も社内ツール内で 多くの重複作業を行っています 部署の犬の情報を更新するWebサイト “Pups on Safari”もその1つ
WebKittensと同様に iPhoneアプリケーションは古いものです 重要なコンテンツを 1日に複数箇所 確認するのは大変だったため “Browser Pets”を作成しました 両サイトを統合し― サイト間のインタラクションを管理する 単一のフィードです 各アプリケーションが独自に発展したため WKWebViewを使い ゼロから作りました 最初の課題はアプリケーションのロジックを Webコンテンツから分離することです アプリケーションを開くと WebKittensのニュースフィードが表示され まずスクロールできないことに気づきました 指でページを動かせなかったのです WebKittensのスクロールは JavaScriptで大幅にカスタマイズされていました ブラウザのページなら問題ありませんが これはアプリケーションです 私が欲しいのはネコだけ WKWebView APIはJavaScriptを無効にできます WKPreferencesのjavaScriptEnabledを “false”に設定するのです 汎用のWebブラウザ作成時以外は リモートソースからのJavaScript を 無効にできるか確認しておくとよいでしょう WKWebViewでは問題になり得ます コンテンツとのインタラクションの多くが JavaScriptの評価によるものだからです そこで その設定を廃止し 新たなものを加えました
WKWebPagePreferencesの allowsContentJavaScript設定で WebコンテンツからのJavaScriptのみを 無効にできます インラインスクリプトや リモート参照されるJavaScriptファイル― JavaScriptのURLなどです しかしアプリケーションのJavaScriptは 機能し続けます WKWebpagePreferences APIは 最近 追加されたもので ナビゲーションごとに特定の動作を設定できます 新バージョンのpolicy delegateを使うと Webページを設定し iPad上でもモバイルデバイスとして 表示できるのです メインのニュースフィードを表示中に ContentJavaScriptも無効にできます
この変更でスクロールが可能になりました
次は投稿されたコメントを 閲覧できるか確認しましょう 投稿をタップすると― 次の問題が発生しました 長年アプリケーションを使ってきて このページの下半分は コメント欄だと知っていますが空白です コメントはJavaScriptで入力されることも 知っています それらのナビゲーションのJavaScriptは 無効にしていません そこでWeb Inspectorに頼ります アプリケーションの Webコンテンツの問題を調べる最適な方法です 数年前からアプリケーションのWebViewや JavaScriptのコンテキストにアタッチできます これができるのは すばらしいことだと 思い出してください Web Inspectorの改善点についての セッションもお勧めします “What's New in Web Inspector”です バグの話に戻ります JavaScriptのコンソールにエラーが出ています
詳しく見てみましょう
WebページはcommentDetailsを 関数だと想定していますが そうではありません JavaScriptは この関数を宣言していますが Web Inspectorはnullだと示しています
アプリケーションのSymbolを検索し このコードを見つけました アプリケーションのコードにも Webページに挿入された commentDetailsというSymbolがあります JavaScriptを評価する際は 無関係な変数で関数を上書きします WKWebViewでの作業時は このようなコンフリクトが常に懸念されます アプリケーションとWebコンテンツが互いに 偶然 コンフリクトしてしまうのです 悪質なWebコンテンツは 動作を変更したり情報を盗んだりして 意図的にアプリケーションと コンフリクトすることもあります アプリケーションとWebページのJavaScriptが 同じ領域で実行されるからです これを解決するには アプリケーションのJavaScriptとは別に JavaScriptを実行する 独自のグローバルオブジェクトが必要です そこで使うのがWKContentWorld JavaScriptを実行するための 独立したSandboxです 同じページのコンテンツに 分離された独自のWindowオブジェクトが あるようなものです Webコンテンツ自体を表すページ領域と アプリケーションのJavaScriptのホームを表す クライアント領域があります クライアント領域で実行されるJavaScriptは ページに内蔵されたDOM APIを呼び出したり DOM自体を変更できます しかしページのJavaScriptが設定した状況を 見るのは不可能です ページのJavaScriptも こちら側を見られません
問題を解決するために すべてのevaluateJavaScriptの呼び出しに デフォルトのクライアント領域を使用します
するとアプリケーションのJavaScriptと ページのJavaScriptがコンフリクトせず コメントが表示されました WKContentWorldを使う方法をお見せしました WKScriptMessageHandlerを 特定のコンテンツ領域に挿入し それらを分けることも可能です これでアプリケーションとWebコンテンツを お互いから守れます Browser Pets開発の次の段階では より多くのJavaScriptを使用しました それを管理するために― アプリケーションのJavaScriptを管理する 新しい方法を採用しました WebKittensは静的なので 複合ニュースフィードの出発点として 最適でした 見た目を整え Pups on Safariと統合するために いくつかのJavaScriptを挿入しました
Pups on Safariには 投稿を取得するためのJavaScript APIがあり それを使って複合ニュースフィードを 稼働させたのです そこで試練にぶつかりました パラメータで関数を呼び出すように 同じJavaScriptを異なる値で再利用したい場合 毎回 新しい文字列を構築する必要がありました
もう1つ厄介なのはデータの移行です これらの文字列はゼロを表すのか? アプリケーションコードの他の場所では これらは整数ですが 文字列のコンポーネントから構築するには それらを文字列に変換する必要があります さらに大変なのは このnative dictionaryの各エントリーに 文字列を手動で追加する方法です 私の望みは名前付き引数を持つ関数として 同じ定数の文字列を再利用すること そして それらの引数が シリアル化や逆シリアル化されないことです
それらは新しいcallAsyncJavaScript APIで 実現できます コードに何が起こるか見てみましょう
引数から文字列を構築しなくても 自然にJavaScriptを書けます 文字列に必要な引数に名前を付けて callAsyncJavaScriptの呼び出しで それらの値を渡せるのです 引数タイプのシリアル化と逆シリアル化は 自動的に行われます Cocoaの文字列がJavaScriptの文字列になり 数字は数字のままです Cocoa dictionaryは JavaScriptのオブジェクトになります このユーティリティメソッドは 引数の値を変えて このように簡単に再利用することができます
私の例ではJavaScriptに 明確な戻り値があります これがevaluateJavaScriptとの もう1つの違いです 明確に値を戻さなければ完了handlerは “undefined”を受け取ります しかし別の重要なトリックが隠されています JavaScriptがPromiseを返した場合 完了handlerは すぐには呼び出されません Promiseが解決するのを待ち その遂行結果とともに呼び出されます このコードは内蔵のfetchメソッドの呼び出しで 戻されるPromiseを返します つまりリソースのバイトがロードされるまで 完了handlerは呼び出されません これは最新の非同期JavaScriptを シームレスに使用する方法の一例です CallAsyncJavaScriptは すばらしい追加機能ですが アプリケーションがJavaScriptを 使用する方法は 他にもあります WebKittensチームは 便利な機能を組み込みました 例えば新しいコメントが サーバ側の投稿に追加されると ページに通知し 知らせてくれます さらにページ上の他のJavaScriptのために コメントのイベントも発生させます アプリケーションにも新しいコメントを知らせ ネイティブコードに通知するには WKScriptMessageHandlerを使います 本来このAPIは一方向の通信チャネルとして 設計されました スクリプトメッセージへの返信を処理するため 双方向にするには― 追加のコードが必要です 例えば後の返信を調べられる識別子で 各メッセージを追跡します メッセージングシステムが高度になるほど メッセージ追跡メカニズムも複雑になり 作成しデバッグするコードも増え 解決不能な競合状態も発生します
これを改善するため2つの変更を加えました 1つは 重要な戻り値がないため postMessageは“undefined”を返していましたが “Promise”を返すようになりました 2つ目はWKScriptMessageHandlerプロトコルの 新しい形式により 受信する各メッセージに 完了handlerが添付されます その完了handlerを呼び出すと postMessageからのPromiseが解決します メッセージの返信を待つJavaScriptのコードは このようになります Promiseの解決により メッセージへの返信を処理するのです これは よいことです
アプリケーションのJavaScriptと その見栄えには満足です 次は猫と犬たちの表示に 問題がないか確認しましょう より柔軟なレンダリングのために新しいAPIを いくつか適用しました このWebコンテンツは比較的古く― “responsive design”という言葉が 現れる前のものです 元のWebKittensは古いiPhone向けのため 古いiPhoneでは見やすくなっています これが元のiPhoneでのコメント欄です
これが新しいiPhoneでのコメント欄で― 元のWebKittensより かなり大きくなっています 投稿からニュースフィードに戻るために追加する ネイティブUIの始まりが見えています Webコンテンツ自体は悪くないですが 空白も多く― 2005年頃のWebサイトのように見えます そこで空白や画面をもっと活用し― ネイティブUIに合うようサイトを適応させます
まずCSSを使って 画面を埋められるか試してみました CSSズームプロパティは WebKitで十数年前からあり― ボディ要素に適用すれば うまくいきそうです
ズーム値が十分大きければ― うまい具合に ビューポート幅いっぱいに広がります ここでは少し不格好です まずクライアント領域で JavaScriptを評価しているにも関わらず ページに見える形で CSSを変えていることに変わりはありません WebKittensでは問題ないかもしれませんが やはり思わしくない 次に ナビゲーションごとに手動で行えば 競合状態になります javascript to override zoomが 実行される前にコンテンツが表示されるか? 分かりません これを解決するのがWKWebViewにある 新しいpageZoomプロパティです Safariでcommand plusや― command minusやfull pape zoomを 行うプロパティと同じもので 多くのシナリオで役立つと思います
これを使えばJavaScriptでCSSを変えるのと 同じ効果が得られます それによる欠点はありません コードも大幅に減り 動作も予測しやすくなります
続いてPups on Safariの コメント欄を見ましょう ヘッダとフッタは ブラウザで表示されることを想定したものです あまり望ましくありません サイトのアーチファクトでなく ネイティブUIを表示したいのです これらを取り除くため Web Inspectorで詳しく見ることにしました これらの要素にはPup Headerと Pup Footerというクラスがありました どこで使われているか詳しく見ましょう
no header and footer deviceに カスタムメディアクエリを一致させています CSSでは普通 少数のメディアタイプしか見られません “画面”や“プリンター”などが ありますが いずれでも ありません 同僚に聞いてみたところ― iPhone用のPupsアプリケーションができる前に MacのWebViewを使うものもあったようです MacのWebViewには特定のメディアタイプとして すばらしい機能がありました 実際の画面をプリンターに見せかけるのに よく使われましたが カスタムタイプにも使えます アプリケーションのコンテキストにより 同じコンテンツを違う表示にできるのです 今年は この機能を 全プラットフォームでWKWebViewに導入します
WKWebViewでカスタムメディアタイプを 設定すると これらの要素を簡単に取り除けます カスタムアプリケーションの他のスタイルも JavaScriptを使わずに― ナビゲーションごとでなく グローバルに導入することができます “Webコンテンツの扱い” アプリケーションの外観の微調整は 済みました 次はWebコンテンツ自体に焦点を当てた 他の機能についてです 幸い今年は関連する新しいAPIがあります 先程のPups on Safariの投稿は― 人気があり たくさんのコメントがありました
ベスが面白いコメントを書き込んでいたのですが スクロールして探すのは大変です “find in page”機能が欲しいところですが どう導入するか? JavaScriptには 優秀な検索ユーティリティがあり― 検索機能を深くカスタマイズするのに 適切だと思われます しかしWKWebViewに 新しく簡単な検索機能ができました 動作も他の機能と似ており まさに求めていたものです
他のAppKitやUIKit APIと同様に― 検索に関するいくつかの設定が可能です 方向や大文字と小文字の区別 wrappingなど 設定しなければ 実用的なデフォルト設定となります 見つかれば選択され そこまでスクロールされます このように “ブレイディに似た犬を思い出した” 最初の印象ほど面白くなかったです アプリケーションには コンテンツのシェア機能も必要です かわいい猫や犬たちは シェアにふさわしいコンテンツでしょう 数年前からWKWebViewではコンテンツの ビットマップスナップショットを取得できます さまざまな状況で有用な機能です ただし対象は画面上のコンテンツに限られます 例えば最大解像度までズームする機能を 追加しても― 見える範囲しかキャプチャできません 目的によっては ビットマップ画像は不適切かもしれません PDFでシェアするのもいいでしょう 今年からWKWebViewで可能になります
PDFのキャプチャ方法を設定したい時 または画面外のコンテンツと 表示されたコンテンツすべてのPDFが欲しいなら デフォルト設定でcreatePDFを呼び出しましょう このコードは― 検索可能なテキスト形式の全コメントも含めて 投稿全体を― このように 1つのPDF文書としてシェアします 人気の投稿でしょ?
もう1つ コンテンツスナップショットで便利なのは WebArchiveです WebコンテンツのDOMと レンダリングが必要なサブリソースを― 豊富に含んだスナップショットです WebKitフレームワークのリリース以来 採用されているファイル形式であり 全プラットフォームのWebコンテンツのための ネイティブのペーストボード形式でもあります Browser Petsの複合ニュースフィードの問題を デバッグしていた時に WebArchiveを活用したかった WKWebViewは最初のリリースから WebArchiveファイルをロードできましたが 保存は できなかったのです 今はできます createWebArchiveDataを使えば Webコンテンツのスナップショットを 後のデバッグやテスト用に取得できます
ビットマップスナップショット取得や PDF作成のように― WebArchiveデータを要求し 完了handlerで結果を得るという単純な方法です 後で使うためディスクに保存したり― ペーストボードに置いたり すぐ別のWKWebViewにロードしたりできます 先述のとおり 以前からWKWebViewは WebArchiveファイルをロードできましたが 知らなかった人もいたようです そこでコードをシェアしたいと思います “load(data”の中に 適切なmimeTypeを入れます
これらを含めて― WKWebViewからデータを入手する方法は 増えています 重要なものが もう1つ WebKittensとPups on Safariは 重要な社内ツールです チームメンバーの中には 好きなペットを印刷する機能のおかげで― 1日のやる気を保つ者もいます
Browser Petsは新しいので 当然 SwiftUIを使っており― Macバージョンも作れました しかし重要なのは印刷機能です しばらく前から iOSではWKWebViewの印刷が可能でしたが Macでは不可能でした それがmacOS Big Surで可能に 興味がある方は SDKで探して試してみてください アプリケーション側で役立つAPIを さらに紹介しますが Webコンテンツに注力したい人もいるでしょう 我々も常に 新しいWeb向け機能に取り組んでいます 今年も例外ではありません ぜひ“What's New for Web Developers” セッションもご覧ください 最後にユーザーのプライバシーに関する 重要な発表があります WKWebViewを使う開発者に 影響するものです ご存じかもしれませんが繰り返します 我々はプライバシーを基本的人権だと考えます この考えは我々の基本理念です これを念頭にiOSとApp Storeを設計しました ネイティブアプリケーションが個人情報を 同意なしに使うことを防ぐよう努めています これはポリシーに限らず技術でも同様で 毎年 改善しています 一方 Webでは― ユーザーがWebを閲覧する時 大抵 誰かしらに監視されます 管理者は おらず― Web技術の中には他者の追跡を 促すようなものもあります 我々はWebKitでの解決策を考えました “トラッキング防止機能” 我々はトラッキング防止機能 すなわちITPに取り組み始めました クライアント側のさまざまな ヒューリスティックスや機械学習を使って― トラッカーを特定し 分類して阻止します 2017年にSafariに追加して以来 改良を重ねており― 今後も改良し続けます SafariにITPを追加して以来― 多くのWKWebView開発者から アプリケーションに使いたいと言われています iOS 14とmacOS Big Surでは― すべてのWKWebViewアプリケーションで ITPをデフォルトで使えます 制御するのはユーザーです 例えば汎用ブラウザで― 外部サイトとの互換性のため ユーザーがITPを無効化すべき場合もあります これは まれな状況ですが― Safariと同様に ユーザーに無効化を促すAPIもあります ITPはWebでユーザーのプライバシーを守る 強力な手段の1つですが― 我々は そこでやめませんでした ユーザーを守る他の方法を探る中― アプリケーションでWebコンテンツが使われる 一般的な方法を3つ特定しました 最も分かりやすいのは Safariのような汎用Webブラウザです これらのアプリケーションの主目的は― あらゆるソースのWebコンテンツを示し ユーザーの閲覧に役立つことです 汎用ブラウザと対局にあるのが― 1つ または2~3つのサイト内に留まる アプリケーションです ネイティブUIや Webコンテンツ表示のバランスに関わらず Webコンテンツ自体が アプリケーションの中核の一部となっています
最後にアプリケーション内ブラウザ アプリケーション固有のドメインを始め さまざまなソースからコンテンツを集めます ユーザーは どこからでも閲覧を始められます その典型例は ソーシャルメディアのニュースフィード Browser Petsと同様です 最後の2タイプには― WKWebViewの新機能 App-bound domainsがあります 発想は単純です どのドメインが アプリケーションの中核かを指定します
最小権限の原理で安全なアプリケーションを 設計できるようにするのです アプリケーションの中核でないコンテンツとの 深いやり取りが あなたが書くコードと― フレームワークやライブラリからの コードのために無効化されます Browser Petsにも影響します コメント欄に猫や犬の情報を含む 他のドメインへのリンクがある時があります これらのリンクを許可するには App-bound DomainsをWebKittensと Pups on Safariに制限すれば安全に行えます
構造や関数がよく分からないドメインで― ユーザーデータが 間違って漏れることを防ぐのです 故意に盗まれることもなくなります サイトの開発者が どんな悪意を持っているか 知る必要はありません
導入は簡単です アプリケーションのInfo.plistに WKAppBoundDomainsのエントリーを追加し ドメインの配列にポイントします これがBrowser Petsの例です 他のドメインはロードできますが― 深いやり取りは 技術的なレベルで阻止されています
すべてのドメインとの深いやり取りを 無効化することもできます Info.plistに 空の値でkeyを追加するだけです やり取りは一切必要なく 任意のコンテンツをロードする場合は これがベストプラクティスです
セッションは以上です 別々のWebサイトからコンテンツを表示する 2つのアプリケーションを 1つのニュースフィードに統合しました SafariとWebKitチームの士気は最高潮です これまでにアプリケーションのJavaScriptを Webコンテンツから分離させました callAsyncJavaScriptと postMessageWithRepliesを呼び出し― JavaScriptロジックを単純化しました レンダリングに影響する新APIで コンテンツの表示を微調整し 簡単な検索機能と 強力なPDFシェア機能 Macでの印刷機能も追加しました トラッキング防止機能を使い App-bound Domainsを導入して― プライバシーを尊重しました これらの機能は 開発者のフィードバックを反映しています すべてには応えられていませんが これで終わりではありません ぜひ新しいAPIを試して― WKWebViewに 他に求めるものをお聞かせください フィードバック以外に webkit.orgにはさまざまな連絡方法があります 我々のSlackや メーリングリストへのリンクなどです WebKitはオープンソースです バグの報告だけでなく 試して構築する方法を学ぶこともできます Twitterもあります 新しいWeb向け機能やWeb Inspectorの改善 他の最新リリース情報を知りたい方は― 隔週で更新される Safari Technology Previewをどうぞ Purple Safariを ぜひお手元に
ご視聴 ありがとうございました 引き続きWWDCをお楽しみください
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。