알람 앱은 그냥 만들어도 귀찮지만 리액트 네이티브로 만들면 더 귀찮다⏰ Part3 — iOS
안드로이드와 iOS에서 알람 앱을 만드는 방법과 그 위에 리액트 네이티브를 끼얹는 개발기
Content
Part 3 — iOS ← Here 🤚
iOS 네이티브 구현
iOS는 구현 방법에서 꽤나 hacky 한 방법을 썼다.
iOS는 Notifcation API에 대해 이해가 쉽지 않은 OS이다.
흔히 착각하는 개념들은 APNs, FCM, Remote notification 등인데, Local Notification 은 iOS 10부터 도입된 UserNotifications
API를 사용하여 독립적으로 구현될 수 있고 상기된 개념들과 무관하다.
어쨌든 모든 구현엔 UserNotifications
API만 사용했다.
알람 기능
reserveAlarm
함수는 각 UNNotificationRequest
를 각 요일, 각 반복에 대하여 각기 다른 identifier로 설정한다. 이렇게 하면 동일한 알람들이 안드로이드에서와같이 자동으로 collapse 되지 않지만 딱히 이런 식으로 안 하고 반복되게 Notification을 오게 할 수는 없어 보인다.
대충 이렇게 UNCAlendarNotificationTrigger와 함께 적절히 시간을 설정해서 호출해 준다.
앞선 글에서 언급했듯이 iOS에서는 반복 알람을 안드로이드 구현과 조금 다르게 했는데
“alarm-{weekday}-{second}”
와 같이 각 request의 identifier가 구성되었다.
예를 들어, 월요일 6시 10분에 울리는 알람은 alarm-2–0
, alarm-2–5
… 처럼 identifier를 갖는다.
뭔가 이런 식으로 알람을 반복해서 보내도 iOS에서 문제가 생기지 않을까하고 서늘한 느낌에 구글링을 해봤는데 역시나 Local Notification은 최대 64개가 예약이 되어있을 수 있다고 하니, 적절한 throttle 작업을 거쳐주길 바란다.
안드로이드에서는 AlarmWorker
라는 설정된 요일과 관계없이 해당 시간대에 매일 실행되는 Work
를 정의했지만 iOS에서는 그럴 필요 없이 해당되는 요일만 모두 설정했다.
알람 취소는 더 간단하다. 만약 모든 알람을 취소해 주고 싶다면
alarm-1–0
… alarm-7–55
까지 모든 가능한 identifier에 대해 취소를 해주면 된다.
여기서 주의해야 하는 것은 안드로이드에서 AlarmWorker가 반복 알림을 새롭게 다시 실행시켜주는 것과 다르게 iOS에서는 각 반복들이 모두 request로 큐에 들어가 있기 때문에
반복 알림에 대해 취소를 할 때 오늘 반복 알림만 취소를 해야 한다는 것이다. 따라서
alarm-week-5
… alarm-week-55
만 취소해 주면 된다(내 구현은 1분만 5초마다 울리게 되어있어서 0 ~ 55까지의 값을 가진다).
이제 믿거나 말거나 알람이 잘 온다.
알람 탭과 딥링크
로컬 알람을 보낼 때 UNMutableNotificationContent
의 userInfo
에 딥링크 정보를 담아서 예약한다.
나 같은 경우는 이 알람 컨텐츠에 Stop action을 넣어서 category를 추가했기 때문에 유저가 알람을 탭 한 건지 끄기를 누른 건지 UNUserNotificationCenterDelegate
의 메서드에서 didReceive
함수를 조금 신경 써서 구현해 줘야 했다.
만약 탭을 했다면 deeplink를 그대로 UIApplication의 open 메소드를 이용해 AppDelegate
의 openURL
이 direct로 호출되게 해주고, 그렇지 않다면 안드로이드에서와같이 네이티브 모듈의 static string에 설정을 해준다.
이 static string을 RN에서 poll 해 오는 시점은 AppState
가active
가 될 때이므로 유저가 background에서 foreground로 다시 와도 기분 좋게 딥링크를 poll 해올 수 있다.
마지막으로 iOS에서 Swift로 만든 Native module을 objective-c로 포팅 해주기 위해 대충 Objective-C 파일에 다음과 같이 RCT_EXTERN_MODULE
, RCT_EXTERN_METHOD
를 이용해 RN에서 호출할 수 있도록 정의해 주면 된다.
후기
알람 기능 구현 개발기가 끝났다. 개발하면서 가끔 재미있었지만 정말 귀찮은 기능이었다. 난 일단 개발을 하면서 빌드가 오래 걸리는 iOS를 자꾸 빌드 시키면서 개발해야 되는 게 싫다.
코틀린이랑 스위프트도 문법이 기억이 잘 안 나서 대충 감으로 구현했다. 여하튼 스위프트는 모르겠고 코틀린은 JS보단 좋은 언어이다.
여담으로 이 작업을 하면서 FCM 쪽 기능도 추가했는데 iOS에서 onReceiveRemoteNotification
함수가 OS 단에서 뭔 이상한 ApplicationPolicy 쪽에 서 throttling이 걸려 호출이 안되는 이슈를 코드 문제인 줄 알고 react-native-firebase/messaging 구현체를 Objective-C도 모르는 내가 샅샅이 뜯어봐야 했다. 그래서 최근에 Swift보다 Objective-C를 더 봤다.
곧 이 기능이 회사 앱에 출시되는데 버그 없이 잘 되려나 모르겠다.
- Github
- Website
- Medium Blog, Dev Blog, Naver Blog
- Contact: mym0404@gmail.com