오늘 TIL의 핵심은 결국 iOS에서는 APNs가 주체적으로 푸시를 담당하고 있다는 것.
우리가 파이어베이스를 쓰는 이유는 자체 서버를 사용해도 되는데 서버가 각 기기 별(애플/안드 등) 분기처리가 복잡함
파베가 알아서 분기처리를 해주기 때문에 보통 파베랑 같이 처리해주는 곳이 많음
출프에서는 어떤 유저가 어떤 토큰을 쓰는지 현재 모르는 상황이라 전체 메시지를 보낼 수만 있는 상황이다.
그럼에도 불구하고, 전체 유저에게 보내기에는 아쉬운데 약간의 구분을 하고 싶을 수 있을 때,
예를 들어, 투두를 100% 달성하는 유저한테 "할 일 왜 다 안하셨어요?"라고 보내면 안되잖아? 의미없는 푸시가 되버리는!!
그렇기 때문에 파베에서 약간의 대응을 할 수 있게끔 주제 단위로 보낼 수 있는 기능을 제공한다.
토픽 지정을 개발자가 마음대로 할 수 있어서 A라는 유저가 "weather"라는 내용을 구독한다는 형식으로 해서
메시지를 보내는 페이지에서 String 값으로 작성을 하면 입력을 받은 유저에게만 데이터를 (푸시를) 보내줄 수 있다.
요론 기능이 있구나~ 정도...? 알면 된다..!
didReceive 또는 willPresent 부분에서 푸시를 눌렀을 때 특정 화면으로 이동하고 싶다? 그러면 어케해?
response.notification.request.content.title
response.notification.request.content.userInfo
response.notification.request.content.body
이 아이들로 해주면 되는데...
근데 일단,,, 모든 화면 플로우에 대응을 어느 정도 해줘야 한다고 한다.
그래야 사용자가 특정 화면에서 뒤로가기 같은 기능도 사용할 수 있기 때문이다.
(카톡 같은 대겹들은 그런 모든 플로우를 다 대응한다는 것이지.. 실로 대단한 일이 아닐 수 없다.. ㅘㅜ...)
여튼 현재 최상위 뷰컨을 판단해주는 메소드를 통해서 구분을 해줄 거다..
1. 탭바 위의 뷰컨
2. 네비 연관 뷰컨
3. 모두 무관한 뷰컨
extension UIViewController {
// 연산 프로퍼티를 호출하면 아래 메소드가 호출되어 동작
var topViewController: UIViewController? {
return self.topViewController(currentViewController: self)
}
// 최상위 뷰컨트롤러를 판단해주는 메소드
func topViewController(currentViewController: UIViewController) -> UIViewController {
// 1. 타입캐스팅이 된다면 탭바 컨트롤러에서 선택된 뷰컨을 가져오면 된다.
if let tabBarController = currentViewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topViewController(currentViewController: selectedViewController)
// 2. 네비뷰컨으로 타입캐스팅이 된다면 현재 보고 있는 뷰컨을 가져오면 된다.
} else if let navigationController = currentViewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController {
return self.topViewController(currentViewController: visibleViewController)
// 3. 위와 무관한 일반 뷰컨
} else if let presentedViewController = currentViewController.presentedViewController {
return self.topViewController(currentViewController: presentedViewController)
} else {
return currentViewController
}
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
// 재구성 사용 중지됨: APNs 토큰과 등록 토큰 매핑
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
// foreground에서 알림 수신: 로컬/푸시 동일
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// 특정화면에서는 포그라운드 푸시를 제한할 수 있다
guard let viewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController?.topViewController else { return }
print("😊", viewController)
// SettingViewController에서는 푸시를 제한한다.
if viewController is SettingViewController {
completionHandler([])
} else {
completionHandler([.badge, .sound, .banner, .list])
}
}
// 푸시 클릭
// 유저가 푸시를 클릭했을 때에만 수신 확인 가능
// 특정 푸시를 클릭하면 특정 상세 화면으로 화면 전환 >
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print("사용자가 푸시를 클릭했습니다.")
print(response.notification.request.content.title)
print(response.notification.request.content.userInfo)
print(response.notification.request.content.body)
let userInfo = response.notification.request.content.userInfo
if userInfo[AnyHashable("sesac")] as? String == "project" {
print("홈 화면으로 넘긴다.")
} else {
print("그냥 냅둔다.")
}
// topViewController는 우리가 만든 것
guard let viewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController?.topViewController else { return }
print("😊", viewController)
// 클래스가 ViewController라면 그냥 무조건 SettingViewController로 넘겨주는 것임
if viewController is ViewController {
viewController.navigationController?.pushViewController(SettingViewController(), animated: true)
}
if viewController is ProfileViewController {
viewController.dismiss(animated: true)
}
if viewController is SettingViewController {
viewController.navigationController?.popViewController(animated: true)
}
}
}
'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글
[iOS] Method Swizzling이 뭔가? (feat. 인스턴스/타입 메소드) (3) | 2022.10.13 |
---|---|
[iOS] Remote Notification (2) | 2022.10.11 |
[iOS] 다국어 지원 i18n, l10n (1) | 2022.09.06 |
[iOS] 안간단한 MVVM 안간단하게 톺아보기 (3) | 2022.08.31 |
[iOS] URLSession(1) (0) | 2022.08.30 |