Skip to content

[FIX] Android release 빌드 크래시 및 FCM 알림 미표시 수정(#361, #362) - #363

Merged
jeonbinggu merged 3 commits into
developfrom
fix/android-release-r8-kakao-crash(#361)
Aug 12, 2026
Merged

[FIX] Android release 빌드 크래시 및 FCM 알림 미표시 수정(#361, #362)#363
jeonbinggu merged 3 commits into
developfrom
fix/android-release-r8-kakao-crash(#361)

Conversation

@jeonbinggu

Copy link
Copy Markdown
Contributor

🔀 Pull Request Title

fix: Android release 빌드 크래시 및 FCM 알림 미표시 수정


🎞️ 주요 코드 설명

1. R8이 Kakao SDK serializer를 제거해 첫 화면에서 앱이 종료되던 문제 (#361)

#352에서 minifyEnabled true를 켠 뒤 R8이 Kakao SDK의 kotlinx.serialization 생성 클래스($$serializer / Companion)를 통째로 제거했습니다. KakaoJson이 serializer를 리플렉션으로 조회해서 R8이 참조를 볼 수 없기 때문입니다.

KakaoSdk.init이 등록한 AppLifecycleObserver가 포그라운드 진입 시 저장된 토큰을 역직렬화하면서 SerializationException이 발생 → 첫 화면 직후 종료.

# android/app/proguard-rules.pro
-keep class com.kakao.sdk.**.model.* { <fields>; }

수정 전 mapping.txtOAuthToken$$serializer가 아예 없었고(제거됨), 수정 후 $$serializer 43개가 모두 유지되는 것을 release 빌드로 확인했습니다. Kakao SDK 2.23.0의 @Serializable 클래스는 전부 *.model 패키지(auth/common/share/template/user)에 있어 이 한 줄로 빠짐없이 덮입니다.

2. 알림 아이콘 리소스 순환 참조 (#362)

mipmap-anydpi-v26/ic_launcher_foreground.xml같은 이름의 리소스inset으로 감싸고 있었습니다. API 26+에서 @mipmap/ic_launcher_foreground를 해석하면 anydpi-v26이 다시 선택되어 자기 자신을 가리키는 순환이 됩니다.

<!-- 제거된 파일 -->
<inset android:drawable="@mipmap/ic_launcher_foreground"
       android:inset="16.7%" />   <!-- ← 자기 자신 -->

이 XML이 같은 이름의 density PNG를 가려 리소스를 어떤 경로로도 로드할 수 없게 만들었고, manifest의 default_notification_icon이 이 리소스를 가리키므로 SystemUI가 아이콘 생성에 실패해 알림을 게시 직후 제거했습니다. 런처 아이콘이 기본 안드로이드 아이콘으로 나오던 것도 같은 원인입니다.

E/Icon    : Resources$NotFoundException: Drawable com.finders:mipmap/ic_launcher_foreground
W/NotifInflater: InflationException: Couldn't create icon StatusBarIcon(...)
I/NotificationListener: received notification removed event - com.finders

3. google-services.json 추적 재개 (#361)

#352에서 .gitignore에 추가되며 git에서 빠졌는데, 이 파일이 없으면 app/build.gradle의 try/catch가 조용히 삼켜 google-services 플러그인이 미적용된 APK가 나옵니다. 다른 머신·CI 빌드에서 Firebase 리소스 없이 푸시가 에러 없이 죽습니다.

API 키는 패키지명 + SHA-1로 제한되어 비밀정보가 아니며, iOS의 GoogleService-Info.plist는 이미 커밋되어 있어 비대칭이었습니다.


📌 PR 설명

이번 PR에서 어떤 작업을 했는지 요약해주세요.


📷 스크린샷

UI 변경 없음. (알림 표시 동작은 아래 검증 결과 참고)

단계 결과
기기 토큰 서버 등록 NOTIFICATION_201, device_token 1행
관리자 발송 → FCM successCount: 1 / failureCount: 0
기기 알림 표시 헤즈업 배너 + 알림 트레이
탭 → 딥링크 이동 PHOTO_FEED/photoFeed

💬 참고

  • 후속 필요 (별도 이슈): 상태바 알림 아이콘이 빈 사각형으로 표시됩니다. Android는 상태바 아이콘의 알파 채널만 써서 실루엣으로 그리는데 현재 지정된 리소스가 단색 알파 아이콘이 아니기 때문입니다. ic_stat_* 전용 drawable을 만들고 manifest를 그쪽으로 돌려야 합니다. 제거한 XML의 원래 의도(적응형 아이콘 여백)도 순환 없이 다시 잡아야 합니다.
  • iOS 미검증: 본 PR 변경사항은 Android 전용입니다. iOS는 알림 아이콘 리소스를 런타임에 해석하는 경로가 없어 #362의 영향을 받지 않습니다. iOS 푸시 수신은 별도 확인 중입니다.
  • 서버 측 댓글·좋아요 자동 발송은 BE #730에서 구현·배포 완료되어 FE 추가 작업은 없습니다.

jeonbinggu and others added 3 commits August 12, 2026 18:04
KakaoJson이 serializer를 리플렉션으로 조회해 R8이 참조를 보지 못하고,
컴파일 시 생성된 $$serializer/Companion을 미사용으로 판단해 제거했다.
저장된 토큰을 역직렬화하는 순간 SerializationException이 발생하고,
KakaoSdk.init이 등록한 AppLifecycleObserver가 포그라운드 진입 시
그 토큰을 읽으므로 첫 화면 직후 앱이 종료됐다.

2.23.0 기준 @serializable 클래스는 전부 *.model 패키지에 있어
(auth/common/share/template/user) 한 줄로 43개가 모두 유지된다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#352에서 .gitignore에 추가되며 git에서 빠졌는데, 이 파일이 없으면
app/build.gradle의 try/catch가 조용히 삼켜 google-services 플러그인이
미적용된 APK가 나온다. 다른 머신·CI 빌드에서 Firebase 리소스 없이
푸시가 에러 없이 죽으므로 다시 추적한다.

API 키는 패키지명+SHA-1로 제한되어 비밀정보가 아니며,
iOS의 GoogleService-Info.plist는 이미 커밋되어 있어 비대칭이었다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mipmap-anydpi-v26 의 ic_launcher_foreground.xml / ic_launcher_background.xml 이
각각 @mipmap/ic_launcher_foreground, @mipmap/ic_launcher_background 를 참조한다.
API 26+ 에서 이 이름을 해석하면 anydpi-v26 이 다시 선택되어 자기 자신을 가리키는
순환이 되고, 같은 이름의 density PNG 를 가려 리소스 로드가 불가능해진다.

manifest 의 default_notification_icon 이 이 리소스를 가리키므로 SystemUI 가
알림 아이콘 생성에 실패하고 알림을 게시 직후 제거한다. FCM 발송이 성공해도
화면에 아무것도 뜨지 않던 원인이다. 런처 아이콘이 기본 아이콘으로 나오던 것도 같은 이유다.

두 파일을 제거하면 density PNG 가 정상적으로 선택된다.
inset 여백은 이 순환 없이 다시 잡아야 한다.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
finders Ready Ready Preview Aug 12, 2026 2:26pm

@jeonbinggu
jeonbinggu merged commit 818636c into develop Aug 12, 2026
3 checks passed
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown

Claude 자동 리뷰
✅ 이슈 없음

검사 범위: 로직 오류 · 엣지 케이스/런타임 · 컨벤션 준수 (CLAUDE.md, .claude/skills/tdd-clean-arch/references/*) · typecheck/lint 미실행

  • typecheck/lint 미실행 사유: 변경 파일 5건이 전부 Android 네이티브 설정(.gitignore, google-services.json, proguard-rules.pro, mipmap XML)이고 TS/JS 변경이 0건이라, 이 PR의 변경 라인에 귀속될 수 있는 결과가 나오지 않습니다.
  • 컨벤션 문서는 전부 프론트엔드(React/TS) 대상이라 이번 변경에 적용 가능한 규칙이 없습니다.

리포지토리 실제 상태로 확인한 항목:

  • applicationId "com.finders"(android/app/build.gradle)와 google-services.jsonpackage_name이 일치 → google-services 플러그인의 client 매칭 실패로 빌드가 깨지지 않습니다. com.google.gms:google-services:4.4.4 classpath도 android/build.gradle에 선언되어 있어, 파일 재추적으로 플러그인이 실제 적용되는 경로가 성립합니다.
  • mipmap-anydpi-v26/ 의 XML 2개 삭제 후에도 ic_launcher.xml / ic_launcher_round.xml은 남아 있고, ic_launcher_foreground · ic_launcher_background 모두 mipmap-{l,m,h,xh,xxh,xxxh}dpi에 PNG가 존재 → 끊어진 리소스 참조 없음.
  • 삭제된 <inset>은 API 26+에서 자기 자신으로 재귀 해석되어 런타임에 해석 자체가 실패하던 상태이므로, 없어진 16.7% 여백은 애초에 적용된 적이 없습니다. 즉 이번 삭제가 새로 만든 회귀는 아닙니다.
  • -keep class com.kakao.sdk.**.model.* { <fields>; } — ProGuard/R8에서 *는 패키지 구분자 .만 제외하고 $는 매칭하므로 OAuthToken$$serializer / Companion 같은 중첩 클래스까지 덮입니다. serializer() 멤버는 kotlinx.serialization이 아티팩트에 동봉한 -keepclassmembers 룰이 담당하므로, 클래스 생존만 보장하면 되는 이번 룰과 역할이 맞물립니다.
  • default_notification_channel_idfinders_defaultsrc/hooks/notifications/usePushNotifications.tsANDROID_CHANNEL_ID 및 테스트와 일치.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants