Mobile/iOS

iOS FCM 푸시 알림 #3 - 코드작성 및 테스트

WonYoungJae 2023. 1. 30. 15:41

코드 작성

Objective-c

// AppDelegate.h

#import <UIKit/UIKit.h>

// 추가
@protocol FIRMessagingDelegate;

@interface AppDelegate : UIResponder <UIApplicationDelegate, FIRMessagingDelegate /*추가*/>

@end
// AppDelegate.m

#import "AppDelegate.h"

@import FirebaseCore;
// 추가
@import FirebaseMessaging;
@import UserNotifications;

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application 
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [FIRApp configure];

        [FIRMessaging messaging].delegate = self;

    [UNUserNotificationCenter currentNotificationCenter].delegate = self;

        // 푸시 알림 권한 (알림, 뱃지, 사운드)
    UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
    UNAuthorizationOptionSound | UNAuthorizationOptionBadge;

    [[UNUserNotificationCenter currentNotificationCenter]
     requestAuthorizationWithOptions:authOptions
     completionHandler:^(BOOL granted, NSError * _Nullable error) {
        // ...
    }];

    [application registerForRemoteNotifications];

    return YES;
}

// APNs에 기기정보 등록
-(void)application:(UIApplication *)application 
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

    NSLog(@"deviceToken : %@", deviceToken);

    [FIRMessaging messaging].APNSToken = deviceToken;
}

// 푸시 알림이 도착했을 때
- (void)application:(UIApplication *)application 
        didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void 
        (^)(UIBackgroundFetchResult))completionHandler {

    [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

        // 알림이 오면 뱃지 갯수를 1 증가 시켜준다.
    application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1;

    completionHandler(UIBackgroundFetchResultNewData);
}

// 사용자가 앱에 들어왔을때
- (void)applicationDidBecomeActive:(UIApplication *)application {
        // 뱃지 갯수를 0으로 바꿔준다.
    UIApplication.sharedApplication.applicationIconBadgeNumber = 0;
}

// 여기서 받은 FCM 토큰으로 푸시 알림 전송할 수 있다.
- (void)messaging:(FIRMessaging *)messaging 
        didReceiveRegistrationToken:(NSString *)fcmToken {

    NSLog(@"FCM registration token: %@", fcmToken);

    [[NSNotificationCenter defaultCenter] postNotificationName:
     @"FCMToken" object:nil userInfo:dataDict];
}

// 앱이 포그라운드 상태일 때 푸시 알림이 왔을 경우 푸시 알림을 노출 방식 설정
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void 
                        (^)(UNNotificationPresentationOptions))completionHandler {

    // completionHandler에 아무것도 주지 않으면 사용자에겐 아무것도 보이지 않은다.
    completionHandler(UNNotificationPresentationOptionBadge /* 알림 벳지 */
                      | UNNotificationPresentationOptionAlert /* 알림창 생성 */ 
                                                | UNNotificationPresentationOptionSound /* 사운드 재생 */);
}

// 앱이 실행중이 아니거나 백그라운드 상태일 때
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
        didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void(^)(void))completionHandler {

    NSDictionary *userInfo = response.notification.request.content.userInfo;

    [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

        // 포그라운드 상태일 때와 다르게 보내는 푸시 알림의 노출 방식 설정에 따라 움직인다.
    completionHandler();
}

// 에러 났을 때
- (void)application:(UIApplication *)application 
        didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  NSLog(@"Unable to register for remote notifications: %@", error);
}

@end

Swift

// AppDelegate.swift

import UIKit
import UserNotifications

import FirebaseCore
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication
                        .LaunchOptionsKey: Any]?) -> Bool {

        FirebaseApp.configure()

        Messaging.messaging().delegate = self

        UNUserNotificationCenter.current().delegate = self

        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )

        application.registerForRemoteNotifications()

        return true
    }

    func application(_ application: UIApplication,
                     didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {

        print(userInfo)
    }

    func application(_ application: UIApplication,
                     didReceiveRemoteNotification userInfo: [AnyHashable: Any]) async
    -> UIBackgroundFetchResult {
        print(userInfo)

        return UIBackgroundFetchResult.newData
    }

    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }

    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("APNs token retrieved: \(deviceToken)")

    }

}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification) async
    -> UNNotificationPresentationOptions {
        let userInfo = notification.request.content.userInfo

        print(userInfo)

        return [[.alert, .sound, .badge]]
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse) async {
        let userInfo = response.notification.request.content.userInfo

        print(userInfo)
    }
}

extension AppDelegate: MessagingDelegate {

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("Firebase registration token: \(String(describing: fcmToken))")

        let dataDict: [String: String] = ["token": fcmToken ?? ""]
        NotificationCenter.default.post(
            name: Notification.Name("FCMToken"),
            object: nil,
            userInfo: dataDict
        ) 
    }

}

테스트

  1. FCM 콘솔에서 첫 번째 캠페인 만들기 클릭
  2. Firebase 알림 메시지 선택 후 만들기 클릭
  3. 제목, 알림 텍스트 입력 후 테스트 메시지 전송 클릭
  4. FCM 등록 토큰 클릭 후 앱 실행해서 로그에 찍힌 FCM 토큰 입력
  5. 플러스 버튼 클릭 후 테스트 클릭
  6. 앱에 푸시 알림이 오면 푸시 알림 구현 성공
728x90