티스토리 뷰

Swift

APNS 구현해보기

진태우 2017. 2. 22. 16:47



APNS(Apple Push Notification Service)를 구현하면서 삽질한 내용을 정리해보기로 했다.


- 순서

1. 애플 개발자 인증서 발급 및 설정

2. client code 작성

3. .p12 파일 생성

4. APN Tester로 push test

 


1. 애플 개발자 인증서 발급 및 설정

development 및 production 인증서는 발급받았다고 가정하고 진행하였다.



1) push notification 인증서를 발급하기 위한 키체인 인증서 생성.


2) AppID 생성

development 및 production 인증서를 발급받았다면 이미 만들어져 있을 것이다.



Bundle ID는 앱에서 사용되는 Bundle ID와 매칭시켜줘야 한다.


  • 아래는 간단히 목록에 대한 설명이다.


- Data Protection
: 앱에서 생성한 파일을 기기의 디스크에 저장할 때 보안 기능 사용 여부를 선택하는 옵션이다.
금융권 앱과 같이 보안에 민감한 앱이 아니라면 선택하지 않는다.

- Complete Protection
: 어떠한 상황에서도 파일을 보호한다.

- Protected Unless Open
: 파일을 open 할 때까지 보호한다.

- Protected Until First User Authentication
: 첫 사용자 인증이 완료되는 시점까지 보호한다.

- Game Center
: 게임센터 서비스를 이용할 경우 선택

- In-App Purchase
: 앱 내부 결제 서비스를 이용할 경우 선택한다. 기본으로 선택되있음.

- Push Notification
: 푸시 서비스를 이용할 경우 선택



완성된 AppID를 선택하면 위와 같은 화면이 나온다.

Push를 보면 활성화되지 않은 것을 확인할 수 있고, Edit을 선택해 활성화 시켜보자.


위 그림은 Edit을 선택한 화면이다. 

그림에서는 이미 활성화되 있어서 다운을 받아 사용하면 된다. 

아직 활성화된 인증서가 없다면 만들어서 사용하면 된다.


다운받은 푸시 인증서를 실행하면 키체인에 등록되는 것을 볼 수 있다.



3) Provisioning Profile 생성


위에 표시해논 3가지에 대해서 간략하게 설명해보겠다.


- IOS App Development

: 개발시 사용되는 profile


- App Store

: 최종적으로 App Store에 배포하기 위해 사용되는 profile


- Ad Hoc

:테스트용 profile. 테스트 플라이트에 업로드 후 push notification을 테스트해보기 위해 사용된다. 또한 최대 100개의 기기에 설치가 가능하기 때문에 이것으로 앱스토어에 최종배포하면 안된다. 



2. client code 작성


푸시 알람을 보내기 위해서는 기기를 식별할 수 있는 deviceToken이 필요하다. 

registerPushNotifications 메서드는 앱이 수신할 알람 유형을 설정하는 코드이다. 
앱이 시작할 때 이 메서드를 실행시켜준다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    registerPushNotifications()
    return true
}

func registerPushNotifications() {
    if #available(iOS 10.0, *) {
        let center  = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
            if error == nil{
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
    }
    else {
        DispatchQueue.main.async {
            let settings = UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil)
            UIApplication.shared.registerUserNotificationSettings(settings)
            UIApplication.shared.registerForRemoteNotifications()
        }
    }
}


앱 실행시 알람 허용여부 창이 출력됬을 때, 허용을 선택하면 didRegisterForRemoteNotificationsWithDeviceToken이 호출된다.   didFailToRegisterForRemoteNotificationsWithError는 에러 발생시 호출된다.

// deviceToken 등록 성공시 실행되는 메서드
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
    let deviceTokenString = ((deviceToken as NSData).description.trimmingCharacters(in: CharacterSet(charactersIn: "<>")) as NSString).replacingOccurrences(of: " ", with: "")
    print("Notification 등록 성공: \(deviceTokenString)")
}

// deviceToken 등록 실패시 실행되는 메서드
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Notification 등록 실패: \(error.localizedDescription)")
}


아래는 푸시를 받을 경우 호출되는 메서드이다.

// push notification when foreground (iOS 8.0 ~ 9.0)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
}

// push notification when foreground (iOS 10.0 ~ )
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    print("User Info = ",notification.request.content.userInfo)
    completionHandler([.alert, .badge, .sound])
}

// push notification when background (라고 하지만 테스트해보면 정작 디버깅이 찍히지 않는다... 좀 더 알아봐야 할듯...)
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    print("User Info = ",response.notification.request.content.userInfo)
    completionHandler()
}


이정도만 하면 APN Tester로 푸시를 보냈을 경우 푸시를 받아볼 수 있다.

하지만 iOS 10.0에서는 백그라운드에서 푸시를 받을 수 없을 것이다.

10.0에서 수정된 것이 있는데 아래의 그림과 같이 Background fetch를 선택해주면 해결된다.

이걸 모르면 이상한 곳에서 삽질하는 모습을 보게될 것이다....




3. APN Tester로 push test

우선 apn tester를 앱 스토어에서 검색하여 설치한다.

실행하면 다음과 같은 화면이 나올 것이다.


클라이언트 코드를 작성하고 앱을 실행하면 출력되는 deviceToken과 push notification 인증서를 넣어준 후 푸시를 누르면 앱에서 푸시를 받아볼 수 있다.

4. .p12 파일 생성

서버에서 코드를 작성해서 푸시를 보내기 위해서는 인증서가 필요하다.
그럼 서버에 필요한 인증서를 만들어 보자.


키체인에서 push notification 인증서를 export해서 .p12 파일을 생성한다.

하지만 이것만 해서는 push를 받지 못한다.

아래와 같이 openssl 명령어를 사용하여 몇 가지 작업을 해줘야 한다.

aps_development.cer   <- download from Apple
development_key.p12   <- Your private key

openssl x509 -in aps_development.cer -inform DER -out aps_development.pem -outform PEM
openssl pkcs12 -nocerts -in development_key.p12 -out development_key.pem
openssl pkcs12 -export -inkey development_key.pem -in aps_development.pem -out aps_development.12

최종적으로 나온 aps_development.12 파일을 서버서 사용하면 된다.

production 파일도 똑같은 방식으로 하면 된다.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함