iOS 27 SDK로 앱을 빌드하면서 UIScene lifecycle을 적용하지 않으면, 앱은 아예 실행되지 않습니다. 그리고 실행되지 않는 앱은 푸시 등록 자체를 하지 않기 때문에, 크래시 리포트에 푸시 관련 원인이 전혀 남지 않은 채 알림이 조용히 멈춥니다. 증상만 보면 전송 문제 같지만, 실제로는 실행(launch) 문제입니다.
이 부분이 팀을 당황하게 만드는 이유는 푸시와 앱 실행이 코드상으로도, 담당자의 머릿속에서도 전혀 다른 영역처럼 느껴지기 때문입니다. iOS 27은 이 둘을 하나로 묶어버렸습니다. 이 글에서는 정확히 무엇이 깨지는지, 알림을 멈추게 하는 장애 흐름, 영향을 받는 대상, 그리고 이를 해결하기 위한 마이그레이션 체크리스트를 다룹니다. Pushwoosh는 고객 인게이지먼트 플랫폼이며, iOS SDK가 이미 이 전환을 처리하고 있지만, 아래 해결 방법은 저희 SDK 사용 여부와 관계없이 동일하게 적용됩니다.
이 글은 iOS 27 릴리스 대응 가이드의 일부입니다. SDK 작업을 진행하는 김에 실제 디바이스 도달 범위도 함께 확인해보시길 권합니다.
실제로 무엇이 깨지는가
Apple은 WWDC25에서 iOS 26 다음 버전부터 최신 SDK로 빌드된 모든 UIKit 앱에 UIScene lifecycle을 필수로 요구한다고 발표했습니다. iOS 27이 바로 그 버전이며, 이 요구사항은 이미 적용되고 있습니다.
중요한 것은 트리거 조건이며, 대부분의 우려성 글들이 이 부분을 잘못 이해하고 있습니다. 강제 적용은 Xcode 27에서 iOS 27 SDK로 빌드할 때 발생하는 것이지, 사용자가 기존 앱을 iOS 27 기기에서 실행한다고 해서 바로 발생하는 것이 아닙니다. 현재 배포된 빌드는 업데이트된 기기에서도 그대로 동작합니다. 문제가 실제로 발생하는 시점은 새 SDK로 컴파일한 다음 릴리스부터입니다. 이 차이 덕분에 시간적 여유가 생기지만, 그것도 다음 제출 전까지입니다.
반면 바뀌지 않는 부분도 있으며, 우려성 기사들이 흔히 과장하는 지점이 바로 여기입니다. APNs 흐름 자체는 전혀 변경되지 않습니다. 여전히 권한을 요청하고, registerForRemoteNotifications()를 호출하며, didRegisterForRemoteNotificationsWithDeviceToken에서 디바이스 토큰을 수신합니다. 이 콜백은 그대로 AppDelegate에 남아 있으며, iOS 27 기준으로 이를 옮길 scene 기반의 대응 API는 존재하지 않습니다. 푸시 메커니즘 자체는 문제가 없습니다. Apple이 바꾼 것은 실행 과정입니다.
푸시를 멈추게 하는 장애 흐름
scene manifest가 없는 앱이 iOS 27 SDK로 빌드되면, 다음 순서로 장애가 발생합니다.
- UIKit이 실행 시점에 scene 적용 여부를 확인하는데, Info.plist에
UIApplicationSceneManifest가 없습니다. - AppDelegate의 어떤 메서드도 실행되기 전에 앱이 종료됩니다.
application(_:didFinishLaunchingWithOptions:)가 전혀 실행되지 않으므로,registerForRemoteNotifications()도 호출되지 않습니다.- 등록이 이루어지지 않으니
didRegisterForRemoteNotificationsWithDeviceToken도 절대 호출되지 않고, 앱은 APNs 토큰을 받지 못합니다. - 토큰이 없으니 전송도 없습니다. 그리고 앱이 실행 시점에 크래시했기 때문에, 로그는 실행 과정을 가리킬 뿐 알림 파이프라인을 지목하지 않습니다.
이 문제가 디버깅 시간을 많이 잡아먹는 이유는 증상과 원인이 서로 멀리 떨어져 있기 때문입니다. 전송이 안 되는 걸 보고 푸시 제공업체, 페이로드, 인증서부터 점검하게 됩니다. 하지만 실제 원인은 알림과 전혀 무관한, 3단계 위쪽에 있는 manifest 파일 안에 있습니다.
영향을 받는 대상
이 요구사항은 UIKit 앱을 대상으로 하지만, 실제 영향 정도는 스택에 따라 달라집니다.
| 스택 | 영향도 |
|---|---|
| 네이티브 UIKit | 직접 영향을 받습니다. AppDelegate 라이프사이클을 직접 관리한다면 마이그레이션도 직접 책임져야 합니다. |
| SwiftUI | 이미 scene 기반인 App 프로토콜과 WindowGroup을 사용 중이라면 위험도가 낮습니다. 커스텀 윈도우 로직을 갖춘 UIApplicationDelegateAdaptor에 여전히 의존하는 앱은 점검이 필요합니다. |
| Flutter | 최신 버전에서는 AppDelegate를 수정하지 않은 앱은 자동으로 마이그레이션되지만, 커스텀 네이티브 로직은 직접 마이그레이션해야 합니다. |
| React Native | 네이티브 모듈, 그리고 AppDelegate에 훅을 거는 서드파티 SDK 래퍼 여부에 따라 달라집니다. |
App 프로토콜과 WindowGroup을 사용 중이라면 위험도가 낮습니다. 커스텀 윈도우 로직을 갖춘 UIApplicationDelegateAdaptor에 여전히 의존하는 앱은 점검이 필요합니다.크로스플랫폼 팀에게 진짜 까다로운 부분은 프레임워크 자체가 아니라 그 위에 얹힌 SDK들입니다. AppDelegate를 감싸는 방식으로 설치되는 푸시나 분석 SDK는, 해당 벤더가 scene을 지원하기 전까지 마이그레이션 자체를 막을 수 있습니다. @main 진입점을 의존성 하나가 쥐고 있다면, 기다려야 하는 건 우리 팀의 릴리스뿐만이 아닙니다. 실제로 팀이 직접 통제할 수 있는 부분은 이미 다 끝났는데도, 협조하지 않는 의존성 하나 때문에 마이그레이션이 2주간 멈춘 사례도 있었습니다. 마이그레이션이 하루 만에 끝날 거라 가정하기 전에, 사용 중인 푸시 SDK의 scene 호환성부터 확인하세요. 저희 Flutter 플러그인을 사용 중이라면, 알려진 마이그레이션 이슈 페이지부터 확인하시길 권합니다.
마이그레이션 체크리스트
이 해결 방법 자체는 2019년에 scene이 도입된 이후로 바뀐 적이 없습니다. 바뀐 것은 이제 선택이 아니라 필수가 되었다는 점뿐입니다.
- scene manifest를 추가하세요. Info.plist에
UIApplicationSceneManifest를 추가하거나, UIApplicationDelegate와 UISceneDelegate 메서드를 통해 코드로 scene을 구성합니다. - SceneDelegate를 생성하세요. 없다면 추가하고, 실제로 타깃에 컴파일되는지 확인합니다. 프로젝트에 SceneDelegate 파일은 있지만 빌드 소스에는 추가되지 않은 경우가 흔한 함정입니다.
- 윈도우 생성 로직을 이전하세요. 윈도우 소유권이 AppDelegate에서 빠집니다.
UIWindow(frame:)를UIWindow(windowScene:)로 교체하고, 루트 뷰를 scene에서 호스팅합니다. - UI 라이프사이클 처리를 이전하세요. 포그라운드, 백그라운드, active/inactive 전환이 UISceneDelegate로 이동합니다. 마이그레이션 후 UIKit은 AppDelegate의 UI 상태 메서드를 더 이상 호출하지 않으므로, 그대로 남겨둔 코드는 조용히 동작을 멈춥니다.
- 푸시 등록 로직은 그대로 두세요. 토큰 등록과 관련 콜백은 AppDelegate에 그대로 둡니다. 대칭성을 맞추겠다고 옮기지 마세요.
- URL 및 딥링크 처리를 마이그레이션하세요. 수신 URL은 이제 scene 메서드를 통해 도착합니다. 푸시가 특정 화면을 여는 구조라면, 이 단계가 딥링크를 계속 동작하게 만드는 핵심입니다.
- 다시 빌드하고 토큰 발급을 확인하세요. iOS 27 SDK로 빌드하고 실행해서 APNs 토큰을 정상적으로 받는지 확인합니다. 받지 못한다면 iOS 오류 트러블슈팅 가이드부터 확인하세요. 릴리스 전에 실제 빌드로 검증하고, 릴리스 후로 미루지 마세요.
AppDelegate는 그대로 유지하세요. “AppDelegate가 사라진다”는 표현을 읽고 팀들이 흔히 오해하는 부분인데, 사라지는 게 아닙니다. 역할이 프로세스 및 앱 레벨 이벤트로 좁혀지고, UI 라이프사이클만 scene으로 이동할 뿐입니다. 푸시 등록은 앱 레벨의 문제이며, 바로 그렇기 때문에 그대로 남아 있는 것입니다.
푸시 하나에만 의존하는 것이 취약한 이유
한 걸음 물러서서 보면, 팀에서 거의 아무도 열어보지 않는 파일 안의 manifest 키 하나가 다음 릴리스에서 전체 푸시 채널을 완전히 멈출 수 있습니다. 단일 전송 채널에 이만큼의 취약성이 실려 있는 셈입니다.
게다가 이는 푸시가 원래 가지고 있던 한계 위에 얹어지는 문제입니다. 바로 opt-in입니다. 잘 설계된 권한 요청 전략이 있어도, 상당수 사용자는 애초에 푸시 권한을 허용하지 않으므로, 좋은 날에도 푸시는 전체 사용자 중 일부에만 도달합니다. 이번과 같은 플랫폼 장애는 도달 가능한 대상과 실제로 도달한 대상 사이의 격차를 더 벌릴 뿐입니다.
이런 변화를 잘 버텨내는 팀은 단일 채널에 의존하지 않는 팀입니다. 푸시가 이메일, SMS, 인앱 메시지와 나란히 있는 여러 전송 수단 중 하나일 때, 한 플랫폼의 실행 시점 회귀는 도달 범위를 완전히 없애는 게 아니라 일부만 줄이는 데 그칩니다. 이렇게 하면 이번 같은 Apple의 갑작스러운 변경에 대응할 여유를 미리 확보하게 됩니다.
SDK 작업이 진행 중인 지금, 애초에 보낼 가치가 있는 알림이란 무엇인지도 함께 점검해보기 좋은 시점입니다.
Pushwoosh와 함께 iOS 27 푸시 설정을 점검해보세요
Pushwoosh SDK는 이미 iOS 27의 scene lifecycle을 지원하며, 멀티채널 구성 덕분에 단일 플랫폼의 장애가 전체 알림 전략을 무너뜨리지 않습니다. 마이그레이션 중 등록이 제대로 되지 않는다면, iOS SDK FAQ에서 흔한 문제들을 다루고 있습니다. 푸시 등록이 이번 전환을 잘 견디는지 제3자의 시각으로 검토받고 싶다면, 저희가 함께 인테그레이션을 살펴봐드릴 수 있습니다.
자주 묻는 질문
didRegisterForRemoteNotificationsWithDeviceToken 콜백은 그대로 AppDelegate에 남습니다. iOS 27에는 이를 옮길 scene 기반 대응 API가 없으며, 옮기려는 시도 자체가 실수입니다. scene으로 이동하는 것은 UI 라이프사이클뿐입니다.