메인 콘텐츠로 건너뛰기
Notification Service Extension을 사용하면 푸시 알림이 사용자에게 표시되기 전에 가로채고 수정할 수 있습니다.
OSNotification 클래스를 통해 OneSignal에서 전송된 푸시 알림의 데이터에 액세스할 수 있습니다.

Android Notification Service Extension

사용자에게 표시되기 전에 알림을 처리할 수 있습니다. 일반적인 사용 사례는 다음과 같습니다:
  • 알림 표시 여부와 관계없이 백그라운드에서 데이터 수신
  • 사용자 지정 강조 색상, 진동 패턴 또는 기타 NotificationCompat 옵션과 같은 클라이언트 측 앱 로직에 따라 특정 알림 설정 재정의
자세한 내용은 Android의 NotificationCompat 옵션 문서를 참조하세요.

1단계: Service Extension용 클래스 생성

INotificationServiceExtension을 확장하는 클래스를 만들고 onNotificationReceived 메서드를 구현합니다. onNotificationReceived 메서드 매개변수는 INotificationReceivedEvent 유형의 event입니다.
package your.package.name

import androidx.annotation.Keep;
import com.onesignal.notifications.IActionButton;
import com.onesignal.notifications.IDisplayableMutableNotification;
import com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;

@Keep // Keep is required to prevent minification from renaming or removing your class
public class NotificationServiceExtension implements INotificationServiceExtension {

     @Override
     public void onNotificationReceived(INotificationReceivedEvent event) {
        IDisplayableMutableNotification notification = event.getNotification();

        if (notification.getActionButtons() != null) {
           for (IActionButton button : notification.getActionButtons()) {
              // you can modify your action buttons here
           }
        }

     /* Add customizations here. See examples below for additional methods to modify the notification*/
     }
}

@Keep 어노테이션은 ProGuard/R8이 축소 과정에서 INotificationServiceExtension을 구현하는 클래스의 이름을 변경하거나 제거하지 못하도록 방지합니다.

2단계: 알림 사용자 지정

다음은 위의 템플릿 Notification Service Extension 클래스에서 구현할 수 있는 일반적인 예시입니다.
event.preventDefault()를 호출하면 알림이 자동으로 표시되지 않으며, 수동으로 표시하거나 완전히 표시하지 않도록 결정할 수 있습니다.
event.preventDefault();

//Do some async work, then decide to show or dismiss
new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ignored) {}

    //Manually show the notification
    event.getNotification().display();
}).start();
event.preventDefault()를 호출한 후 display()를 호출하지 않으면 알림이 아무런 경고 없이 자동으로 삭제됩니다. 자세한 내용은 중복 알림을 참조하세요.

3단계: AndroidManifest.xml에 Service Extension 추가

AndroidManifest.xml 파일의 application 태그 내에 클래스 이름과 값을 meta-data로 추가합니다. “unused” 경고는 무시하세요.
XML
<application>
  <meta-data
    android:name="com.onesignal.NotificationServiceExtension"
    android:value="com.onesignal.example.NotificationServiceExtension" />
</application>
com.onesignal.example.NotificationServiceExtension을 클래스의 정규화된 이름으로 교체하세요.

iOS Notification Service Extension

UNNotificationServiceExtension을 사용하면 푸시 알림이 사용자에게 표시되기 전에 콘텐츠를 수정할 수 있으며 다음과 같은 다른 중요한 기능에 필요합니다: 앱에 대한 Mobile SDK 설정 지침을 따랐다면 Extension이 이미 구성되어 있을 것입니다. 이 섹션에서는 OneSignal 알림 페이로드 데이터에 액세스하는 방법과 발생할 수 있는 문제를 해결하는 방법을 설명합니다.

iOS 푸시 페이로드 가져오기

