아틀리에316(1.0.2+17) 업데이트

노영택·2026년 9월 13일

아틀리에316

목록 보기
21/28

2026-09-13 APNs 프로덕션 키 재발급, iOS 광고 SKAdNetwork 설정, 업데이트 안내 기능 점검

오늘은 새 기능 작업은 없었고, 출시 이후 실사용자 쪽에서 터진 두 가지 인프라 문제(푸시 안 옴, 광고 노출 0%)를 잡고, "업데이트 안내가 실제로 뜨는지" 확인해달라는 요청을 코드 레벨에서 점검했다. 둘 다 코드는 멀쩡한데 스토어/콘솔 설정 쪽이 원인이라 삽질 방향을 잘못 잡았다가 되돌아온 과정이 길었다.

1. 푸시가 실사용자 기기에만 401로 실패했다

시뮬레이터/개발 기기로는 잘 오던 푸시가, 앱스토어에 실제로 설치한 기기에서는 전부 실패한다는 리포트가 들어왔다.

처음엔 entitlement를 의심했다

send-push Edge Function 로그를 보려고 에러 상세를 그대로 노출하는 디버그 버전을 임시로 배포했다.

401 THIRD_PARTY_AUTH_ERROR / BadEnvironmentKeyInToken

BadEnvironmentKeyInToken이라는 메시지 때문에 처음엔 "iOS 앱 자체가 개발용 aps-environment로 서명된 게 아닌가"로 방향을 잡았다. 앱 번들의 엔타이틀먼트를 열어 확인했더니 실제로 flutter build ipa가 만든 로컬 IPA는 개발용 entitlement로 서명돼 있었다 — 그런데 App Store에 실제로 배포된(사용자 기기에 깔린) 빌드는 Apple이 업로드 시점에 프로덕션 entitlement로 자동 재서명한다는 걸 확인하면서 이 가설은 기각했다. 로컬 빌드 산출물만 보고 있었던 거다.

진짜 원인은 Apple 쪽 키 자체였다

Apple Developer 콘솔에서 Firebase 프로덕션 슬롯에 올라가 있던 키(9V367KTB4Q, 2026.09.03 발급)의 상세를 다시 열어보니 Enabled Services가 [Sandbox]로만 찍혀 있었다. 이름이나 발급 경로 어디에도 "프로덕션용"이라는 표시가 없었는데 실제로는 처음부터 Sandbox 전용으로 발급된 키였던 것 — Environment는 발급 후에는 수정도 안 된다.

키Environment결과
9V367KTB4Q (기존, 09.03 발급)Sandbox 전용실사용자 기기(production) 401
ZN9Z73XWKH (신규, 09.13 발급)Sandbox & Production정상

새 키를 "Sandbox & Production"으로 발급받아 Firebase 콘솔 프로덕션 APNs 슬롯을 교체하고, 디버그 버전을 되돌린 뒤 다시 배포해서 확인했다.

앞으로 APNs 키를 새로 만들 땐 Environment를 반드시 "Sandbox & Production"으로 선택할 것 — 기본값이나 무심코 고르면 Sandbox 전용으로 굳어버려서 재발급 말고는 답이 없다.

2. iOS 광고가 요청은 들어오는데 노출이 0건이었다

Android(비공개 테스트)는 광고가 정상 노출되는데, iOS(정식 출시)는 요청 12건에 노출이 0건이었다. 리워드 광고 코드 자체(로드 실패 시 토스트, 표시 중 스피너, nonPersonalizedAds: true)를 다시 봤지만 로직엔 문제가 없었다.

원인: SKAdNetworkItems가 통째로 빠져 있었다

Info.plist에 AdMob 앱 ID는 등록돼 있었는데 SKAdNetworkItems가 아예 없었다. iOS 14부터는 이게 없으면 대부분의 광고 네트워크가 응찰 자체를 안 해서 매치율이 0%로 떨어진다 — 요청은 AdMob 서버까지 도달하니 코드/네트워크 문제로는 안 보이고, 정작 원인은 입찰 참여 자격 자체가 없었던 것.

<key>SKAdNetworkItems</key>
<array>
  <dict>
    <key>SKAdNetworkIdentifier</key>
    <string>cstr6suwn9.skadnetwork</string>
  </dict>
  <!-- ... 구글 AdMob 퀵스타트 가이드 권장 목록, 총 50개 ... -->
</array>

