Notification Extensionは、プッシュ通知をユーザーに表示する前にその内容と外観を変更できるiOSのメカニズムです。拡張機能はオペレーティングシステム側で別プロセスとして動作し、UNNotificationServiceExtensionが受信コンテンツを処理し、UNNotificationContentExtensionがインターフェースを管理します。Apple Developer Documentation、2026によると、Service Extensionは通知表示前にタスクを実行するために最大30秒与えられます。この制限は添付ファイルのダウンロードやデータの復号化において重要です。
重要ポイント
Notification Extensionは、プッシュ通知の標準動作を拡張し、コンテンツの変更とインターフェースのカスタマイズを可能にするiOSソフトウェアコンポーネントです。システムが標準形式で表示する通常の通知とは異なり、拡張機能は開発者が表示前にコンテンツに影響を与え、独自のユーザーインターフェースを作成することを可能にします。
Appleは異なる目的のために2種類のNotification Extensionを提供しています。UNNotificationServiceExtensionは受信ペイロードの処理を担当し、UNNotificationContentExtensionは表示を管理します。Service Extensionは通知が表示される前に実行され、Apple Developer Documentationによると最大30秒の制限された実行時間があります。Content Extensionはユーザーが通知と対話した後にアクティブになり、カスタムビューを表示します。
標準のiOSプッシュ通知は、JSONペイロードのalert、title、subtitleフィールドに基づいてシステムによって自動的に表示されます。Notification Extensionは制御をインターセプトします。Service Extensionは生のペイロードを受け取り、それを変更して表示のためにシステムに渡します。Content Extensionは標準のバナーを任意の制御要素を持つカスタムインターフェースに置き換えます。
デバイスがmutable-content:1キーを持つプッシュ通知を受信すると、システムは別のプロセスでService Extensionを起動します。拡張機能のプロセスはメインアプリケーションから隔離され、50 MBのメモリ制限を持つ独自のサンドボックスを持ちます。処理が完了すると、拡張機能はcompletion handlerを呼び出し、変更されたUNNotificationContentを表示のためにシステムに渡します。
UNNotificationServiceExtensionは、ユーザーに表示する前にプログラムでプッシュ通知を変更するための主要なツールです。拡張機能は、ペイロードにmutable-content:1フラグが設定された通知を受信すると自動的にアクティブになります。30秒以内に、拡張機能はメディア添付ファイルのダウンロード、テキストの変更、暗号化データの復号化、コンテンツの強化を行うことができます。
拡張機能はUNNotificationServiceExtensionプロトコルから2つの主要なメソッドを実装します。didReceiveメソッドは生のUNNotificationRequestを持つ受信リクエストを受け取り、新しいUNNotificationContentでcompletion handlerを通じて変更を許可します。serviceExtensionTimeWillExpireメソッドはタイムアウトの1秒前にシステムによって呼び出されます。この中で処理を完了し、現在の(おそらく部分的な)結果を渡す必要があります。
サーバーがカスタムフィールドに画像URLを含むプッシュを送信するシナリオを考えます。Service Extensionはこの画像をネットワーク経由でダウンロードし、UNNotificationAttachmentを作成してコンテンツに追加します。UNNotificationAttachmentはローカルの画像、動画、または音声ファイルを受け入れ、自動的に拡張機能のサンドボックスにコピーします。添付ファイルを作成した後、拡張機能は更新されたコンテンツをシステムに渡します。
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void) {
let userInfo = request.content.userInfo
guard let imageURL = URL(string: userInfo["image-url"] as! String)
else { contentHandler(request.content); return }
let attachment = try! UNNotificationAttachment(
identifier: "image", url: imageURL,
options: [UNNotificationAttachmentOptionsTypeHintKey: "jpg"])
let modifiedContent = request.content.mutableCopy()
as! UNMutableNotificationContent
modifiedContent.attachments = [attachment]
contentHandler(modifiedContent)
}
override func serviceExtensionTimeWillExpire() {
contentHandler?(bestAttemptContent ?? request.content)
}
}
同じ添付ファイルを持つ通知が頻繁に送信される場合、ダウンロードしたファイルをデバイスにキャッシュすることをお勧めします。FileManagerは、起動間で永続化される拡張機能のキャッシュディレクトリへのアクセスを提供します。これにより、後続の通知の処理時間が短縮され、ネットワーク負荷が軽減されます。Appleによると、キャッシュにより処理時間を完全なダウンロードの代わりに2〜5秒に短縮できます。
UNNotificationContentExtensionは、標準の通知バナーをInterface BuilderまたはSwiftUIで作成されたカスタムインターフェースに置き換えることを可能にします。拡張機能はユーザーが通知に対してアクション(タップ、スワイプダウン、3D Touch)を実行したときにアクティブになります。Content ExtensionはService Extensionによって既に処理されたコンテンツを受け取り、カスタムビューに表示します。
各Content ExtensionはInfo.plistを介して1つ以上の通知カテゴリにリンクされます。カテゴリはサーバー側でAPNSペイロードのcategoryフィールドによって定義されます。システムは受信した通知のカテゴリに基づいて適切な拡張機能を自動的に選択します。インターフェースは標準のUIKitコンポーネントまたはSwiftUI Viewを使用してストーリーボードを介して構築されます。
Content ExtensionはUNNotificationActionで定義されたカスタムボタンとタップハンドラーをサポートします。UNNotificationActionはカテゴリ登録段階で作成され、UNTextInputNotificationActionを介してテキスト入力をサポートできます。ユーザーがボタンを押すと、拡張機能はアクション識別子とともにdidReceiveコールバックを受け取り、対応するロジック(URLを開く、サーバーにリクエストを送信する、インターフェースを更新する)を実行できます。
Content Extensionは独自のランループと約50 MBのメモリ制限を持つ隔離されたプロセスで実行されます。拡張機能のパフォーマンスは、システムのウォッチドッグが制限を超えるとプロセスを終了するため重要です。Content Extension内での重い計算、大きな画像の読み込み、長時間のネットワークリクエストは避けることをお勧めします。
UNNotificationAttachmentは、プッシュ通知にメディアファイル(画像、動画、音声、GIF)を追加するオブジェクトです。添付ファイルは、拡張機能のサンドボックス内にあるローカルファイルURLから作成されます。添付ファイルの最大サイズは10 MBを超えてはなりません。超えた場合、システムは作成時に添付ファイルを拒否します。
Appleはメディア添付ファイルに対して限られた形式のセットをサポートしています。画像 — JPEG、PNG、GIF(アニメーションを含む)、TIFF。動画 — MPEG、MP4、MOV、最大30秒の長さ。音声 — MP3、AAC、WAV、CAF。各形式について、UNNotificationAttachmentOptionsTypeHintKeyを介してタイプを指定でき、システムがファイルを正しく処理するのに役立ちます。
プッシュペイロードにはファイル自体ではなくURLのみが含まれるため、添付ファイルのダウンロードはService Extension内で行う必要があります。最大ダウンロード時間は30秒に制限されているため、最小限の設定でURLSessionを使用し、弱い信号ではダウンロードを無効にすることをお勧めします。添付ファイルが時間内に読み込まれない場合、通知はメディアなしで表示されます。これがシステムのデフォルト動作です。
画像をダウンロードして保存し、通知に追加する完全なNotification Extensionの例を見てみましょう。NotificationServiceはUNNotificationServiceExtensionを継承し、didReceiveメソッドをオーバーライドします。この例では、オプションフィールドの処理、添付ファイルの作成、変更されたコンテンツでのcompletion handlerの呼び出しを示しています。
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
self.bestAttemptContent =
(request.content.mutableCopy()
as! UNMutableNotificationContent)
guard let attachmentURLString =
bestAttemptContent?.userInfo["attachment-url"] as? String,
let url = URL(string: attachmentURLString)
else {
contentHandler(request.content)
return
}
URLSession.shared.downloadTask(with: url) {
[weak self] localURL, _, error in
guard let localURL = localURL, error == nil
else {
contentHandler(request.content)
return
}
let attachment = try! UNNotificationAttachment(
identifier: "media", url: localURL)
self?.bestAttemptContent?.attachments = [attachment]
contentHandler(self?.bestAttemptContent
?? request.content)
}.resume()
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}
拡張機能を正しく動作させるには、Info.plistで通知カテゴリを登録する必要があります。NSExtensionPointIdentifierキーはService Extensionの場合はcom.apple.usernotifications.service、Content Extensionの場合はcom.apple.usernotifications.contentに設定します。カテゴリはAppDelegateでアプリ起動時にUNUserNotificationCenterを介して定義され、拡張機能はペイロードに一致するカテゴリを持つ通知に対してのみアクティブになります。
よくある質問
Service Extensionは通知表示前にコンテンツを変更します。メディアの追加、テキストの変更、データの復号化を行います。Content Extensionはユーザー操作後に通知インターフェースをカスタムインターフェースに置き換えます。Service Extensionは表示前に動作し、Content Extensionは表示後に動作します。
システムはdidReceiveでのコード実行に30秒を割り当てます。この時間内に処理が完了しない場合、serviceExtensionTimeWillExpireが呼び出され、現在の結果を渡す必要があります。添付ファイルのダウンロードを考慮して10〜15秒以内に収めることをお勧めします。
はい、SwiftUIはiOS 16以降のContent Extensionでサポートされています。ViewはUIHostingControllerにラップされてストーリーボードに追加されます。ただし、メモリ制限のため、SwiftUIは最小限の要素を持つシンプルなインターフェースにのみ使用することをお勧めします。
ダウンロードエラーまたはタイムアウトの場合、添付ファイルなしで元のコンテンツをcompletion handlerに渡すだけです。システムは通知をメディアなしで標準形式で表示します。診断のためにOSLogでエラーを記録しますが、通知の表示をブロックしないでください。
拡張機能は約50 MBの制限を持つ隔離されたプロセスで実行されます。制限を超えると、システムはウォッチドッグを介してプロセスを強制終了します。大きなファイルの読み込み、メモリ内の画像の保存、URLSessionでのリークを避けてください。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。