didReceive(_:withContentHandler:) 오버라이드는 OneSignalExtension.didReceiveNotificationExtensionRequest를 호출합니다. 이 메서드가 호출되기 전에 bestAttemptContent를 읽거나 수정할 수 있습니다. 이 예시에서는 다음 데이터와 함께 알림을 보냅니다:
JSON
{
  "app_id": "YOUR_APP_ID",
  "target_channel": "push",
  "headings": {"en": "The message title"},
  "contents": {"en": "The message contents"},
  "data":{
    "additional_data_key_1":"value_1",
    "additional_data_key_2":"value_2"
    },
  "include_subscription_ids": ["SUBSCRIPTION_ID_1"]
}
userInfocustom 딕셔너리 내 a 키를 통해 OneSignalNotificationServiceExtension 내에서 이 추가 data에 액세스합니다:
if let bestAttemptContent = bestAttemptContent {

    if let customData = bestAttemptContent.userInfo["custom"] as? [String: Any],
       let additionalData = customData["a"] as? [String: Any] {

        if let jsonData = try? JSONSerialization.data(withJSONObject: additionalData, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            print("The additionalData dictionary in JSON format:\n\(jsonString)")
        } else {
            print("Failed to convert additionalData to JSON format.")
        }
    }

    if let messageData = bestAttemptContent.userInfo["aps"] as? [String: Any],
       let apsData = messageData["alert"] as? [String: Any],
       let body = apsData["body"] as? String,
       let title = apsData["title"] as? String {
        print("The message contents is: \(body), message headings is: \(title)")
    } else {
        print("Unable to retrieve apsData")
    }

    OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest,
                                                              with: bestAttemptContent,
                                                              withContentHandler: self.contentHandler)
}
콘솔 출력 예시:
The additionalData dictionary in JSON format:
{
  "additional_data_key_1" : "value_1",
  "additional_data_key_2" : "value_2"
}
The message contents is: The message contents, message headings is: The message title

iOS Notification Service Extension 문제 해결

이 가이드는 iOS 모바일 앱에서 이미지, 액션 버튼 또는 확인된 전달이 표시되지 않는 문제를 디버깅하기 위한 것입니다.

Xcode 설정 확인

General > Targets에서 main app targetOneSignalNotificationServiceExtension 타겟이 동일하고 올바른지 확인하세요:
  • Supported Destinations
  • Minimum Deployment(iOS 14.5 이상)
Cocoapods를 사용하는 경우 Podfile의 main target과 일치하는지 확인하여 빌드 오류를 방지하세요.
Xcode General tab showing Supported Destinations and Minimum Deployment for the main app target
Xcode General tab showing Supported Destinations and Minimum Deployment for the notification service extension target
OneSignalNotificationServiceExtension > Info 탭을 계속 진행하여 NSExtension 키를 확장합니다. 다음이 표시되는지 확인하세요:
XML
 <dict>
   <key>NSExtensionPointIdentifier</key>
   <string>com.apple.usernotifications.service</string>
   <key>NSExtensionPrincipalClass</key>
   <string>$(PRODUCT_MODULE_NAME).NotificationService</string>
 </dict>
예시:
Xcode Info tab showing the NSExtension dictionary with NSExtensionPointIdentifier and NSExtensionPrincipalClass keys
Objective-C를 사용하는 경우 $(PRODUCT_MODULE_NAME).NotificationService 대신 NotificationService를 사용하세요.

”Copy only when installing” 끄기

main app target > Build Phases > Embed App Extensions를 선택합니다. “Copy only when installing”이 선택되지 않았는지 확인하세요. 선택되어 있으면 선택 해제하세요:
Xcode Build Phases tab showing Embed App Extensions with Copy only when installing unchecked

iOS Notification Service Extension 디버깅

다음 단계에 따라 Notification Service Extension이 올바르게 설정되었는지 확인하세요.

1. OneSignalNotificationServiceExtension 코드 업데이트

NotificationService.m 또는 NotificationService.swift를 열고 전체 파일 내용을 아래 코드로 바꾸세요. Extension이 실행 중인지 확인하는 데 도움이 되는 로깅을 추가합니다. YOUR_BUNDLE_ID를 실제 Bundle ID로 바꾸세요.
import UserNotifications
import OneSignalExtension
import os.log

class NotificationService: UNNotificationServiceExtension {

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

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

        let userInfo = request.content.userInfo
        let custom = userInfo["custom"]
        print("Running NotificationServiceExtension: userInfo = \(userInfo.description)")
        print("Running NotificationServiceExtension: custom = \(custom.debugDescription)")
        os_log("%{public}@", log: OSLog(subsystem: "YOUR_BUNDLE_ID", category: "OneSignalNotificationServiceExtension"), type: OSLogType.debug, userInfo.debugDescription)

        if let bestAttemptContent = bestAttemptContent {
            print("Running NotificationServiceExtension")
            bestAttemptContent.body = "[Modified] " + bestAttemptContent.body

            OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            OneSignalExtension.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }

}

디버그 로그 유형은 Console에서 Action > Include Debug Messages를 통해 활성화해야 합니다.

2. Active Scheme 변경

Active Scheme을 OneSignalNotificationServiceExtension으로 설정합니다.
Xcode toolbar showing the active scheme dropdown set to OneSignalNotificationServiceExtension

3. 프로젝트 빌드 및 실행

Xcode에서 실제 장치에서 프로젝트를 빌드하고 실행합니다.

4. Console 열기

Xcode에서 Window > Devices and Simulators를 선택합니다.
Xcode menu showing the Window dropdown with Devices and Simulators selected
연결된 장치가 표시되어야 합니다. Open Console을 선택합니다.
Xcode Devices window showing the Open Console button for a connected device

5. Console 확인

Console에서:
  1. Action > Include Debug Messages 선택
  2. CATEGORY로 OneSignalNotificationServiceExtension 검색
  3. Start 선택
macOS Console app showing the category filter and Start button for debugging the notification service extension
이 장치에 메시지가 포함된 알림을 보냅니다(푸시 알림 API에서 보내는 경우 contents 속성 사용). 이 예시에서 페이로드는 다음과 같습니다:
cURL
curl --request POST \
 --url 'https://api.onesignal.com/notifications' \
 --header 'Authorization: Key YOUR_API_KEY' \
 --header 'accept: application/json' \
 --header 'content-type: application/json' \
 --data '
{
"app_id": "YOUR_APP_ID",
"target_channel": "push",
"headings": {"en": "The message title"},
"contents": {"en": "The message contents"},
"data":{"additional_data_key_1":"value_1","additional_data_key_2":"value_2"},
"include_subscription_ids": [
"SUBSCRIPTION_ID_1"
]
}'
앱이 실행 중이거나 실행 중이 아닐 때 로그된 메시지가 표시되어야 합니다.
macOS Console app showing debug log output from the OneSignalNotificationServiceExtension
메시지가 표시되지 않으면 앱에서 OneSignal을 제거하고 Mobile SDK setup을 다시 따라 통합을 확인하세요.

FAQ

iOS에서 Notification Service Extension이 실행되지 않는 이유는 무엇인가요? Extension은 mutable-content가 설정된 경우에만 실행됩니다. OneSignal은 첨부 파일이나 액션 버튼이 있는 알림에 대해 자동으로 이를 설정합니다. Xcode 설정이 문제 해결 섹션의 요구 사항과 일치하는지 확인하세요. Android에서 알림 표시를 방지할 수 있나요? 네, event.preventDefault()를 호출하여 알림을 억제할 수 있습니다. 나중에 event.getNotification().display()를 호출하여 표시하거나 호출하지 않고 자동으로 삭제할 수 있습니다. 자세한 내용은 중복 알림을 참조하세요. Android에서 @Keep 어노테이션이 필요한가요? 네, @Keep 어노테이션은 축소 과정에서 ProGuard/R8이 INotificationServiceExtension을 구현하는 클래스의 이름을 변경하거나 제거하지 못하도록 방지합니다.

관련 페이지

Mobile SDK 설정

iOS 및 Android용 OneSignal SDK를 설치하고 구성합니다.

이미지 및 리치 미디어

푸시 알림에 이미지, GIF 및 비디오를 첨부합니다.

확인된 전달

장치에 대한 알림 전달 확인을 추적합니다.

중복 알림

모든 플랫폼에서 중복 푸시 알림 문제를 해결합니다.