ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Group ActivitiesによるSafariでのメディア再生連携
Web上やコンパニオンAppで楽しめるSharePlay体験を構築しましょう。Group ActicitiesフレームワークとコンパニオンWebサイトを組み合わせてSharePlayをSafariに導入する方法を紹介します。SharePlayによって、まだApp StoreからAppをダウンロードしていない人であっても、お互いにつながってグループインタラクションを楽しむことが可能になります。
リソース
関連ビデオ
WWDC21
-
ダウンロード
♪ (Safariでのメディア再生と Group Activitiesの調整) Jerです こんにちは AppleのWebKitと Safariで メディア再生に取り組んでいます 人々はお気に入りの番組や 映画を見たり 音楽を一緒に聴くことが大好きです 同じ部屋にいる人も 隣にいる人も 地球の反対側にいる人も GroupActivitiesを使えば これまで以上に簡単に ユーザーがどこにいても SharePlay体験ができます このセッションでは 4つのトピックについて説明します Safariでの調整再生の概要 SafariでSharePlayを 使う為のiOSアプリを準備方法 アプリのウェブページにMedia Session APIを採用する方法 また 複数のデバイス間で再生を 調整するための 新しいウェブAPIも 追加しています それでは SharePlayと Safariについて 少し話してみましょう 前のセッションでは GroupActivitiesを 使ってiPhoneやiPad アプリケーションで素晴らしい SharePlay体験を作り出す 方法を学びました macOS Montereyでも 同じ体験ができます iPhoneやiPadの 素晴らしいアプリと一緒に Catalystを使用する Macに変更します またアプリにコンパニオン Webサイトがある場合は Mac Safari 15 ユーザーがApp Storeから アプリケーションを ダウンロードしなくても 同じ素晴らしい SharePlay体験を それらのユーザーに提供できます これが このセッションで行う方法です 私は映画の予告編を見られる iPhoneアプリケーションを 開発しています アプリには既に GroupActivitiesの サポートが追加されており 友達がFaceTimeで一緒に 映画の予告編を見ることができます しかし 私の映画予告編アプリには ウェブサイトもあります そして そのWebページに GroupActivitiesの サポートを追加したら どうなるかを示します 友人のSamと FaceTime通話をしています Samは映画の予告編を 見るのが大好きなので この新しい Movie Trailers アプリのテストを手伝って くれるよう頼んだ 通話中にアプリで新しい 予告編を再生すると 私はその予告編を通知で 見るように招待されます Safariでセッションに 参加するオプションが表示されます この通知をクリックすると Safariが起動して 共有コンテンツのURLが表示され Samが予告編の再生を 開始すると同時に ここSafariでも再生されます 私はここSafariでビデオを 一時停止したり 再生したり 探したりすることができセッションに 参加している他のすべての人は 同じコマンドが同時にローカル動画に 反映されているのを見られます すごくいいことになりますよ! では 映画の予告編サイトに GroupActivitiesの サポートを追加するには 何が必要なのでしょうか? Safariの中身を見る前に Safari 15で利用可能に なった新しいWeb APIで GroupActivitiesを 使ってアプリケーションを Safariで動作させる 方法を説明しましょう Safariで GroupActivities セッションに参加するには iPhoneまたはiPadアプリを 持っているユーザーが自分の Webを指すfallbackURLを持つ GroupSessionActivityを 作成する必要があります fallbackURLは Webサイトだけでなく 再生する特定のコンテンツも 識別する必要があります Watch Togetherの 招待状が iPhoneユーザーから Macユーザーに発行されると Safariが起動され GroupSessionActivityに 指定したURLを 読み込むように求められます fallbackURLが Safariにロードされると サイトはいくつか単純だが 重要なWeb APIを実装する 必要があります 1つはメディアセッションです Media Sessionは 標準のWeb APIで サイトがブラウザー Safariに ページ内のメディア再生の 現在の状態について詳細を 通知できるようにします サイトは 現在の再生状態 コンテンツの再生時間を ブラウザに通知できます 現在の再生項目の アートワークを提供できます また 現在のコンテンツが スキップ可能な広告であることを ブラウザに通知することもできます ブラウザがこのメタデータを すべて使用できるようになると そのメタデータを オペレーティングシステムの 他の部分に提供し ブラウザウィンドウの外部にある ユーザーに表示することができます オペレーティングシステムは データが 「再生中」 と呼ばれるものの中にあると表示 再生中のメディアを素早く見て コントロールするには 今すぐ再生するのに最適な方法です iOSでは ユーザーは コントロールセンターと ロック画面から再生中のゲームに アクセスできます macOS Monterey では メニューバーから直接 プレイビューにアクセスできます また Safariは Media Sessionを 通じて提供される情報を使用して コンテンツのタイトル 再生時間 再生状態 アートワークなどを 再生中に取り込みます 再生中に簡単な再生コントロールの セットを表示することで 再生中の曲の再生を コントロールすることもできます ユーザーが再生中に操作したときに 実行する特定のアクションについて サイトをメディアセッションに 登録できます これにより ユーザーが再生中に再生ボタンを タップしたときに Safariがサイト独自の アクションの 実行を開始できます メディアセッションでは ブラウザに公開するメタデータや 再生コマンドの実装方法をサイトで 完全に制御できます 再生を開始する前に 何らかの設定や プリフライトを行う 必要がありますか? 問題ありません mediaSessionの 再生アクション実行を使用すると 次の操作を実行できます サイトが以前にメディアセッションを 採用していた場合は すでに半分完了しています しかし 映画の予告編サイトはまだ Media Sessionを 採用していないので ここでそのサポートを追加しよう このサイトでは 再生 一時停止 および seektoのアクションを 追加します そのためにはnavigatorの mediaSession プロパティを使用します 最初に再生用の アクション実行を追加します mediaSession. setActionHandler ()を 呼び出し ストリングplayと video要素に対して play () を呼び出すだけの インライン関数を渡します 次に pauseとseektoに ついても同じ操作を行います 再生状態をブラウザに 正確に表示するために ビデオ要素にイベントリスナーを 追加し その状態が変化したときに mediaSessionを 更新します まず updateMediaSessionState () という関数を追加します 再生中か一時停止中かを 調べるために 動画エレメントを照会します 次に ビデオ要素の再生状態に 応じて mediaSessionの playbackState プロパティを文字列の再生 または一時停止に設定します 次に ビデオエレメントの継続時間 再生レート および現在の時間を照会します 次に これらの値を使用して mediaSessionの setPositionState () 関数を呼び出しdictionary パラメータに値を入力します 次に これらの値が 変更されたことを 検出するイベントリスナーを追加し updateMediaSessionState ()を 呼び出してこれらの新しい値で mediaSessionを 更新します 再生 一時停止 継続時間の変更 レートの変更 および時間の変更を行う イベントリスナーが必要です 最後に 映画の予告編のWebには タイトル文字列と タイトルアートワークのURLの 両方があるため Media Sessionの metadataプロパティを これらの値を含む新しいMediaMetadata オブジェクトに設定できます 試してみよう! Safariでページをリロード して再生を開始し システムメニューの 再生中アイコンをクリックします 再生中パネルにタイトルと アートワークが表示されます 一時停止ボタンをタップすると 一時停止アクション実行機能が 呼び出され再生が一時停止します Media Sessionは 再生の開始または停止を ブラウザがページに 指示するメカニズムを提供する ことによって Webページでの Watch Together 体験の構成要素を提供します これで Webページに カウティング体験を作成する 第2のパートに進む 準備ができました セッション内のすべてのデバイス 間で再生を調整します そのために メディアセッションに 「Coordinator」 という新しいプロパティを追加して 拡張しました ページは Media Session's Coordinatorを 使用して セッション内の他の すべてのユーザーに再生の開始 または一時停止 メディアの タイムライン内の特定の ポイントへのシークまたは 再生リスト内の 次のアイテムへの移動の 意図を通知します Coordinatorは セッション内の他のすべての機器と これらのインテントを通信し 他のすべてのデバイスの 再生状態の変更を受信し コンフリクトを解決し 全員が再生を開始する 準備ができるのを待ちます 全員の準備ができたら Coordinatorは 先に追加した メディアセッションの アクション実行を使用して セッション内の他のすべてのユーザー とともに再生を開始します また 別のユーザーが何らかの 理由で再生を一時停止した場合 Coordinatorは メディアセッションの一時停止 アクション実行機能を呼び出します とはいえ 幾つかの注意点を指摘しておきたい Coordinator UIは 実験的なWeb APIです 標準化はまだ行われておらず そのプロセスによってこのAPIは 改善される可能性が高いですが APIの一部の側面は 変更される可能性があります 詳細については W3CのMedia Session GitHubページをご参照下さい このAPIは現在Safariで のみ実装していますが SafariがCoordinatorを 実装するために使用する GroupActivities フレームワークは 他のMac ブラウザでも採用する可能性があり また採用されることを期待しています 最後に ユーザーはSafariの 既存のセッションに参加できますが GroupSessionは iPhone iPad macOSアプリケーションから 開始しなければなりません ここでCoordinator のサポートを追加します 最初にしたいことは 利用可能になったら セッションに参加することです そこで coordinatorchange というイベント用のリスナーを mediaSessionに追加します 実行機能でmediaSessionに null以外のcoordinator プロパティがある場合 そのjoin () 関数を呼び出します また コントロールにアイコンを 追加して セッションで再生していることを 示します 実行機能では mediaSessionに coordinator プロパティーがあるかどうかに 基づいてアイコンを表示または 非表示にします また clickイベント リスナーをアイコンに接続して コーディネータの leave () を呼び出します 次に カスタムコントロールの イベントハンドラを変更して コーディネータが存在するか どうかを確認します coordinatorが 存在する場合は 代わりに適切な coordinator関数を呼び出します 再生ボタン 一時停止ボタン およびタイムラインスライダ用に 1つ追加します 実際の動作を見てみましょう 友人のSamからここに 招待状をもらったので それを受け取るつもりです SamがiPhoneで 見ているのと同じコンテンツに 私のページがロードされます 再生ボタンをクリックすると SamのiPhoneと私の ウェブページが同時に再生されます そこに行く方法は アドベンチャーです 怖いです そうでなければ アドベンチャーにはなりません (音楽) 素晴らしかったです 予告編が終わったので SamはiPhoneを使って 最初に戻ります
iPhone iPad Apple TV またはMacで 実行しているSafariなどの アプリケーションで お気に入りのコンテンツを 一緒に視聴できることが ユーザーはきっと好きになる と思います ユーザーがどこにいても その体験を すべてのユーザーに提供できる ようになることを願っています GroupActivities APIの詳細については 「Coordinate media playback with Group Activities」 および 「Design for Group Activities」の セッションを参照してください Safari 15で利用 可能になる他の新しいウェブ APIに興味がある人は セッション 「Develop advanced web content」を チェックしてほしいです お集まり頂きありがとうございます WWDC 21の続きを楽しんでください ♪
-
-
2:50 - Preparing your app
struct WatchTogether: GroupActivity { var contentIdentifier: String func metadata() async -> GroupActivityMetadata { var metadata = ActivityMetadata() metadata.fallbackURL = URL(string: "https://example.com/title/\(contentIdentifier)") return metadata } }
-
5:29 - Adopting Media Session
if (navigator.mediaSession) { navigator.mediaSession.setActionHandler('play', () => video.play() ); navigator.mediaSession.setActionHandler('pause', () => video.pause() ); navigator.mediaSession.setActionHandler('seekto', details => { video.currentTime = details.seekTime; }); } let updateMediaSessionState = function() { if (!navigator.mediaSession) return; let playbackState = video.paused ? 'paused' : 'playing'; navigator.mediaSession.playbackState = playbackState; let positionState = { video.duration, video.playbackRate, video.currentTime }; navigator.mediaSession.setPositionState(positionState); }; for (var event of ['playing', 'pause', 'durationchange', 'ratechange', 'timechange']) video.addEventListener(event, updateMediaSessionState); navigator.mediaSession.metadata = new MediaMetadata({ title: myPlayer.titleString, artwork: [{ src: myPlayer.artworkURL }] });
-
9:32 - Adopting Coordinator
navigator.mediaSession.addEventListener('coordinatorchange', coordinator => { if (coordinator) coordinator.join(); controls.inSessionIcon.style.hidden = !coordinator; }); controls.inSessionIcon.addEventListener('click', event => { let coordinator = navigator.mediaSession.coordinator; if (coordinator && coordinator.state == 'joined') navigator.mediaSession.coordinator.leave(); }); controls.playButton.addEventHandler('click', event => { if (navigator.mediaSession.coordinator) navigator.mediaSession.coordinator.play(); else video.play(); }); controls.pauseButton.addEventHandler('click', event => { if (navigator.mediaSession.coordinator) navigator.mediaSession.coordinator.pause(); else video.pause(); }); controls.timeline.addEventHandler('onchange', event => { if (navigator.mediaSession.coordinator) navigator.mediaSession.coordinator.seekTo(event.target.value); else video.currentTime = event.target.value; });
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。