티스토리 뷰

 

 

[iOS] FCM으로 Push Notification (푸시 알림) 구현하기

FCM(Firebase Cloud Messaging)같은 경우는 공식문서와 설정 튜토리얼이 정말 잘 되어있어서 공식 문서를 따라가시는 것도 좋을 것 같습니다! I. Key 발급 1. 우선 먼저 Apple Developer Member Center에서 Keys에 들

dokit.tistory.com

이번엔 FCM에 이어서 로컬에서 푸시를 구현해보려고합니다. 별도의 토큰이 필요하지 않기 때문에 훨씬 간단해요!

 

알림 허용 받기


우선 사용자에게 알림 허용 권한을 받야야합니다.

AppDelegate에서 설정하기

import UserNotifications

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        // 앱 실행 시 사용자에게 알림 허용 권한을 받음
        UNUserNotificationCenter.current().delegate = self
        
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
        return true
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    // Foreground(앱 켜진 상태)에서도 알림 오는 설정
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.list, .banner])
    }
}

이렇게 AppDelegate에 작성해주셔도 되고, 팝업 시점을 로그인 후로 하고 싶다면 따로 함수를 빼서 원하는 부분에 작성해도됩니다.

이때 Delegate를 설정하기 위해서는 UNUserNotificationCenterDelegate프로토콜을 꼭 채택해주셔야합니다.

 

UNUserNotificationCenterDelegate는 푸시 알림 관련해서 다양한 설정들을 오버라이드할 수 있게해주는데요, 우선 앱 활성화 상태에서도 알림을 받아볼 수 있는 설정만 추가해놓겠습니다.

⚠️ SwiftUI프로젝트라면 AppDelegate를 생성하고 @main에 연결해주세요!
// App.swift
@main
struct AtchIApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate // ✅ 추가
    
	//...
}

// AppDelegate.swift
// ✅ AppDelegate 클래스 생성
class AppDelegate: NSObject, UIApplicationDelegate {
	// ...
}​

 

다른곳에서 설정하기

// AppDelegate.swift
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        // 앱 실행 시 사용자에게 알림 허용 권한을 받음
        UNUserNotificationCenter.current().delegate = self
        
        return ture 
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    // Foreground(앱 켜진 상태)에서도 알림 오는 설정
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.list, .banner])
    }
}
    

// LocalNotificationHelper.swift
class LocalNotificationHelper {
    static let shared = LocalNotificationHelper()
    
    private init() { }
    
    func setAuthorization() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
    }
}

// AnyView.swift
struct AnyView: View {

    var body: some View {
		// ...
        }
        .onAppear() {
            // Setting push notification
            PushNotificationHelper.shared.setAuthorization()
    }
}

저는 이렇게 싱글턴 객체를 만들어서 권한 설정 부분을 위임했는데요, 단 UNUserNotificationCenter.current().deleate = self 부분은 꼭 AppDelegate에서 설정해주셔야합니다!

 

그리고 권한 허용을 하는 부분을 원하는 곳에 넣어주시면 됩니다. 예시에서는 onAppear부분에 넣었지만 특정 네트워킹(ex.로그인) 콜백 부분에 작성할 수도 있습니다.

 

알림 팝업이 뜬다면 성공입니다!

 

푸시 알림 보내기


함수 구현

// PushNotificationHelper.swfit > PushNotificationHelper
func pushNotification(title: String, body: String, seconds: Double, identifier: String) {
    // 1️⃣ 알림 내용, 설정
    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = title
    notificationContent.body = body

    // 2️⃣ 조건(시간, 반복)
    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: seconds, repeats: false)

    // 3️⃣ 요청
    let request = UNNotificationRequest(identifier: identifier,
                                        content: notificationContent,
                                        trigger: trigger)

    // 4️⃣ 알림 등록 
    UNUserNotificationCenter.current().add(request) { error in
        if let error = error {
            print("Notification Error: ", error)
        }
    }
}

Push를 보내기 위해서는 3가지를 설정해주어야하는데요 Content, Trigger, Reuqest입니다.

1️⃣ Content는 알림의 내용입니다. title과 body외에 이미지, 뱃지나 사운드도 설정할 수 있습니다.

2️⃣ Trigger는 알림 시간과 반복에 대한 설정입니다. 알림은 timeInterval에 설정된 초 이후에 실행됩니다. interval은 반드시 1이상 값이어야합니다. 그리고 repeats를 true로 설정하게 되면 timeInterval 간격으로 계속 알림이 오게되며 trigger의 반복을 true로 설정하려면 timeInterval이 60초 이상이어야합니다.

3️⃣ Request는 content와 trigger를 합쳐 요청으로 만듭니다. 이때 identifier는 알림 취소 등에 사용되는 식별자 입니다.

 

저는 아까 인증에 사용했던 PushNotificationHelper에 구현해주었습니다.

 

호출 하기

