Sendbird Push Noti 연결하기
Posted on 2021-10-26 by GKSRUDTN99
Swift&Xcode
Xcode
Chat
1. APN Certificate 만들기
- '키체인 접근' 열기
- 상단 메뉴바에서 키체인 접근 > 인증서 지원 > 인증 기관에서 인증서 요청 선택
- 사용자 이메일 주소에는 자신의 Apple Developer 계정을 넣고, 요청 항목은 '디스크에 저장됨'을 선택하여 계속
- '.certSigningRequest'파일을 적당한 곳에 저장한다.
- 'https://developer.apple.com/account/resources/certificates/list' 에 접속하여, 로그인 한 뒤, 우측 상단에서 앱을 소유하고 있는 팀으로 변경한다.
- 왼쪽에서 'Identifiers'탭을 선택한 뒤에 APN Certificate를 만들 앱을 선택한다.
- App Id Configuration 창에서 Push Notifications를 체크한뒤, 우측에 'Edit'또는 'Configure' 버튼을 선택한다.
- 앱의 Identifier에 맞게 Dev 또는 Prod를 선택하여 'Create Certificate' 버튼을 선택한다.
- 이어 나오는 화면에서 'Choose File'을 선택한 뒤 앞서 만들었던 '.certSignRequest'파일을 선택한 뒤 'Continue'버튼을 선택한다.
- 다음으로, 'Download' 버튼을 선택하여 APN Certificate를 다운로드 받는다.
2. APN Certificate .p12 파일로 내보내기
- 앞에서 내려받은 APN Certificate를 더블클릭하여 키체인에 등록한다.
- 좌측 메뉴에서 '로그인'을 선택한 뒤, 상단 메뉴들 중에서 '내 인증서'를 선택한다.
- 'Apple Development IOS Push Services: (App Identifier)' 이름을 가진 인증서의 왼쪽 '>' 모양을 눌러 개인키가 보이도록 펼친다.
- 인증서와 개인키를 같이 선택한 뒤, 오른쪽 클릭하여 '2개 항목 내보내기'를 선택한다.
- .p12 파일을 적절한 곳에 저장한다.
- 이때, 내보낸 항목을 보호하는 데 사용할 암호를 입력하라고 하는데, 입력하지 않고 확인을 누르고 넘어가도 된다.
3. .p12 파일 Sendbird에 등록하기
- 'https://dashboard.sendbird.com/' 를 열어 샌드보드 대쉬보드에 접속한다.
- 좌측 상단에서 앱을 선택한다.
- Settings > Chat > Notifications로 들어간다.
- 'Push notifications credentials'탭을 찾아, 애플 아이콘 옆에 있는 'Add credential'을 클릭한다.
- 'Format'을 '.p12'로 선택하고 'Choose File'버튼을 클릭해서 앞서 저장한 .p12 파일을 업로드 한다.
- 기타 설정을 마무리한다.
- Password는 .p12를 저장할 때 항목을 보호하는 데 사용할 암호를 입력하지 않았다면 비워둔다.
- SSL certificate type은 APN Certificate를 발급받을 때 선택한 것과 동일하게 선택한다.
4. Sendbird Server에 Device Token 등록하기
1. UIApplication.shared.registerForRemoteNotifications
함수 호출하기
- 위 함수를 호출해야 Push Noti에 사용할 Device Token을 발급받을 수 있다.
- 적절한 위치에 다음 코드를 작성한다.
// Swift
let center = UNUserNotificationCenter.current()
center.delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
center.requestAuthorization(options: authOptions) { (granted, error) in
center.getNotificationSettings(completionHandler: { (settings: UNNotificationSettings) -> Void in
guard settings.authorizationStatus == UNAuthorizationStatus.authorized else {
return;
}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
})
}
- 빔뷰의 경우는 App Delegate 내에,
application:didFinishLaunchingWithOptions
함수 안에서 registerForRemoteNotification 함수를 호출한다.
2. application:didRegisterForRemoteNotificationsWithDeviceToken
함수 작성하기
registerForRemoteNotifications
함수가 호출되면, App Delegate내에서 이 함수가 호출되는데, parameter에 device token이 전달되므로 이를 Sendbird에 등록할 수 있다.- 예시 코드
// AppDelegate.swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Sendbird server에 Device Token을 등록합니다.
SBDMain.registerDevicePushToken(deviceToken, unique: true, completionHandler: { (status, error) in
if error == nil {
// Device Token이 정상적으로 등록된 경우
}
else {
if status == SBDPushTokenRegistrationStatus.pending {
// Device Token 등록이 지연된 경우
}
else {
// Device Token 등록이 실패한 경우
}
}
})
}
- Device Token 등록이 지연되는 경우는 보통, Device Token Register가 비동기적으로 진행되기 때문에,
SBDMain.connect
보다 먼저 실행되는 경우가 있어 발생한다. - 이 경우,
SBDMain.getPendingPushToken()
을 통해 Device Token을 전역에서 받아올 수 있다. - 그렇기 때문에
SBDMain.connect
를 App Delegate내에서 실행하지 않고 나중에 실행할 때,connect
함수의 completion Handler에서 이 토큰을 이용해 Device Token을 등록할 수 있다. - 예시 코드
// Swift
SBDMain.connect(withUserId: USER_ID, completionHandler: { (user, error) in
if error == nil {
SBDMain.registerDevicePushToken(SBDMain.getPendingPushToken()!, unique: true, completionHandler: { (status, error) in
...
})
}
})
5. Notification Payload Handling
1. center:didReceive:withCompletionHandler
함수 작성하기.
- 앞서
UIApplication.shared.registerForRemoteNotifications
를 호출할 때UNUserNotificationCenter
를 함께 설정해 두었기 때문에, 사용자가 Noti를 클릭하면 위의 함수가 호출된다. - 이 함수 내에서
response.notification.request.content.userInfo
로 payload를 받아올 수 있다. - payload에서 sendbird 객체를 받아올 수 있고, sendbird 객체 내의 구조는 다음과 같다.
{
"category": "messaging:offline_notification",
"type": string, // Message type: 'MESG', 'FILE', or 'ADMM'
"message": string, // User input message
"data": string, // Custom data field
"custom_type": string, // Custom message type
"message_id": long, // Message ID
"created_at": long, // 13-digit timestamp
"app_id": string, // Application's unique ID
"unread_message_count": int, // Total number of new messages unread by the user
"channel": {
"channel_url": string, // Group channel URL
"name": string, // Group channel name
"custom_type": string // Group channel custom_type
},
"channel_type": string, // The value of "channel_type" is set by the system.
// The 'messaging' indicates a distinct group channel
// while 'group_messaging' indicates a private group channel
// and 'chat' indicates all other cases.
"sender": {
"id": string, // Sender's unique ID
"name": string, // Sender's nickname
"profile_url": string // Sender's profile image URL
},
"recipient": {
"id": string, // Recipient's unique ID
"name": string // Recipient's nickname
},
"files": [], // If a message is a file link,
// this array represents files.
"translations": {}, // If a message has translations,
// this dict has locale:translation.
"push_title": string, // Title of a notification message that can be
// customized in the Sendbird Dashboard
// with or without variables
"push_sound": string, // The location of a sound file for notifications
"audience_type": string, // The type of audiences to receive notifications
"mentioned_users": {
"user_id": string, // The ID of a mentioned user
"total_unread_mention_count": int, // The number of messages which
// a user has been mentioned
// but has not read within the channels
"channel_unread_mention_count": int, // The number of channels with messages
// which a user has been mentioned
// but has not read
"is_hidden": boolean // Whether or not a mentioned user has
// hidden the channel from the list
},
"channel_unread_count": int // Total number of unread new messages
// from the specific channel
}
- 아래는 payload에서 channel Url에 접근하는 예시코드이다.
// AppDelegate.swift
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if let userInfo = response.notification.request.content.userInfo as? [String : Any],
let sendbirdDict = userInfo["sendbird"] as? [String : Any],
let channelDict = sendbirdDict["channel"] as? [String : Any],
let channelUrl = channelDict["channel_url"] as? String {
print(channelUrl)
}
}