구글 AdMob 퀵스타트 가이드(developers.google.com/admob/ios/quick-start)에 있는 식별자 50개를 그대로 추가했다. ATT(App Tracking Transparency) 권한은 따로 안 붙였는데, 이미 AdRequest(nonPersonalizedAds: true)로 비개인화 광고만 요청하는 구조라(admob_ad_service.dart) 트래킹 동의 자체가 필요 없는 케이스라서다.

버전 올리다 한 번 걸렸다

Info.plist를 고쳤으니 새 빌드를 올려야 하는데, 직전 승인된 마케팅 버전(1.0.0+15)으로 빌드 번호만 올려 제출하려 하니 App Store Connect가 "Invalid Pre-Release Train ... is closed for new build submissions"로 거부했다. 이미 승인된 마케팅 버전엔 새 빌드를 못 얹는다 — patch 자리를 올려 1.0.1+16으로 다시 시도했는데 이것도 막혀서, 결국 1.0.2+17까지 올리고서야 제출 가능한 상태가 됐다.

IPA는 로컬에서 빌드 완료했고(objective_c.framework가 아카이브에 안 딸려 들어간 것도 확인), Xcode/Transporter로 직접 업로드하는 것만 남았다 — 로컬 업로드 도구는 파일 크기 제한 때문에 못 쓴다.

3. "업데이트 안내가 실제로 뜨나" 점검

앱 시작 시 최신 버전이 아니면 알려주는 기능(upgrader 패키지, UpgradeAlert)이 잘 작동하는지 확인해달라는 요청이 있어서 코드를 다시 훑었다. 결론부터 말하면 코드는 문제없는데 실기기에서 다이얼로그가 뜨는 걸 눈으로 본 적은 아직 한 번도 없다.

  • lib/main.dart:372 부근에서 MaterialApp.router의 builder가 UpgradeAlert(child: child!)로 앱 전체를 감싸는 구조라 항상 마운트된다.
  • 버전 비교는 package:version의 semver > 연산자를 쓰기 때문에 "1.0.10"이 "1.0.9"보다 낮게 취급되는 문자열 비교 버그는 없다.
  • iOS는 iTunes Lookup API, Android는 Play 스토어 페이지 스크레이핑으로 최신 버전을 조회하는데 — Android는 Play Console에 아직 등록을 안 해서 스토어 페이지 자체가 없다. 등록 전까지는 이 기능이 Android에서 작동할 수 없는 게 정상.
  • 9/8 dSYM 작업 중 실수로 project.pbxproj의 버전이 하드코딩됐던 적이 있는데(그러면 iOS에서 항상 구버전으로 읽힘) 9/11 커밋에서 이미 고쳐진 것도 재확인했다.
  • upgrader 패키지 자체의 알려진 함정도 GitHub 이슈로 확인해뒀다: 사용자가 다이얼로그 버튼을 안 누르고 앱을 그냥 꺼버리면 그 버전은 "이미 보여준 걸로" 기록돼서 다시 안 뜬다(#379, #444). 스토어 응답이 비어있으면 FormatException으로 조용히 실패하는 것도 알려진 이슈(#94).

코드 변경은 없었고, 다음에 "업데이트 안내 왜 안 떠요" 문의가 오면 바로 참고할 수 있게 위 내용을 메모리에 남겨뒀다.

오늘 한 것 정리

  • Apple Developer 콘솔에서 Sandbox 전용으로 잘못 발급됐던 APNs 프로덕션 키를 "Sandbox & Production"으로 재발급, Firebase 교체 후 실기기 푸시 도착까지 확인
  • Info.plist에 SKAdNetworkItems(구글 권장 50개) 추가 — iOS 광고 매치율 0% 문제 해결
  • 버전 1.0.0+15 → 1.0.2+17로 상향(App Store Connect의 승인된 버전 재제출 거부 때문에 두 번 올림), IPA 로컬 빌드 완료
  • upgrader/UpgradeAlert 구현 상태 코드 레벨 점검 — 문제 없음을 확인, 실기기 검증 이력·Android 등록 여부 등 미확인 사항을 메모리에 정리

남은 것

출시 전 필수

  • IPA를 Xcode/Transporter로 App Store Connect에 실제 업로드하고 심사 제출 (버전 1.0.2+17, SKAdNetwork 수정 포함)

그 외

  • Android Play Console 등록 (미등록 상태라 업데이트 안내 기능도 Android에서는 작동 불가)
  • 업데이트 안내 기능 실기기 검증(구버전 설치 → 스토어에 새 버전 있을 때 다이얼로그가 실제로 뜨는지)
  • iOS 광고 노출 정상화 여부는 새 빌드 심사 통과 후 AdMob 콘솔에서 재확인 필요
profile
https://github.com/NohYeongtaek

0개의 댓글