LocalNotificationHelper.shared.pushNotification(title: "안녕하세요", body: "푸시 알림 테스트입니다.", seconds: 2, identifier: "PUSH_TEST")

앱 활성화 상태에서도 알림이 오도록 설정해두었기 때문에 상단에 알림이 잘 오는 것을 확인할 수 있습니다!

 

UNUserNotificationCenterDelegate 프로토콜 알아보기


UNUserNotificationCenterDelegate에는 3가지 메서드가 있는데 하나씩 살펴보도록 하겠습니다.

 

1. userNotificationCenter(_:didReceive:withCompletionHandler:)

알림에 대해 사용자가 반응하면 실행된다고 합니다. 즉, 알림을 탭하면 실행되게 됩니다. (백그라운드, 포그라운드 모두 실행됨)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {
    completionHandler()
}
더보기
func userNotificationCenter(_ center: UNUserNotificationCenter,
            didReceive response: UNNotificationResponse,
            withCompletionHandler completionHandler: 
               @escaping () -> Void) {
   // Get the meeting ID from the original notification.
   let userInfo = response.notification.request.content.userInfo
        
   if response.notification.request.content.categoryIdentifier ==
              "MEETING_INVITATION" { // ✅ category Identifier 식별 - noti content에서 따로 설정해주어야합니다!
      // Retrieve the meeting details.
      let meetingID = userInfo["MEETING_ID"] as! String
      let userID = userInfo["USER_ID"] as! String
            
      switch response.actionIdentifier {
      case "ACCEPT_ACTION":
         sharedMeetingManager.acceptMeeting(user: userID, 
               meetingID: meetingID)
         break
                
      case "DECLINE_ACTION":
         sharedMeetingManager.declineMeeting(user: userID, 
               meetingID: meetingID)
         break
                
      case UNNotificationDefaultActionIdentifier,
           UNNotificationDismissActionIdentifier:
         // Queue meeting-related notifications for later
         //  if the user does not act.
         sharedMeetingManager.queueMeetingForDelivery(user: userID,
               meetingID: meetingID)
         break
                
      default:
         break
      }
   }
   else {
      // Handle other notification types...
   }
        
   // Always call the completion handler when done.
   completionHandler()
}

공식 예제인데요, 이런식으로 identifer를 통해 알림 종류마다 다른 행동을 정의해줄 수도 있습니다.

 

2.userNotificationCenter(_:willPresent:withCompletionHandler:)

포그라운드 상태(앱 실행 중)일때 알림을 받으면 해야할 행동을 정의할 수 있습니다.

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent notification: UNNotification,
                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.list, .banner]) //포그라운드 상태에서도 상단 알림이 뜨도록 completion에 전달
}

 

3. userNotificationCenter(_:openSettingsFor:)

외부에서 인앱 설정 페이지로 이동할 수 있도록 해주는 메서드입니다. 구현하면 기본 설정 앱에 인앱 설정으로 이동할 수 있는 옵션이 생깁니다. UIKit 프로젝트에서는 알림 화면 VC를 push 하는 코드를 작성해주면 되는데요, SwiftUI에서는 HostingController를 사용해야하기 때문에 조금 복잡했습니다. 그래서 딥링크를 넣어봤는데 잘 작동하진 않네요 ㅎㅎ.. 성공하면 업데이트해서 적어보겠습니다.

 

 

응용 - 햅틱(진동) 넣기


포그라운드에서 푸시 알림이 올 때 햅틱이 오는 기능을 추가하고 싶어서 구현해보았습니다.

import Foundation
import SwiftUI

class HapticHelper {
    
    static let shared = HapticHelper()
    
    private init() { }
    
    func notification(type: UINotificationFeedbackGenerator.FeedbackType) {
        let generator = UINotificationFeedbackGenerator()
        generator.notificationOccurred(type)
    }
    
    func impact(style: UIImpactFeedbackGenerator.FeedbackStyle) {
        let generator = UIImpactFeedbackGenerator(style: style)
        generator.impactOccurred()
    }
}

우선 햅틱 기능을 담당해줄 클래스를 하나 생성해주었습니다. 이것 역시 싱글턴으로 만들어주었습니다.

 

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent notification: UNNotification,
                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    // 햅틱을 실행하는 함수를 호출합니다.
    HapticHelper.shared.impact(style: .medium)
    completionHandler([.list, .banner])
}

UNUserNotificationCenterDelegate의 willPresent함수에 추가해주었습니다.

 

진동 기능이므로 테스트는 실제 디바이스에서 해야합니다! ☺️

 

 

마치며


별도 개발자 인증도 필요하지 않고 쉽게 구현이 가능했습니다! 👍👍

 

 

읽어주셔서 감사합니다.

 

 

ref.

https://velog.io/@hope1053/iOS-로컬-푸시-알림Local-Notification-구현하기

[iOS] 로컬 푸쉬 알림 구현 방법 (Local Notification)

[SwiftUI] Haptics

Handling notifications and notification-related actions

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함