Notification Service Extension: iOS에서 표시 전 콘텐츠 처리란

저자: IT Sectr 게시일: 2026-03-21 읽는 시간: 8 분

Notification Service Extension은 사용자에게 표시되기 전에 푸시 알림을 가로채서 콘텐츠를 수정할 수 있게 해주는 iOS 확장입니다. 이 확장은 암호화된 데이터를 복호화하고, 미디어 첨부 파일을 다운로드하고, 텍스트를 변경하거나 사용자 정의 필드를 추가할 수 있습니다. Apple Developer, 2025에 따르면, Notification Service Extension은 백그라운드에서 작업을 완료하는 데 최대 30초까지 사용할 수 있습니다.

핵심 포인트

  • Notification Service Extension — 표시 전에 푸시 알림을 처리하기 위한 iOS 확장입니다.
  • 확장은 UNNotificationServiceExtension에서 상속받고 didReceive 메서드를 구현합니다.
  • 데이터 다운로드 및 처리를 위해 최대 30초의 백그라운드 실행이 가능합니다.
  • 주요 사용 사례: 페이로드 복호화, 이미지 및 비디오 다운로드, 콘텐츠 유효성 검사.
  • 확장은 알림 표시를 지연시키거나 contentHandler를 통해 완전히 취소할 수 있습니다.

Notification Service Extension이란

Notification Service Extension은 푸시 알림이 표시되기 전에 실행되는 iOS 앱 확장입니다. 서버가 최소 페이로드를 보내고 확장이 이미지 다운로드, 데이터 복호화, 텍스트 대체 등의 콘텐츠를 추가할 수 있습니다. 사용자는 이미 처리된 알림을 보게 됩니다.

작동 방식

iOS가 푸시 알림을 수신하면 시스템은 앱에 확장이 있는지 확인합니다. 확장이 등록되어 있으면 iOS가 백그라운드 프로세스에서 실행하고 didReceive(_:withContentHandler:) 메서드를 통해 알림 콘텐츠를 전달합니다. 확장은 콘텐츠를 처리하고 수정된 콘텐츠로 contentHandler를 호출합니다. 확장이 30초 이내에 완료되지 않으면 시스템이 원래 알림을 표시합니다.

Service Extension을 사용해야 하는 경우

Service Extension은 알림 콘텐츠가 기기에서 처리를 필요로 하는 시나리오에서 필요합니다. 안전한 통신: 서버가 암호화된 페이로드를 보내고 확장이 로컬에서 복호화합니다. 리치 미디어 알림: 서버가 이미지 URL을 보내고 확장이 다운로드하여 첨부합니다. 동적 현지화: 확장이 기기 언어로 텍스트를 대체합니다.

시나리오확장 없음확장 있음
이미지지원되지 않음다운로드 및 표시
암호화서버가 키를 보유기기에서 복호화
텍스트서버에서 고정동적 대체
검증확인되지 않음악성 알림 취소

제한 사항 및 실행 시간

Notification Service Extension은 제한된 환경에서 실행됩니다. 최대 실행 시간은 30초입니다. 확장은 (App Group을 제외한) 기본 앱 저장소에 접근할 수 없습니다. 확장 크기는 50MB로 제한됩니다. 시간이 초과되면 시스템이 원래 콘텐츠로 contentHandler를 호출하고 모든 변경 사항이 손실됩니다.

확장 생성 및 Info.plist 구성

Xcode에서 Notification Service Extension은 Notification Service Extension 유형의 새 target을 생성하여 추가됩니다. Xcode는 UNNotificationServiceExtension에서 상속받는 템플릿 NotificationService 클래스를 생성하며, didReceive와 serviceExtensionTimeWillExpire의 두 가지 메서드를 제공합니다.

프로젝트에 target 추가

Xcode에서 File → New → Target → Notification Service Extension을 선택합니다. 이름(예: PushNotificationService)을 입력하고 Swift 언어를 선택합니다. target이 기본 앱에 추가되고 올바른 서명이 있는지 확인합니다. 생성 후 NotificationService.swift 클래스가 기본 구현과 함께 생성됩니다.

확장 Info.plist 구조

확장의 Info.plist에는 NSExtension 키와 하위 키 NSExtensionPointIdentifier(com.apple.usernotifications.service) 및 NSExtensionPrincipalClass(컨트롤러 이름)가 포함됩니다. 추가로 확장 활성화 규칙이 있는 NSExtensionAttributes를 지정할 수 있습니다. Xcode가 이러한 설정을 자동으로 생성합니다.

기본 확장 예제

기본 구현은 didReceive를 재정의하고, 알림 콘텐츠를 수정하고 contentHandler를 호출합니다. 처리 시간이 너무 오래 걸리면 serviceExtensionTimeWillExpire가 호출되며, 현재 상태로 작업을 완료해야 합니다.

swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(
        request: UNNotificationRequest,
        withContentHandler handler: @escaping (UNNotificationContent) -> Void
    ) {
        contentHandler = handler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            bestAttemptContent.title = "[처리됨] \(bestAttemptContent.title)"
            contentHandler?(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler,
           let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

암호화된 페이로드 복호화

Service Extension의 주요 용도 중 하나는 기기에서 알림 콘텐츠를 복호화하는 것입니다. 서버가 암호화된 페이로드를 보내고 확장이 Keychain 또는 App Group에 저장된 키를 사용하여 복호화합니다. 이렇게 하면 전송 중에 콘텐츠를 가로챌 수 없습니다.

안전한 전달 아키텍처

서버는 대칭 키(AES-256)를 사용하여 알림 본문을 암호화합니다. 암호화 키는 클라이언트와 서버 간에 사전 합의됩니다. 확장은 페이로드의 data 필드에서 암호화된 문자열을 받아 복호화한 후 알림 필드에 대체합니다. 사용자 키는 인증 후 Keychain에서 가져올 수 있습니다.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    guard let content = request.content.mutableCopy()
        as? UNMutableNotificationContent else {
        handler(request.content)
        return
    }

    guard let encryptedData = content.userInfo["encrypted_data"]
        as? String else {
        handler(content)
        return
    }

    let decrypted = CryptoService.decrypt(encryptedData)
    content.body = decrypted.body
    content.title = decrypted.title
    handler(content)
}

안전한 키 저장

복호화 키는 확장 코드나 NSUserDefaults에 저장해서는 안 됩니다. 앱과 확장 모두 키를 읽을 수 있도록 App Group을 통해 접근하는 iOS Keychain을 사용하세요. 클라이언트에서 키 생성을 위해 AES-256-GCM 알고리즘과 함께 Security.framework를 사용하세요.

미디어 첨부 파일 다운로드 및 첨부

Notification Service Extension의 가장 일반적인 용도는 알림에 표시할 이미지, GIF, 비디오를 다운로드하는 것입니다. 서버가 미디어 파일 URL을 보내고 확장이 다운로드하여 임시 디렉토리에 저장하고 UNNotificationAttachment를 생성합니다.

미디어 다운로드 및 첨부 프로세스

확장은 알림 페이로드 필드에서 이미지 URL을 받습니다. URLSession을 사용하여 확장은 파일을 임시 디렉토리에 다운로드합니다. 다운로드가 완료되면 로컬 URL로 UNNotificationAttachment가 생성됩니다. 첨부 파일은 수정된 콘텐츠에 전달됩니다. iOS가 자동으로 표준 인터페이스 또는 Notification Content Extension에서 이미지를 표시합니다.

swift
private func downloadAndAttachMedia(
    content: UNMutableNotificationContent,
    mediaUrl: String,
    handler: @escaping (UNNotificationContent) -> Void
) {
    guard let url = URL(string: mediaUrl) else {
        handler(content)
        return
    }

    let task = URLSession.shared.downloadTask(with: url) { localUrl, _, error in
        guard let localUrl = localUrl, error == nil else {
            handler(content)
            return
        }

        let attachment = try? UNNotificationAttachment(
            identifier: "media",
            url: localUrl,
            options: nil
        )

        if let attachment = attachment {
            content.attachments = [attachment]
        }
        handler(content)
    }
    task.resume()
}

지원되는 미디어 형식

iOS는 알림 표시를 위해 다음 형식을 지원합니다: JPEG, PNG, GIF(정적), 최대 50MB의 MPEG-4 비디오. 오디오 파일의 경우 MP3, AAC, ALAC가 지원됩니다. 중요: 모든 미디어 파일은 30초 제한 내에 다운로드되어야 합니다. 큰 파일의 경우 서버 측 자르기 또는 점진적 로딩을 권장합니다.

시간 관리 및 폴백 시나리오

30초 제한 관리는 Notification Service Extension 개발 시 핵심 작업입니다. 확장이 제시간에 처리를 완료하지 못하면 시스템이 serviceExtensionTimeWillExpire를 호출하고 원래 콘텐츠를 표시합니다. 각 처리 유형에 대해 폴백 시나리오를 제공해야 합니다.

우선순위 전략

작업을 우선순위에 따라 분할합니다. 먼저 중요한 수정(복호화, 기본 현지화)을 수행합니다. 선택적 개선(이미지 다운로드, 텍스트 보강)은 나중에 수행합니다. 네트워크 요청에 타임아웃이 있는 URLSession을 사용하여 전체 제한을 단일 작업에 소비하지 않도록 합니다.

오류 시 폴백

이미지 다운로드가 실패하거나 페이로드 복호화가 오류를 반환하면 확장은 원래 콘텐츠로 contentHandler를 호출해야 합니다. contentHandler를 호출하지 않고 확장을 종료하지 마세요. 알림 손실이 발생합니다. 안전한 폴백은 항상 확장 코드에 포함되어야 합니다.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    let content = (request.content.mutableCopy()
        as? UNMutableNotificationContent) ?? request.content

    // 중요 작업: 복호화
    var decryptedContent = tryDecryptPayload(content)

    // 선택 작업: 미디어
    guard let mediaUrl = decryptedContent.userInfo["media_url"]
        as? String else {
        handler(decryptedContent)
        return
    }

    downloadAndAttachMedia(
        content: decryptedContent,
        mediaUrl: mediaUrl,
        handler: handler
    )
}

