ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
コミュニケーション通知と即時通知の送信
Appleプラットフォームにおける通知機能の進化について紹介します。App内でユーザが通知を管理できるようにする方法を探ります。中断レベルや即時通知を使って、有意義な時間を作る方法も紹介します。また、SiriKitを使って、App内で通話やメッセージをより豊かに体験できるコミュニケーション通知についても紹介します。 このセッションを最大限活かしていただくためには、ローカル通知とリモート通知の作成経験と、SiriKitインテントに関するある程度の知識があることが推奨されます。
リソース
関連ビデオ
WWDC21
-
ダウンロード
♪ (コミュニケーション通知と即時通知の送信) こんにちは 「コミュニケーション通知と 即時通知の送信」へようこそ 私はNotificationsチームの エンジニア クリタートです 後ほど同僚のケビンも 合流します 通知はApp体験における 重要な要素です ここでは 通知を強化する 新しい方法と 特定のカテゴリの通知の価値向上 のための方法について説明します まず最初に 通知機能の視覚的な アップデートと 新しいAPIを使った拡張方法 について説明します 次に 新しい管理のための コントロールの概要と これらがコミュケーションや 即時の通知に どのように関連するかを 説明します 続いて 通知の割り込みに 焦点を当て それを制御するための 新しいAPIを取り上げます その後で 2種類の通知に絞って説明します 即時とコミュニケーション… そしてこれらを設定する方法 を説明します まず通知機能の視覚的な アップデートについて 説明します 今回の通知機能は Appののアイコンとともに コンテンツや関連するメディア に焦点を当てた 新しいデザインを 採用しています リッチな通知の表示と それに関連するアクションは システムのスタイルに合わせて 更新されています 通知のアクションにアイコンを 関連づけられるようになりました アイコンによって アクションが何をするのかを伝え アクションの横に視覚的な コンテキストを提供します ここでは 「いいね!」と 「コメント」という 2つの通知アクションがあり これらはカスタム通知カテゴリ に設定されています これらのアクションに アイコンを追加するには UNNotificationActionIconタイプ のオブジェクトを システムイメージ または テンプレートイメージの イメージ名で作成します そして これらのアイコンを UNNotificationActionのそれぞれの コンストラクタに与えます このカテゴリに関連した 通知が展開されると アクションが そのために用意されたアイコンと ともに表示されます 通知ではAppアイコンが 大きく表示されるため 高解像度アイコンを Appバンドルに提供してください リッチな通知の新しい 表示とレイアウトに合わせて Content Extensionが 継続して動作するようにし 通知アクションにアイコンを採用し さらなるコンテキストを追加します 次に 新しい通知管理オプション について説明します Appからの 通知の配信と割り込みに 影響する新しい システムコントロールがあります それが 通知要約と 集中モードです まず 通知要約について 説明します 一日の中で予定された時間に まとめて通知を 配信できるようになりました これにより 受信した通知による アクティブな割り込みの数を減らし あらかじめ設定した時間に まとめて表示します 配信されたすべての通知は 予定された時間に要約され ロック画面の通知リスト に表示されます メディアの添付ファイルを 通知コンテンツに含めることで その通知が 通知要約のトップに 取り上げられる可能性が 高くなります 新しいAPIを採用し 通知コンテンツに 関連性スコアを 提供することでも Appからの 適切な通知が 通知要約で 取り上げられるようになります 通知に関連する もう1つの管理ツールは 集中モードです 「読書」「睡眠」「仕事」など 活動内容や 時間帯に応じて 特定の集中モードを 設定することができます このような設定の場合 デバイスは 通知の表示と割り込みを フィルタリングします 集中モードの設定では 割り込み通知を 送信できる人や Appを選択できます 例えば 仕事という集中モードの間 メールやメッセージは 同僚からの直接連絡が来ると 通知を送ることができます そのため 通知要約と 集中モードは どのAppが 割り込み通知を送信できるか そしていつ送信できるかを コントロールします これにより 1日を通して 割り込みを より適切に 管理することができます このような管理コントロールを 切り抜ける機会が 通知にはありますが それは許可された場合のみです またコミュニケーション通知や 即時通知の場合 切り抜けることが可能です 次に 通知に伴う割り込みを Appで制御する 方法について説明します UserNotifications フレームワークの1つに 割り込みレベルのための 新しいAPIがあります サポートされているのは 4つの異なる 割り込みレベルです これらはPassive Active Time SensitiveとCriticalです 割り込みレベルが Passiveの通知は アラートや 画面の点灯がなく システムコントロールを 切り抜けることもありません これらの通知は 通知リストに サイレントに配信され 次にリストが表示されたときに 確認できます Passive 割り込みは 割り込みによって すぐに注意を払う必要はないが 最終的に確認されるべき通知に 使用すべきです 例えば お勧めの食事や 新しいエピソードの 紹介などです Active 割り込みは 通知で音や振動が流れたり 画面を光らせたりする 現時点で存在する動作と 似ています これらの通知は 通知のシステムコントロールを 切り抜けることはありません これはデフォルトの 割り込みレベルです Active 割り込みは システムが現在割り込みされない ように設定されている場合 割り込みをしない通知に 使用してください 例えば スポーツ速報や ライブストリームビデオ の通知などです Time Sensitive 割り込みは active 割り込みと同様に アラートを発します そして 許可されていれば 通知要約や 集中モードなどの システムコントロールを 切り抜けることができるため 特別な存在です これらの通知は すぐに注意を払う必要があり 積極的に割り込むことが 必要な場合にのみ 使用してください 例えば アカウントの セキュリティや 荷物の配送に関する通知 などがあります 最後に Critical割り込みレベルは iOS 14に存在する重大な通知 のサポートと同等です この割り込みレベルの通知は 積極的に警告を発し システムコントロール を切り抜け またデバイスのサイレントスイッチ も考慮しません この破壊的な動作のため critical割り込みには 承認されたエンタイトルメントが 引き続き必要です critical 通知の ユースケースとしては 荒天や地域の安全性に関する アラートなどがあります UserNotificationsフレームワーク の新しいAPIをサポートするため UNNotificationInterruptionLevelという 新しい列挙型があり それぞれのレベルが定義されています 通知リクエストのコンテンツ オブジェクトを設定する際に この割り込みレベルを 設定します この例ではPassive が 設定されています 割り込みレベルが 指定されていない場合は デフォルトのレベルが 使用されます プッシュ通知のペイロードには interruption-levelキーという 新しいキーと値のペア を提供します ここでも割り込みレベルを passiveに設定します この通知がデバイスに配信されると passiveに設定されているので どんな割り込みもなく ロック画面に表示されます 通知に関連した もう1つの割り込みの形は 読み上げです AirPods Proや AirPods Maxなどの 対応デバイスが 接続されていれば Siriが通知を 読み上げます iOS 14でこの読み上げ動作 を実現するには AllowAnnouncementオプション を要求するカテゴリに 通知を結びつける 必要がありました iOS 15では この カテゴリオプションの必要性が 非推奨なものとなりました サポートされたオーディオデバイス に接続されている間は あらゆる通知に対してアナウンスが サポートされます コミュニケーション通知や 即時通知は デフォルトでサポートされます CarPlayに接続している間は コミュニケーション通知が 自動的に読み上げられるように 設定でき よりシームレスな体験を 提供します 次に即時通知 について その設定方法を 説明します 即時通知とは 直ちに対応が必要な 通知のことです これらは重要であるため 許可されていれば 通知要約や集中モードなどの システムコントロールを 切り抜けることができます 即時通知の例としては 薬の服用に関する リマインダーの通知です この通知は 仕事 集中モードを 切り抜けて すぐさま目立つように 表示されます 即時通知を送る際には 信頼関係を保つことが 重要です 割り込みの性質を 利用しすぎず 適切な場合にのみ 利用してください 即時なアラートをオフにしたり Appからの すべての通知をオフにする オプションもあります 即時通知を 設定するには Xcodeで Appに対して 関連するケイパビリティを 有効にします 表示されている 通知リクエストに Time Sensitive割り込みレベル を設定します ローカル通知の場合 Time Sensitive 割り込みレベルは コンテンツオブジェクトに 設定されます プッシュペイロードの場合は interruption-levelキーに対し time-sensitiveを設定してください この通知は 配信されると 目立つように表示され 緊急性が強調されます コミュニケーション通知について 説明します こちらについてお伝えするために ケビンに交代します ケビン? ありがとう クリタート 私はNotificationsチームの エンジニア ケビンです 集中モードや通知要約を 切り抜けた 緊急の通知には 重要性があります 人からのコミュニケーションもまた 通知の配信を高める 必要があります このようなコミュニケーションは 電話やメッセージなど さまざまな形で行われます どのような通知が コミュニケーションなのか そしてそのコミュニケーションに 関連する人々を Appが伝えられるように する新しいAPIを紹介します コミュニケーション通知の重要性は ユーザーの判断により 決定されます Siriからの提案は これらの判断に役立ち 割り込みを許可すべき 重要な人物を提案します ユーザーが電話をかけたり FaceTimeに参加したり メッセージを送ったりと デバイスを操作するたびに Siriは集中モードや 通知要約を 誰が切り抜ける候補なのか を学習します iOS 15では コミュニケーション通知は より豊かなユーザー体験を 提供します 最も目立つのは 際立つアバターです タイトルとサブタイトルは 標準化されます タイトルには必ず送信者を入れ グループコミュニケーションの場合は サブタイトルに受信者を入れます タイトルとサブタイトルのテキスト はプラットフォームを問わず すべてのデバイス用にローカライズ され フォーマットされます 例えば Watchでは グループコミュニケーションで 受信者の名だけを表示する といった具合です Siriは HomePod AirPods CarPlayなどの 対応機器で コミュニケーション通知の内容を アナウンスするようになりました そしてSiriはこれらの コミュニケーション通知の 優先順位を決めるための 提案を行います Appの中の人は 連絡先の中の人と 関連付けられます これらの関連付けは 通知の際に 提案として表示されます ユーザーが 提案を確認すると あなたのAppで その人たちとのタスクに Siriショートカットが 使えるようになります 集中モードの設定では Siriが切り抜けられる関連人物を App内のコミュニケーションに 関連づけられた人も含めて 人物を提案します 何がコミュニケーションであり 何がそうではないかを判断するために この新しいAPIでは SiriKitのコールインテントと メッセージインテントを Notificationsに追加します インテントは 共通のタスク によって引き起こされます Appは 電話をかけたり メッセージを受け取ったりといった イベントが発生した際に これらのインテントをドネートします そこから Siriは ショートカットを提供し これらのインテントに 基づいて Appにいる人が 共有シートからメッセージを送ったり Siri経由でAppから電話を かけることを提案します この新しいAPIは このような同じ インテントを通知に関連付け さらにAppをSiriの エコシステムに統合します コミュニケーション通知にSiriKit インテントを使用することで App Siri システムUI全体の 一貫性を保ちながら Appのエンゲージメントを高める ことができます 関連するコミュニケーションを表す インテントは StartCallインテントと SendMessageインテントです NotificationContentProviding プロトコルが インテントと通知を 関連付けるメカニズムです NotificationContent オブジェクトでは コミュニケーション処理のために ContentProvidingインテントで 更新を呼び出します StartCallとSendMessage インテントはProvidingに準拠しています コミュニケーション通知は Apple Push Notificationサービス 経由で配信されます Appの NotificationServiceExtensionで SiriKitインテントを使って NotificationContentオブジェクト を更新する必要があります SiriKitインテントはデバイスの ローカルなものなので このようにローカルにサービスを 提供する必要があります 今回のサービスExtensionは まさに このようなケースに対応します リモート通知を配信する前に その内容を カスタマイズする場所です また ローカル通知のために メインのAppプロセスで 行うこともできます didReceive関数で プッシュペイロードの内容を インテントで更新します メッセージング通知の場合は SendMessageIntentを作成します また 通話関連の通知には StartCallIntentを 使用します Siriインテリジェンスに 何が起きているかを伝える インタラクションを 作成します 通知Extensionでは インタラクションの方向は 常にincomingです これは ユーザーに起こっている イベントであり ユーザーは着信を 受けています 次に インタラクションを ドネートする必要があります また ドネートは システムが 今後より良い提案をするためにも 役立ちます インテントを使って 通知コンテンツを更新します そして最後に 返されたインテントで contentHandlerを 呼び出します SiriがあなたのAppで起きた 出来事を学習するためには ドネートが必要です インタラクションの方向は 通知に対しては常にincomingです その他のSiriKitの使い方として インタクションの方向は メッセージ送信や電話をかけるなど デバイス上で開始したアクション に対してはoutgoingになります ContentProvidingに準拠した システムオブジェクトのみが サポートされます あなた自身のオブジェクトをこれに 準拠させないようにしてください コミュニケーション通知を 送信するには Appに対して Xcodeで コミュニケーション機能を 有効にします Info.plistのユーザー アクティビティタイプの配列に インテントタイプを追加するか Intents Extensionを実装することで コミュニケーションインテントを サポートします ユーザーがAppのアクションを フォアグラウンドで起こしたとき 例えばメッセージを作成した後に 送信ボタンを押したときなどに コミュニケーションインテントを ドネートします Siriはoutgoing方向のインテント を利用して 集中モードや 通知要約を切り抜けられる どの人を提案すべきかを より適切に判断します コンタクトの提案に関しても 同様です この機能では Siriはoutgoing方向のインテントの ドネートのみから学習するため スパム電話のような 関与していない人によって 連絡先が乱されること はありません コミュニケーションインテントを 適切に使用することは 合理的な通知体験の基本ですが いくつかの確認事項 があります Intent Personは SendMessageや StartCallインテント の構成要素です 各パラメータの入力によって より豊かで合理的な ユーザー体験が得られます Intent Personを使ってインテント を作成する場合も同様で 各パラメータの入力によって より豊かで合理的な ユーザー体験が得られます まだインテントを使っていない方は ぜひ使ってみてください インテントにより 通知 共有シート 連絡先 Spotlightなどで Appの可視度が向上します そして SiriKitを使って メッセージの送信や 通話の開始などのSiriショートカット を提供することができます 受信と送信の 両方のインタラクションに インテントをドネートする 習慣をつけましょう すでにoutgoing方向のインテントを ドネートしているかもしれません incoming方向のStartCallおよび SendMessageインテントのドネートを サービスExntensionで開始しましょう これは コミュニケーション通知体験の 基本となります もしあなたのAppがまだ 通知サービスExtensionを 使っていなければ 追加したほうが いいでしょう 最後に Content Providingプロトコルを使って 配信する各通知を コミュニケーションとして デコレートすることで まとめ上げましょう このセクションでは 視覚的なアップデートから コミュニケーション通知まで さまざまな 内容を紹介してきました いくつかのポイントを 確認します 新しいビジュアルの更新や 管理オプションに対して 通知がそれらとスマートに 機能するようにします 割り込みレベルを選ぶことで システムコントロールとの相乗効果 で通知がどのように割り込まれるか よりコントロールできるようになります コントロールの切り抜けや 読み上げなどの挙動や 目立った形での割り込みに 相当するような場合は 即時通知を使用します 通話とメッセージングのインテントを 実装してドネートすることで 通知と連動した 進化したコミュニケーション体験を コントロールの切り抜けと 読み上げといった 動作とともに得ることができます 通知を使った新しく 素晴らしい体験を提供されるのを 楽しみにしています 素晴らしいWWDCを お過ごしください! ♪
-
-
1:57 - Notification Action Icons
// Setting up notification actions with icons let likeActionIcon = UNNotificationActionIcon(systemImageName: "hand.thumbsup") let likeAction = UNNotificationAction(identifier: "like-action", title: "Like", options: [], icon: likeActionIcon) let commentActionIcon = UNNotificationActionIcon(templateImageName: "text.bubble") let commentAction = UNTextInputNotificationAction(identifier: "comment-action", title: "Comment", options: [], icon: commentActionIcon, textInputButtonTitle: "Post", textInputPlaceholder: "Type here…") let category = UNNotificationCategory(identifier: "update-actions", actions: [likeAction, commentAction], intentIdentifiers: [], options: [])
-
8:19 - Notification Interruption Levels
// Interruption levels let enum UNNotificationInterruptionLevel : Int { case passive = 0 case active = 1 case timeSensitive = 2 case critical = 3 public static var `default`: UNNotificationInterruptionLevel { get } }
-
8:31 - Passive Notification: Local
// Interruption levels // Local notification import UserNotifications let content = UNMutableNotificationContent() content.title = "Passive" content.body = "I’m a passive notification, so I won’t interrupt you." content.interruptionLevel = .passive let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false) let request = UNNotificationRequest(identifier: "passive-request-example", content: content, trigger: trigger)
-
8:47 - Passive Notification: Push
// Interruption levels // Push notification { "aps" : { "alert" : { "title" : "Passive", "body" : "I’m a passive notification, so I won’t interrupt you." } "interruption-level" : "passive" } }
-
11:13 - Time Sensitive Notification: Local
// Time Sensitive // Local notification let content = UNMutableNotificationContent() content.title = "Urgent" content.body = "Your account requires attention." content.interruptionLevel = .timeSensitive let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0, repeats: false) let request = UNNotificationRequest(identifier: "time-sensitive—example", content: content, trigger: trigger)
-
11:20 - Time Sensitive Notification: Push
// Time Sensitive // Push notification { "aps" : { "alert" : { "title" : "Urgent", "body" : "Your account requires attention." } "interruption-level" : "time-sensitive" } }
-
15:20 - Notification Content Providing
// New UserNotifications API @available(macOS 12.0, *) public protocol UNNotificationContentProviding : NSObjectProtocol {} open class UNNotificationContent : NSObject, NSCopying, NSMutableCopying, NSSecureCoding { // ... @available(macOS 12.0, *) open func updating(from provider: UNNotificationContentProviding) throws -> UNNotificationContent // ... }
-
16:08 - Communication Notification: Incoming message
// Create a messaging notification // In UNNotificationServiceExtension subclass func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { let incomingMessageIntent: INSendMessageIntent = // ... let interaction = INInteraction(intent: incomingMessageIntent, response: nil) interaction.direction = .incoming interaction.donate(completion: nil) do { let messageContent = try request.content.updating(from: incomingMessageIntent) contentHandler(messageContent) } catch { // Handle error } }
-
16:20 - Communication Notification: Incoming call
// Create a call notification // In UNNotificationServiceExtension subclass func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { let incomingCallIntent: INStartCallIntent = // ... let interaction = INInteraction(intent: incomingCallIntent, response: nil) interaction.direction = .incoming interaction.donate(completion: nil) do { let callContent = try request.content.updating(from: incomingCallIntent) contentHandler(callContent) } catch { // Handle error } }
-
17:48 - Communication Notification: Outgoing message
func sendMessage(...) { // ... let intent: INSendMessageIntent = // ... let interaction = INInteraction(intent: intent, response: nil) interaction.direction = .outgoing interaction.donate(completion: nil) }
-
18:29 - Communication Notification: INPerson
// Create INPerson let person = INPerson(personHandle: handle, nameComponents: nameComponents, displayName: displayName, image: image, contactIdentifier: contactIdentifier, customIdentifier: customIdentifier, aliases: nil, suggestionType: suggestionType)
-
18:43 - Communication Notification: INSendMessageIntent
// Create INSendMessageIntent // In your notification service extension let intent = INSendMessageIntent(recipients: [person2], outgoingMessageType: .outgoingMessageText, content: content, speakableGroupName: speakableGroupName, conversationIdentifier: conversationIdentifier, serviceName: serviceName, sender: person1, attachments: nil) let interaction = INInteraction(intent: intent, response: nil) interaction.direction = .incoming
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。