본문 바로가기
아이폰 개발/ios 개념&튜토리얼

Ios push 기초 with Firebase

by 인생여희 2020. 8. 1.

ios push 개념

시작하기 전에 push가 어떤 원리로 작동되는지 먼저 개념과 그림을 그리고 시작해도 좋을 것 같다.

아래 포스팅에서 ios push 개념에 대해서 상황을 만들어서 설명해 놓았다. 

몽실이의 ios push 개발하기 - push 개념

 

push 작동 원리

 

push 작동 원리

 

xcode 셋팅

필요한 프레임워크를 넣어준다. 

 

 

push Notifications 옵션을 넣어준다.

 

푸시 인증서 생성 

 

1.

 

2.

3.

 

 

4.

인증서가 생성되었다. 더블클릭.

 

5.

하나씩 선택 후 내보내기.

 

 

6.

파일명 작성, 파일포맷작성후 저장

 

 

7.

암호를 설정한다.

 

8.

p12 파일이 생성되었다. 

 

9.

파이어 베이스 프로젝트를 만든 후, 셋팅화면으로 들어간다.

 

(파이어 베이스 프로젝트 생성하는 부분은 이곳 파이어베이스 문서 가이드 참고)

 

 

 

10.

위에서 만든 apn 인증서를 업로드 한다.

 

 

11.

업로드 성공.

 

 


 

ios 클라이언트 push 기능 개발

위에서 푸시 인증서 생성, 파이어베이스 푸시 서버에 인증서 셋팅이 끝났고, pod로 firebase 푸시 관련 라이브러리를 주입했다면, 이제 ios 클라이언트에서 로직을 구현할 차례다. 클라이언트 부분 개발로직 작성 순서는 아래와 같다.

 

1. 라이브러리 추가

Xcode builde phases 에서 두개의 라이브러리를 추가해준다. UserNotification framework, PushKit framework

 

2.ios push 라이브러리 import

AppDelegate.h에서 1번에서 추가한 라이브러리를 import 해준다. 그리고 파이어 베이스 라이브러리도 import 해준다.

#import <UserNotifications/UserNotifications.h>

@import Firebase;

@import FirebaseMessaging;

 

3, 4. 푸시 프로토콜 상속

appDelegate.h에서 푸시 관련 프로토콜을 상속받는다

@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate,FIRMessagingDelegate>

 

 

5.파이어베이스 푸시 서버 프로젝트 번호 작성

파이어베이스 서버의 설정에 들어가면 프로젝트 번호가 있다. 상단에 작성해준다.

 NSString *const kGCMMessageIDKey = @"353819155139";

 

6.파이어베이스 모듈 설정

앱이 시작할 때 didFinishLaunchingWithOptions 부분에 파이어베이스 모듈 설정을 해준다.

 [FIRApp configure];

 

 

7.FIRMessaging의 delegate 속성 설정

구글 푸시 서버에서 메시지를 발송했을때 메시지를 받으려면 메시지 처리를 하는 델리게이트 메소드를 구현해야 한다. 그럴려면 FIRMessaging의 delegate 속성을 설정해야한다.

 [FIRMessaging messaging].delegate = self;

  

 8.푸시 허용 여부

푸시를 받고 싶은 사람도 있고, 받고 싶지 않은 사람도 있다. 아래 로직을 이용해서 푸시 수신 여부를 물어보고 응답결과에 따라서 처리해주는 로직을 구현한다.

 if ([UNUserNotificationCenter class] != nil) {

   // iOS 10 or later
   // For iOS 10 display notification (sent via APNS)

   [UNUserNotificationCenter currentNotificationCenter].delegate = self;

     //푸쉬 옵션

     UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;

     //위의 푸시 옵션을 사용하겠냐 질문

     [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions

       completionHandler:^(BOOL granted, NSError * _Nullable error) {

         //앱 최초 실행시, 사용자에게 푸쉬 허용을 할건지 아닌지 권한 질문. 허용을 하든 , 거부를 하든 이곳이 실행된다.

         NSLog(@"APNS에 디바이스 알림 등록 시작");

        
         //허용 : 1, 허용안함 : 0

         NSLog(@"granted(푸시허용여부 1:허용 , 0: 거부) : %d" , granted);
       }];

 }else {

   // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.

   UIUserNotificationType allNotificationTypes =

   (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);

   UIUserNotificationSettings *settings =

   [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];

   [application registerUserNotificationSettings:settings];

 }

 

9.APNS에 디바이스를 등록

앱 자신이 APNS를 사용하겠다고 iOS와 APNS에게 알린다.

