ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Safari Web Extensionの最新情報
Safari Web Extensionの最新の改善点により、Webを閲覧するユーザに優れたエクスペリエンスを提供する方法をご確認ください。Manifestバージョン3へのアップグレード方法、最新のWeb Extension用APIを取り入れる方法、デバイス間でExtensionを同期する方法を紹介します。
リソース
- Developing a Safari Web Extension
- Learn more about bug reporting
- MDN Web Docs - Web Extensions API
- Messaging a Web Extension’s Native App
- Modernizing Safari Web Extensions
- Safari web extensions
関連ビデオ
WWDC23
WWDC22
WWDC21
-
ダウンロード
♪♪
こんにちは Kiara Roseです Safari Extensionの エンジニアをしています 今年のExtensionの新機能 についてお話しできることを とてもうれしく思います 今日のプレゼンテーションに入る前に iOSやiPadOS macOSの ExtensionをApp Storeに 提出してくれたみなさんに 感謝いたします 今後も優れた体験を 提供できるように 新しい機能とAPIを実装 し続けることが目標です 今日は過去1年間に実装した エキサイティングな新機能の いくつかに焦点を 当てたいと思います Extensionの新しい Manifestバージョン アップデートされたAPI 複数のデバイス間での Extensionの同期などです Manifestバージョン3 から始めましょう Manifest3はWeb Extentionプラット フォームの次のイテレーションで パフォーマンスと セキュリティが改善され 一般的なExtension APIも 統合されています バージョン3を使用するように Extensionを更新済みの場合は ExtensionはSafari15.4 以降で機能します Extensionのサポートが まだでも心配無用です Safariでの Manifestバージョン2 サポートは継続されます Manifestバージョン3の 重要な新機能の1つは ExtensionがService Workerを 使用できることです Web開発者ならService Workerに精通されているかと思います addEventListener APIによる リスナー登録が可能な イベント駆動型のページが こちらです このページはManifest バージョン3をサポートする 他のブラウザとも 互換性があります Extensionにバックグラウンド ページの使用を継続する場合は それでも構いませんが 非永続でなければなりません バージョン3のもう1つの 改善点はページで JavaScript実行のAPIが スクリプト型に移動したこと メソッドの機能のほとんどは 同じままですが スクリプトが提供する 新しい追加機能もあります ページにコードを挿入する 新しい方法 コード実行ページのフレーム オプション コード実行環境を決定 する機能などです 新しいスクリプトAPIの コードがタブAPIと どう異なるかを見て みましょう このコードスニペットでは tabs.executeScript APIを使用してページの 背景色を青に変更します このAPIではcodeプロパティを 渡すことによって 文字列に含まれるコード のみを挿入できます では新しいスクリプト APIを使用して このコードを含む関数 オブジェクトを渡します また他の関数と同様に 引数を含めることも 可能です これは文字列でのコード 記述に制限されないため スクリプト実行のために 改善された方法と言えます またスクリプトにtargetという 新しいプロパティがあります このプロパティはスクリプトを 実行する場所を指定します スクリプトを実行するには 実行するタブのIDを指定 する必要があります タブIDが指定されていないと APIはエラーを返します コードを挿入するページの フレームを選択する場合は フレームIDを指定する こともできます タブAPIでは指定できるIDは 1つだけですが スクリプトを使用すると 複数のIDを指定できます もっと多くのコードを複数の ファイルに含められれば きれいに見えるとしましょう tabs.executeScript APIで 指定できるファイルは1つ だけですが scripting.executeScriptでは 複数のファイルを指定できます insertCSSでも同じ ことができます ここではページにスタイルを 挿入できて ページから挿入されたスタイルを 削除できる removeCSSについても 同様です このAPIはManifest バージョン2と3で使用可能です ただしtabs.executeScriptAPIは バージョン3では使用できません 新しいスクリプトAPIに加えて 他のAPIにも変更があります その変更の1つは web_accessible_resourcesです
Manifestバージョン2では リソースを含める場合に ファイルの配列を渡すことに よっておこない ページにアクセスできる ようにします ただしManifestで指定した すべてのリソースへのアクセスが ページに与えられるため 問題になる可能性もあります
バージョン3の新しい形式を 使用すると 特定のサイトで使用できる リソースを制御できます 例を見てみましょう 以前はクッキーとパイの 画像はExtensionが アクセスできるサイトで 利用可能でした 今回バージョン3では パイの画像はapple.comの URLでのみ使用でき クッキーの画像はwebkit.orgの ページでのみ使用できます 次にbrowser_action APIと page_action APIの 変更点を見てみましょう
Manifestバージョン2では アクションを明確に指定します ただしこれらのAPIは同様の 役割を果たしているため バージョン3ではアクションAPIを 1つだけ使用するように統合しました
またExtensionのコンテンツ セキュリティポリシーを 宣言する方法も 更新されました バージョン2ではExtensionの ポリシーは文字列で定義します バージョン3ではextension_pages キーを持つ オブジェクトを使用して 定義します スクリプトのリモートソースは バージョン3では 許可されなくなりました 最後は非推奨の browser.extension.getURL APIの変更についてです このAPIはバージョン3では サポートされなくなりました browser.runtimeで同等の APIを定義してください Manifestバージョン3で 導入された新機能について 説明しましたのでExtentionの 更新プロセスを順に見て 新機能を活用できる ようにします
昨年からのSeaCreator Extensionを更新して Manifestバージョン3に 対応しました このExtensionは魚という語の 出現箇所を絵文字に置換えます まずバージョン番号を2から3に 変更します
既存のバックグラウンドページを 使用できますが バージョン3ではExtensionが Chromeと互換性を持つように Service Workerを使用する よう更新します
最後にbrowser_actionを actionに変更
Manifestの構造に関して この拡張を行うために 必要がある重要な変更で バージョン3の 新しい仕様と互換性が あります したがってこれをテストする ためにExtensionをビルドし Safariで有効化します
次にwebkit.orgブログ ページに移動して このExtensionでfishという単語の すべてのインスタンスを 魚の絵文字で置換えます
何かがうまくいかなかった ようです ご覧のとおりページの魚が 絵文字に置換されていません ポップオーバーを調べてエラー メッセージを確認します
コンソールタブに エラーメッセージがあります browser.tabs.executeScriptが 未定義となっています これはこのAPIがバージョン3で 使用できなくなったためです 代わりに新しいスクリプト APIを使用するよう更新します Xcodeでpopup.js ファイルに戻り スクリプトを使用するように この行を変更します
スクリプトを挿入する場所を 指定するためのターゲット プロパティを追加します
新しいスクリプトAPIを 使用するため タブのIDを指定する 必要があります これを行うには tabs.getCurrent APIを 使用してタブ情報を 含むオブジェクトを取得します
次にそのオブジェクトを 使用してタブIDを取得します
次に実行するスクリプトを 含むファイルを追加します
最後に行う変更はManifestに スクリプト権限を 追加することです
先に進んでExtensionを ビルドし Safariでこれらの変更を 適用します ご覧のとおりこのExtensionは Safariで機能する Manifestバージョン3の 新機能です Extensionのアップグレードが いかに簡単か分かりました ただし新しい変更に慣れて いない場合は スクリプトなどの多くの 機能がバージョン2でも 使用できるようにして おきます 宣言型のネットリクエスト から始めて 今年更新したAPIを 見てみましょう 宣言型ネットリクエストは Extensionに高速で プライバシーを保護する方法を提供する コンテンツブロッキングAPIです ルールセットによりネットワーク リクエストをブロックします このAPIによりリクエストの インターセプトや変更など すべての作業をSafariに 委任して適用する コンテンツブロックルールを 指定します Manifestでルールセットも 指定できます
ここでは宣言型ネットリクエスト 権限を追加し declarative_net_request キーを使用して ページに適用する必要がある ルールセットを追加します 以前はManifestで宣言できる ルールセットは最大10点でした 機能の更新により最大50の ルールセットを 宣言できるように なりましたので Extensionをカスタマイズ できます ただし一度に有効にできる ルールセットは10個です ルールセットの作成 方法の詳細については Safari Web Extensionに 関するプレゼンをご覧ください このAPIについてさらに 詳しく説明されています 宣言型ネットリクエストの 新機能に移ります 以前はManifestでルール セットを宣言するのみでした 今回2つのAPIが 実装され ルールを動的に更新 できるようになりました 最初のAPIは updateSessionRulesです これによりExtensionのルールを 追加や削除できます ただしこれらのルールは ブラウザセッションや Extensionの更新を超えて保持 されないことが重要です 永続化するルールを更新する 場合は代わりに updateDynamicRules APIを使用してください これによりExtension全体を 更新せずに ブロックルールを更新できます これらのAPIの1つを使用して ルールセットに 変更を加える方法を 見てみましょう Extensionを使用してページの 一部のコンテンツを ブロックしてから新しいAPIで 選択したページのブロックを解除 Extension Manifestでは最初に 宣言型ネットリクエスト権限を 追加します
次に宣言型ネットリクエスト キーを使用してルールを追加
適用されているルールは rules.jsonファイルにあります このファイルではURLすべての 画像をブロックするルールを宣言 Extensionのビルドでこのルールが Safariでどう適用されるか
ご覧のとおり画像は 消えています 期待どおりの挙動です Safariはコンテンツブロック ルールを適用しました 魚に関するウィキペディアの ページに移動すると このサイトの画像もブロック されていることがわかります ここではwebkit.orgページ 以外のすべてのページの 画像をブロックする想定 とします 宣言型ネットリクエスト用に 更新されたAPIを使用して それを実行できます Xcodeに戻って 変更を加えましょう popup.jsファイルで コンテンツブロックルールを 更新する関数を宣言
webkit.org/blog-filesページで 画像を許可するルールを設定 次にupdateSessionRules APIでセットに追加 最後にExtensionをビルドし Safariで変更をテスト
ブログ投稿の画像が 読み込まれサイトで画像を 許可する新しいルールが 機能していることがわかります ウィキペディアのサイトに アクセスすると このページの画像はまだ ブロックされていますが 新しいルールがこのページに 適用されていないためです これが新しい宣言型ネット リクエストAPIを使用して コンテンツブロックルールを 更新する方法です
ではExtensionがページと どう通信するかを見ましょう このすばらしい機能により Extensionが有効な場合 サイトはカスタム動作を 作成できます このAPIはexternally_connectableと 呼ばれます これの使用にはManifestで 一致パターンを宣言 この一致パターンによって Extensionと通信するページが決定
この機能はブラウザの 名前空間を 使用した場合のみ 機能します 最後にユーザーはメッセージを 送受信する前にExtensionに ページへのアクセスを 許可します この機能の使用にはページに 追加するコードを見ます まずextensionIDを 取得します これはExtensionのバンドルID であり この形式のチームIDです チームIDは developer.apple.comの アカウント設定の タブにあります 次にメッセージ送信APIを 使用してメッセージを投稿 関数を渡すことで Extensionからの 受理応答を処理できます 次にExtensionがメッセージを 受信するために 必要なコードを 見てみましょう ExtensionはonMessage Externalというイベントから ページへのメッセージを 受信できます イベントリスナーに渡された メソッドを使用して メッセージをページに返信 することもできます ブラウザごとに異なるExtension ストアがあるため Extensionは多くの異なる 識別子を持つことが可能です したがってChromeやEdge ではなく Safari Web Extensionに メッセージを送信 していることを確認 する必要があります この処理にはPromise.allの 呼び出しで browser.runtime.send MessageAPIを使用 次にこの処理のサンプル コードを見てみましょう ページから複数IDを使用して メッセージを ブロードキャストできます Extensionからの応答によって 今後の通信に 使用するExtensionIDが 通知されます determineExtensionID という関数があります この関数はbrowser.runtime. sendMessageという APIでExtensionに メッセージを送信 複数のIDがあり使用すべき 正しいIDを 決定する場合は Promise.allを使用し defineExtensionID関数で 複数の呼び出しを行います Promise.allはpromiseの 配列を受理し 解決された値の配列を含む 単一promiseを返します この配列を使用してユーザーが インストールしたExtensionを検出 Extensionのバックグラウンドページで メッセージを検索する 必要があります メッセージを受信したら Extensionのインストールを ページに通知するために メッセージを送り返します これが新しい externally_connectableです APIによるExtensionがページと 通信できるようにする方法です 更新された機能の中で 個人的なお気に入りは unlimitedStorageです unlimitedStorageは実際 無制限なのです! この機能のリクエストが 非常に多かったので Extensionの10MB割当ては 撤廃されました 適切な量データを自由に ご利用いただけます ただしユーザーには使用中の データをクリアする機能が あることに 注意することが重要です そこでユーザーがデータを クリアしたくないと思わないよう 厳密に必要なデータのみを 保存するようにしてください この機能を使用するには Manifestでストレージと unlimitedStorageの アクセス許可を要求するだけ これが昨年Extension用に 更新した全APIです 最後にユーザーがすべての デバイスでExtensionを 簡単に利用できるように する新機能について Safari 16ではExtensionの 使用体験をよりシームレスに ユーザーがデバイスで Extensionをオンにすると すべてのデバイスで オンになります さらにExtensionの ダウンロードが簡単に どのように機能するかを 見てみましょう ユーザーがMacでExtensionの 1つを有効にしているとします 他のデバイスのExtension 設定で ダウンロードするオプションが 提供されます ダウンロードするとデバイスで 自動的に有効になり ユーザーエクスペリエンスが 向上します それではこれをWeb Extensionと コンテンツブロッカーに 設定する方法について 詳しく見ていきます まずApp Storeに提出 するときに ExtensionをiOS iPadOS macOSに対しリストします これによりExtensionはユーザーの 全デバイスで利用できます 次にExtensionをデバイス間で 同期できるようにするには 次の2つの方法を採用する 必要があります 最も簡単でおススメなのは ユニバーサル購入を 採用すること ユニバーサル購入により ユーザーは1回購入するだけで 全プラットフォームでExtensionを 利用できます この方法を使用すれば 準備完了 ユーザーはExtensionを ダウンロードすると すべての機能を利用 できるようになります ユニバーサル購入を 設定するには 単一のバンドル識別子を 使用する必要があります Extension全体でApp Store Connectと同じ Appレコードに関連 付けます この詳細については ユニバーサル購入の 設定方法に関する ドキュメントを 確認してください ユニバーサル購入を設定 しないことを選択した場合は Appを手動でリンクできます それにはXcodeから同期する AppとExtensionのInfo plistに バンドル識別子を 追加します iOS AppとExtensionを macOSのものと同期するには info plistで特定のキーを 使用する必要があります このキーをmacOS Appの plistに入れ macOS Extensionの plistにも入れます 同様にmacOS Appを同期 するためのプロセスがあります このキーをiOS Appのplistに 追加し iOS Extensionのplistに 追加します Xcodeでどう機能するか 見てみましょう Xcodeで最初に行う作業は 同期するExtensionと AppのバンドルIDを含めるために 各ターゲットの設定を更新 iOS Appのinfo plistに対応する macOS Appの バンドル識別子を追加します
ご覧のとおりiOS App バンドル識別子を追加して macOS Appに対して同じ プロセスを実行しました iOS Extension同様macOS Extensionバンドル識別子を追加 最後にiOS Exentionの バンドル識別子を 追加するmacOS Extensionです これはユーザーがどこでも 使用できるようにAppと Extensionをリンクするのが いかに簡単かということです ユニバーサル購入を設定 することでこの機能を ユーザーが利用できるようにしたり iOSやmacOS Appのバンドル識別子と ExtensionにXcodeで追加し実現します 最新APIであるManifest バージョン3に ついて説明しました 複数のデバイス間で Extensionが同期されます Safari Web Extensionの 新機能について 興奮が抑えきれません 今日のセッションからコードを 含むサンプルプロジェクトを ダウンロードしてAPIを 試してみてください ご意見をお聞かせください フィードバックアシスタントから バグ報告するか Safari開発者フォーラムで チャットしてフィードバックしてください Extensionの開発をより良い ものにしたいと思います 本当ににご意見を 知りたいんです! WebExtensionsコミュニティ グループに参加して Extensionの未来を 形作りましょう Extension作成に関する WWDCプレゼンもどうぞ ご参加ありがとうございます 残りのWWDCもお楽しみください
-
-
2:43 - Executing script on webpages
// Manifest version 2 browser.tabs.executeScript(1, { frameId: 1, code: "document.body.style.background = 'blue';" });
-
3:00 - scripting.executeScript API
// Manifest version 3 function changeBackgroundColor(color) { document.body.style.background = color; }; browser.scripting.executeScript({ target: { tabId: 1, frameIds: [ 1 ] }, func: changeBackgroundColor, args: [ "blue" ] });
-
4:02 - tabs.executeScript file
// Manifest version 2 browser.tabs.executeScript({ 1, file: "file.js" });
-
4:09 - scripting.executeScript API files
// Manifest version 3 browser.scripting.executeScript({ target: { tabId: 1 }, files: [ "file.js", "file2.js" ] });
-
4:15 - scripting.insertCSS
// Add styling browser.scripting.insertCSS({ target: { tabId: 1, frameIds: [ 1, 2, 3 ] }, files: [ "file.css", "file2.css" ] });
-
4:21 - scripting.removeCSS
// Remove styling browser.scripting.removeCSS({ target: { tabId: 1, frameIds: [ 1, 2, 3 ] }, files: [ "file.css", "file2.css" ] });
-
5:08 - Manifest version 3 web_accessible_resources
// Manifest version 3 "web_accessible_resources": [ { "resources": [ "pie.png" ], "matches": [ "*://*.apple.com/*" ] }, { "resources": [ "cookie.png" ], "matches": [ "*://*.webkit.org/*" ] } ]
-
5:42 - Manifest version 3 action
// Manifest version 3 "action": { "default_icon": { "16": "Images/icon16.png" }, "default_title": "defaultTitle" }
-
5:57 - Manifest version 2 content_security_policy
// Manifest version 2 "content_security_policy" : "script-src 'unsafe-eval' https://*apple.com 'self'"
-
6:08 - Manifest version 3 content_security_policy
// Manifest version 3 "content_security_policy" : { "extension_pages" : "script-src 'unsafe-eval' 'self'" }
-
10:31 - Specifying a ruleset
// manifest.json "permissions": [ "declarativeNetRequest" ], "declarative_net_request": { "rule_resources": [ { "id": "my_ruleset", "enabled": true, "path": "rules.json" } ] }
-
11:44 - updateSessionRules
// Rules that won't persist browser.declarativeNetRequest.updateSessionRules({ addRules: [ rule ] }); // Rules that will persist browser.declarativeNetRequest.updateDynamicRules({ addRules: [ rule ] });
-
14:33 - externally connectable
// In the webpage let extensionID = "com.apple.Sea-Creator.Extension (GJT7Q2TVD9)"; browser.runtime.sendMessage(extensionID, { greeting: "Hello!" }, function(response) { console.log("Received response from the background page:"); console.log(response.farewell); });
-
15:00 - Message from webpage to extension (in the webpage)
// In the webpage let extensionID = "com.apple.Sea-Creator.Extension (GJT7Q2TVD9)"; browser.runtime.sendMessage(extensionID, { greeting: "Hello!" }, function(response) { console.log("Received response from the background page:"); console.log(response.farewell); });
-
15:33 - Message from webpage to extension (in the background page)
// In the background page browser.runtime.onMessageExternal.addListener(function(message, sender, sendResponse) { console.log("Received message from the sender:"); console.log(message.greeting); sendResponse({ farewell: "Goodbye!" }); });
-
16:17 - Determining the correct identifier
// Determining the correct identifier function determineExtensionID(extensionID) { return new Promise((resolve) => { try { browser.runtime.sendMessage(extensionID, { action: 'determineID' }, function(response) { if (response) resolve({ extensionID: extensionID, isInstalled: true, response: response }); else resolve({ extensionID: extensionID, isInstalled: false }); }); } }); };
-
17:09 - background.js
// background.js browser.runtime.onMessageExternal.addListener(function(message, sender, sendResponse) { if (message.action == "determineID") { sendResponse({ "Installed" }); } });
-
18:07 - Unlimited storage
// manifest.json "permissions": [ "storage", "unlimitedStorage" ]
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。