반응형
IOS FCM 푸시 알림 연동(Spring)
환경
IOS
스프링 부트
웹뷰
주의
작성한 코드는 수정이 필요한 코드이다 동일한 코드 작성 시 정상적인 작동을 하지 않는다.
알림 과정
앱 > 인증번호 요청 > 서버(스프링 부트) > 인증번호 생성 > 앱 알림(푸시)
FCM 푸시 동작 과정
1. FCM 프로젝트 생성
- 사이드 주소
- 생성방법
- 프로젝트 만들기
- 프로젝트 이름 생성(자신이 구분할 수 있는 이름)
- 애널리틱스는 미사용으로 진행(사용 시 별도설명확인)
- 프로젝트 생성 완료(다소 시간이 걸릴수 있다)
2. 앱에 Firebase에 추가
- IOS선택
- 앱 등록
xcode프로젝트 생성 방법
Apple번들 ID만 필수고 나머지는 선택사항이다
- Apple번들 ID 확인방법
- 구성 파일 다운로드
파일 위치 : 해당 프로젝트의 /ROOT/Test(프로젝트 명) 경로에 두어야 한다.
- 파일 적용 화면
- Firebase SDK 추가
cocoapods사용하여 SDK추가
추가방법 및 cocoapods사용방법
- 초기화 코드 추가
사용하는 코드로 복사
- 수정한 코드
import UIKit
import Firebase
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Firebase 초기화
FirebaseApp.configure()
// FCM 메시지 수신 대리자 설정
Messaging.messaging().delegate = self
// 푸시 알림 권한 요청
requestNotificationAuthorization(application)
return true
}
// 알림 권한 요청 메서드
func requestNotificationAuthorization(_ application: UIApplication) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
}
// APNs 토큰 등록
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print("Device Token: \(tokenParts)")
// FCM 토큰 등록
Messaging.messaging().apnsToken = deviceToken
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register for remote notifications: \(error.localizedDescription)")
}
// MARK: MessagingDelegate
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
if let fcmToken = fcmToken {
print("FCM Token: \(fcmToken)")
}
}
// MARK: UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound]) // 앱이 활성화된 동안에도 알림을 표시
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
// 알림 탭 후 행동 처리
print("User tapped the notification")
completionHandler()
}
}
- 설정 완료
3. 프로젝트 설정
- 프로젝트 정보 및 info.plist 파일 확인가능
- Apple APN인증기 설정
- APN 인증 키 발급
발급 방법 링크
- APNs 인증 키 업로드
APNs인증 키 : 발급 방법 링크에서 받은 Authkey_xxxxxxxxxx.p8
키 ID : 발급받은 키의 xxxxxxxxxx에 해당하는 내용
팀 ID : 멤버십 세부 사항에 있는 팀 ID
- 팀 ID
- APNs 인증 키 등록 완료
4. Xcode 설정
- Background Modes, Push Notifications 설정
Automatically manage signing 체크
- Background Modes 추가
- Remote notifications체크
이 옵션은 앱이 Apple Push Notification Service(APNs)에서 푸시 알림을 수신했을 때 앱이 백그라운드에서 특정 작업을 수행할 수 있다
활설화 필요한 경우
백그라운드 데이터 동기화 : 서버에서 새로운 데이터를 푸시 알림으로 알려주고, 앱이 데이터를 자동으로 동기화
예 : 뉴스 앱에서 새 기사가 추가 될 때
알림 데이터 처리 : 사용자가 알림을 클릭하기 전에 앱이 알림 데이터를 미리 처리
예 : 채팅 앱에서 알림 수신 시 메시지를 미리 로드
푸시 알림 기반 기능
예 : 특정 이벤트가 발생했을 때 알림을 받고 백그라운드에서 작업 수행
- Push Notifications 추가
- 푸시 알림(Cloud Messaging) 테스트
- 캠페인 만들기
- 알림 선택
- 테스트 메시지 작성
- 토큰값 확인
- 전송
- 받은 알림
5. 자바 코드 설정
- 자바코드 작성 준비(새 비공개 키 생성은 자바코드에 필요한 키)
- 코드 수정(getFile(받아온 파일 위치작성)
@Configuration
public class FcmConfig {
@Bean
public FirebaseApp firebaseApp() throws Exception {
List<FirebaseApp> apps = FirebaseApp.getApps();
if (!apps.isEmpty()) {
// 이미 존재하는 FirebaseApp 인스턴스가 있는 경우, 첫 번째 인스턴스를 반환
return apps.get(0);
}
File configFile = ResourceUtils.getFile("classpath:fcm/config/wonthelotto-app.json");
FileInputStream serviceAccount = new FileInputStream(configFile);
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();
return FirebaseApp.initializeApp(options);
}
}
- 전송을 위한 코드(전후 기능은 별도 작성필요)
Message message = Message.builder()
.setToken(XCODE에서 받은 토큰)
.setNotification(
Notification.builder()
.setTitle("FCM TEST")
.setBody("테스트")
.build()
)
.putData("verificationCode", "테스트")
.build();
FirebaseMessaging.getInstance().send(message);
- IOS코드 수정
자바에서 전송(.send(message);를 두 번 하는 경우 알림이 두 번 올 수 있다.
import UIKit
import Firebase
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
let SERVER_IP = "전송하는 URL"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// 알림 센터 델리게이트 설정
UNUserNotificationCenter.current().delegate = self
// 푸시 알림 권한 요청
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
if let error = error {
print("알림 권한 요청 실패: \(error.localizedDescription)")
} else {
print("알림 권한: \(granted ? "허용됨" : "거부됨")")
}
}
// 원격 알림 등록
application.registerForRemoteNotifications()
// Firebase Messaging 델리게이트 설정
Messaging.messaging().delegate = self
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// APNs 토큰 등록
Messaging.messaging().apnsToken = deviceToken
print("APNs 토큰 등록 완료: \(deviceToken.map { String(format: "%02.2hhx", $0) }.joined())")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("APNs 등록 실패: \(error.localizedDescription)")
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
// FCM 토큰 수신 및 서버 전송
if let fcmToken = fcmToken {
let deviceId = UIDevice.current.identifierForVendor?.uuidString ?? "UnknownDevice"
print("FCM 토큰: \(fcmToken)")
sendTokenToServer(deviceId: deviceId, token: fcmToken)
}
}
func sendTokenToServer(deviceId: String, token: String) {
// FCM 토큰 서버로 전송
guard let url = URL(string: "\(SERVER_IP)/나머지 URL") else {
print("유효하지 않은 URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: String] = ["deviceId": deviceId, "token": token]
guard let httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) else {
print("HTTP Body 생성 실패")
return
}
request.httpBody = httpBody
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("FCM 토큰 전송 실패: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
print("Token sent successfully")
} else {
print("Failed to send token. Response code: \((response as? HTTPURLResponse)?.statusCode ?? -1)")
}
}
task.resume()
}
// MARK: UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
print("알림 수신 (포그라운드): \(userInfo)")
// 메시지 고유 ID 확인
if let messageId = userInfo["gcm.message_id"] as? String {
print("메시지 ID: \(messageId)")
}
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print("알림 수신 (클릭): \(userInfo)")
completionHandler()
}
}
반응형
'앱 > IOS(애플)' 카테고리의 다른 글
[IOS]APN 인증키(.p8) 발급 및 푸시 알림 설정 (0) | 2025.01.03 |
---|---|
IOS XCODE 프로젝트 생성 (0) | 2025.01.03 |