[application registerForRemoteNotifications];

 

여기까지가 APSN에 등록하고 토큰을 요청하는 로직이다. 이후 아래 소개할 메소드는 델리게이트 메소드이다.토큰이 왔을때, 푸시가 왔을때, 푸시를 눌렀을때 호출된다. 애플과 구글 파이어 베이스 메소드를 구분해서 소개한다.

 

 

apple push 관련 델리게이트 메소드

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken;

✅설명 : APNS 등록이 성공하고 DeviceToken을 전달받으면 아래 메서드가 실행된다. NSData 형식의 deviceToken 인자가 전달된다.

 

 

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err;

✅설명 : APNS 서버에 등록 실패

 

  

 Firebase push 관련 델리게이트 메소드

- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken

✅설명 : 앱이 실행될때 토큰을 받는다.

 

 

 - (void)userNotificationCenter:(UNUserNotificationCenter *)center

 willPresentNotification:(UNNotification *)notification

  withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler

✅설명 : 앱이 포그라운드 상황에서 푸시가 오면 호출된다.

 

 

 - (void)userNotificationCenter:(UNUserNotificationCenter *)center

 didReceiveNotificationResponse:(UNNotificationResponse *)response

          withCompletionHandler:(void(^)(void))completionHandler

✅설명 : 사용자가 푸시 알림을 누르면 호출된다.

 

 

ios push 예제 코드

AppDelegate.h

#import <UIKit/UIKit.h>

//1.UserNotifications 라이브러리 임포트
#import <UserNotifications/UserNotifications.h>


//2.파이어 베이스 메시징 라이브러리 임포트
@import Firebase;
@import FirebaseMessaging;


//3. UNUserNotificationCenterDelegate 추가,
//4. FIRMessagingDelegate 추가
@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate,FIRMessagingDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

 

AppDelegate.m

#import "AppDelegate.h"

@interface AppDelegate () 

@end

@implementation AppDelegate

//5.파이어베이스 푸시 서버 key 작성
NSString *const kGCMMessageIDKey = @"353819155139";


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

    NSLog(@"### didFinishLaunchingWithOptions 호출");
    
    //6.[파이어베이스 모듈 설정]
    [FIRApp configure];
   
    
    //7. 메시지 대리자 설정
    //등록 토큰을 받으려면 [FIRApp configure]를 호출한 후 메시지 대리자 프로토콜을 구현하고 FIRMessaging의 delegate 속성을 설정해야한다.
    [FIRMessaging messaging].delegate = self;
   

    //8. 푸시 허용여부 질문
    if ([UNUserNotificationCenter class] != nil) {
        
      // iOS 10 or later
      // For iOS 10 display notification (sent via APNS)
      [UNUserNotificationCenter currentNotificationCenter].delegate = self;
     
        //푸쉬 옵션
        UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
     
        //위의 푸시 옵션을 사용하겠냐 질문
        [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions
          completionHandler:^(BOOL granted, NSError * _Nullable error) {
           
            //앱 최초 실행시, 사용자에게 푸쉬 허용을 할건지 아닌지 권한 질문. 허용을 하든 , 거부를 하든 이곳이 실행된다.
            NSLog(@"APNS에 디바이스 알림 등록 시작");
            
            //허용 : 1, 허용안함 : 0
            NSLog(@"granted(푸시허용여부 1:허용 , 0: 거부) : %d" , granted);

          }];
        
    }else {
      // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
      UIUserNotificationType allNotificationTypes =
      (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
      UIUserNotificationSettings *settings =
      [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
      [application registerUserNotificationSettings:settings];
    }

    
    //9.APNS에 디바이스를 등록
    //앱 자신이 APNS를 사용하겠다고 iOS와 APNS에게 알림.
    [application registerForRemoteNotifications];
    
    return YES;
}


/*  애플 푸시 셋팅 관련 델리게이트 메소드 */

//APNS 등록이 성공하고 DeviceToken을 전달받으면 아래 메서드가 실행된다.
//NSData 형식의 deviceToken 인자가 전달된다.
- (void)application:(UIApplication *)app
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {

    //토큰형식 변경
    NSString *str = [self stringFromDeviceToken:devToken];
    NSLog(@"애플 APNS에서 받은 token: %@", str);
    
    //실제 서비스라면 이 토큰을 사용자 정보와 함께 프로바이더에게 전달하여 관리를 할 필요가 있음.
    //Provider에게 DeviceToken을 전송한다.
    //예) [self sendProviderTokenString:[deviceToken bytes]];
}
 
//APNS 서버에 등록 실패
- (void)application:(UIApplication *)app
        didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
   
    NSLog(@"APNS에 등록 실패 error: %@", err);
}