확장 테스트

Notification Service Extension을 테스트하려면 Xcode를 사용하세요: 확장 target을 선택하고, 시뮬레이터에서 실행하고, 터미널 또는 Firebase Console을 통해 푸시 알림을 보냅니다. os_log를 사용하여 각 처리 단계를 기록하면 타이밍 및 다운로드 문제를 진단하는 데 도움이 됩니다.

자주 묻는 질문

확장이 30초 이내에 완료되지 않으면 어떻게 되나요?

시스템이 serviceExtensionTimeWillExpire를 호출한 후 원래 알림을 변경 없이 표시합니다. 다운로드된 모든 파일과 수정 사항은 폐기됩니다.

확장에서 알림 표시를 취소할 수 있나요?

네, 빈 콘텐츠(빈 필드의 UNNotificationContent)로 contentHandler를 호출하면 알림이 표시되지 않습니다. 이는 스팸 알림이나 잘못된 데이터를 필터링하는 데 사용됩니다.

미디어 다운로드를 위한 인증 토큰을 어떻게 전달하나요?

토큰은 알림 페이로드의 userInfo에 전달하거나 App Group을 통해 Keychain에서 가져올 수 있습니다. 확장 UserDefaults에 토큰을 저장하는 것은 권장되지 않습니다.

확장에 특별한 인증서 구성이 필요한가요?

확장은 기본 앱과 동일한 개발자 인증서로 서명되어야 합니다. 프로덕션의 경우 Push Notifications 기능이 활성화된 프로덕션 인증서가 필요합니다.

실제 기기에서 확장을 디버그하려면 어떻게 하나요?

기기를 Xcode에 연결하고, 실행 스킴에서 확장 target을 선택하고, Firebase Console을 통해 푸시 알림을 보냅니다. 확장의 중단점은 기본 앱과 동일하게 작동합니다.

요약

  • Notification Service Extension — 표시 전에 푸시 알림을 백그라운드에서 처리하기 위한 iOS 확장입니다.
  • 최대 실행 시간은 30초이며, 이후 시스템이 원래 콘텐츠를 표시합니다.
  • 주요 사용 사례: 페이로드 복호화, 미디어 다운로드, 콘텐츠 검증 및 현지화.
  • 확장은 UNNotificationServiceExtension에서 didReceive 및 serviceExtensionTimeWillExpire 메서드와 함께 상속받습니다.
  • 미디어 다운로드에는 URLSession을, 키 저장에는 iOS Keychain을 사용하세요.
  • 항상 폴백을 제공하세요 — 오류 시 원래 콘텐츠로 contentHandler를 호출합니다.
  • 알림을 완전히 제어하려면 Service Extension을 Content Extension과 결합하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기