/*  파이어 베이스  푸시 셋팅 */


//앱이 최초 실행되면 이 메소드까지 실행되고 토큰을 받는다.
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    NSLog(@"### didReceiveRegistrationToken 호출 - 토큰 받기");
    NSLog(@"FCM registration token: %@", fcmToken);

    //받은 토큰에 대해 알립니다.
    NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"FCMToken" object:nil userInfo:dataDict];

    // TODO : 필요한 경우 토큰을 응용 프로그램 서버로 보냅니다.
    // 참고 :이 콜백은 앱이 시작될 때마다 그리고 새 토큰이 생성 될 때마다 시작됩니다.
}



//포그라운드에서 푸쉬 받기
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
  NSDictionary *userInfo = notification.request.content.userInfo;

     NSLog(@"### willPresentNotification 호출 - 푸시 도착");

  // 스위즐링을 사용하지 않도록 설정하면 Analytics에 대해 메시지에 대해 메시지를 알려야합니다.
  // [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

  // 파이어베이스 푸시서버 키
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

   //메시지 전체 내용 출력
   NSLog(@"## 메시지 전체 내용 : %@", userInfo);

  // 선호하는 프리젠 테이션 옵션으로 변경
  completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionAlert);
}



//포그라운드든 백그라운드든 유저가 푸쉬를 눌렀을때 발생
//사용자가 표시 알림을 누른 후 알림 메시지를 처리.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void(^)(void))completionHandler {

     NSLog(@"### didReceiveNotificationResponse 호출 - 유저 푸시 클릭");

  NSDictionary *userInfo = response.notification.request.content.userInfo;
    
   // 파이어베이스 푸시서버 키
  if (userInfo[kGCMMessageIDKey]) {
    NSLog(@"Message ID: %@", userInfo[kGCMMessageIDKey]);
  }

  //메시지 전체 내용 출력
  NSLog(@"## 메시지 전체 내용 : %@", userInfo);

  completionHandler();
}


//ios 13에서 푸쉬 토큰 받는 형식 변경됨.
//참고 : http://blog.daum.net/creazier/15311563
//참고 : https://effectivecode.tistory.com/1211
- (NSString *)stringFromDeviceToken:(NSData *)deviceToken {

    NSUInteger length = deviceToken.length;
    if (length == 0) {
        return nil;
    }
    const unsigned char *buffer = deviceToken.bytes;

    NSMutableString *hexString  = [NSMutableString stringWithCapacity:(length * 2)];

    for (int i = 0; i < length; ++i) {

        [hexString appendFormat:@"%02x", buffer[i]];
    }

    return [hexString copy];

}

@end


 

ios push 테스트

앱을 실행하면 파이어베이스로 부터 토큰하나, APNS로 부터 토큰하나가 응답된다. 그 토큰을 가지고 Firebase의 클라우드 메시지 창으로 가서 푸시를 받을 대상 토큰을 적어주자. 나의 앱으로 응답된 토큰을 적어주면 나에게로 푸시가 온다.

firebase cloud message 설정

테스트 버튼을 누르면 아래와 같이 나의 앱으로 푸시가 와있는것을 볼 수 있다.

 

ios push test

 

 

 

ios push 참고 사이트

*애플 문서 : https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW3

*파이어베이스 문서 : https://firebase.google.com/docs/cloud-messaging/ios/receive?hl=ko

*핑거 푸쉬 : https://helloworld.fingerpush.com/apns-p8-%ed%8c%8c%ec%9d%bc-%ec%83%9d%ec%84%b1/

*닉군의 : https://nicgoon.tistory.com/203

*pem 파일 만들기 : https://g-y-e-o-m.tistory.com/24

*node js 서버 : https://g-y-e-o-m.tistory.com/72

*개발, 배포 버전 : https://blog.canapio.com/34

 

 *ios 13에서 푸쉬 토큰 받는 형식 변경됨.

참고 1.: http://blog.daum.net/creazier/15311563

참고 2.: https://effectivecode.tistory.com/1211

 

 

'아이폰 개발 > ios 개념&튜토리얼' 카테고리의 다른 글

코어 오디오 - 오디오 정보 추출  (0) 2020.08.06
ios 위변조 탐지 로직  (1) 2020.08.05
Ios CoreData 간단한 예제로 배우기  (0) 2020.07.30
SQLite 응용  (0) 2020.07.29
SQLite 기초  (0) 2020.07.29