약 4년 전에 개발된 React Native 프로젝트 리브랜딩 프로젝트 재오픈을 하면서 배포 이슈에 뒤덮였던 2025년 초..
연말 회고, 연초 다짐 이런거 할 겨를이 없었던 것 같다. 프로젝트 2개, 코테에, 버겁지만 항상 개발과 함께했던 겨울을 지나 봄이 왔다. 그저 기능을 구현했다는 걸로 절대 개발자가 될 수 없음을 계속 느끼고 있다.
험난했던 배포 과정
iOS 재오픈!
교내 커뮤니티 런칭을 앞두고 iOS 배포에서는 앱스토어 심사관과 많은 소통을 했다.
로그인 에러 나는 기기 시뮬레이터 실행해서 영상, 사진도 보내고, 정책이 담긴 파일에 정책 수정도 하고..
배포에 많은 힘을 들여 결국 오픈하게 되었다. 오픈 후 신규 유입이 몇백명 단위로 나왔는데, 안드로이드 재오픈 이후로 A/B 테스트 결과 내용도 업로드해야겠다.
안드로이드는 시간을 더 주세요..
안드로이드 배포는 우선 몇 개월 간 업데이트를 안하면 개발자 계정이 삭제된다는 정보를 알았다. 개발자 계정이 삭제되면 새로 심사를 받아야한다. 그리고 최근부터 SDK 버전이 34 이상인 앱만 등재할 수 있다고 했다. 우리 앱은 32였다.
SDK 버전을 올리면 Gradle 버전을 올려야했다. 자칫 잘못하면 RN 버전도 올려야했던 것이다. 우리 프로젝트에는 유지보수가 중단된.. 중복된.. 아주 많은 패키지가 있었기에 FE 내부 분위기는 심각했다. node_modules 파일..몇백개의 패키지들이 담겨있다..
우선 기획팀에는 1주일의 시간을 달라고 했고, 해당 기간에는 AND 정상 배포만을 목표로 하였다.
버전 업그레이드와 함께한 등장한 에러들
당장의 해결은 다른 에러를 낳는다.
우리 프로젝트는 앞서 말했듯이 패키지 정리가 안되어 있어서, index.js에서 초기화도 안되어 처음에는 패키지를 인식못하는 이슈는 수동으로 build.gradle에 패키지를 등록하여 에러를 해결하였다. SDK 버전업하고 Gradle 버전하고 나니 빌드에서부터 막혔다. 패키지 하나 버전업하면 바로 새로운 에러가 터지고.. 당시 그냥 프로젝트만 보면 머리가 아플정도로 힘들었던 것 같다.
결국엔 RN 버전 업!
하지만 이젠 패키지 내부 코드에 대해서도 에러가 나서, 결국 다른 팀원이 리액트 네이티브 버전업을 몇시간을 끌고 가서 약 3만줄이 변동되는 대공사가 이루어졌다. 우리 리액트네이티브 버전은 이제 0.65에서 0.73 업그레이드 되었고, Java도 16에서 17을 써야한다.
빌드도 되고, 실행도 된다. 이대로 약 7시간의 회의를 마치나~? 기대했는데,
애뮬레이터에서 사진을 기기에 저장하는 버튼을 누르니 해당 오류가 발생하는 것이다.
One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
Android 14(SDK 34)에서 새롭게 적용된 보안 정책 때문에 발생했다. Android 14부터는 모든 브로드캐스트 리시버가 명시적으로 exported 속성을 선언해야 한다. (broadcast reciever란, 시스템이나 다른 앱에서 발생하는 이벤트를 수신/응답하는 역할이다.)
Android 14부터 모든 동적으로 등록된 브로드캐스트 리시버(registerReceiver 호출을 통해)는 명시적으로 RECEIVER_EXPORTED 또는 RECEIVER_NOT_EXPORTED 플래그를 지정해야 합니다. 이는 앱이 의도치 않게 외부 앱으로부터 브로드캐스트를 수신하는 보안 취약점을 방지하기 위함입니다.
1. AndroidManifest.xml 에서 <receiver> 태그 수정하기 (실패)
처음에는 프로젝트의 모든 AndroidManifest.xml 파일에서 <receiver> 태그를 찾아 android:exported 속성을 추가했다.
이 방식은 정적 리시버이다. 앱이 설치될 때 시스템에 등록되어, 앱이 실행 중이지 않아도 특정 이벤트가 발생하면 앱을 활성화시킬 수 있도록 한다.
<receiver
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions"
android:exported="false" />
<receiver
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher"
android:exported="false" />
하지만 이 방법은 문제를 해결하지 못했다.
오류 메시지는 AndroidManifest에 선언된 정적 리시버가 아닌, 코드에서 registerReceiver() 메서드를 통해 동적으로 등록된 리시버를 가리키고 있었다. registerReceiverWithFeature 메서드는 동적 등록 과정에서 내부적으로 호출되는 메서드이다.
2. 라이브러리 코드에 Context.RECEIVER_NOT_EXPORTED 추가하기(성공)
문제의 핵심은 rn-fetch-blob 패키지에서 동적으로 브로드캐스트 리시버를 등록하는 방식이었다. 이 패키지를 직접 까보았고, 라이브러리 코드를 직접 수정했다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14 (SDK 34)
appCtx.registerReceiver(this, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), Context.RECEIVER_NOT_EXPORTED);
} else {
appCtx.registerReceiver(this, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
이 수정으로 Android 14에서는 RECEIVER_NOT_EXPORTED 플래그를 사용하여 브로드캐스트 리시버가 외부 앱에서 수신할 수 없도록 했고, 이전 버전의 Android에서는 기존 방식을 유지했다.
‼️patch-package 로 패키지 수정사항 유지하기‼️
이게 다가 아니다. 그냥 저장하고 커밋하면 패키지에 반영이 안된다. 패키지의 코드를 직접 수정한 후에는 해당 변경사항을 팀원들과 공유하고 npm install이 실행될 때마다 변경사항이 유지되도록 해야 했다. 이를 위해 patch-package를 사용했다.
npm install patch-package --save-dev
npx patch-package rn-fetch-blob
이렇게 하면 patches 디렉토리에 패치 파일이 생성되고, 다른 팀원들이 프로젝트를 pull 받고 npm install을 실행했을 때 동일한 수정사항이 적용된다.
이렇게 하니 배포 관련 이슈는 모두 해결할 수 있었고, 이제는 플레이스토어의 심사관에게 운명을 맡기기로 했다..
너무 많은 걸 깨달았다.
안드로이드 트러블슈팅을 하면서 정말 많은 것을 깨달았다.
프로젝트 초기 설계가 정말 중요하구나..!
인프라가 정말 중요하고 이런 지식이 있으면 패키지 하나 다운 받을 때 1) 공식 문서를 보게 되고, 2) 호환되는 버전을 보게 되고, 시야가 넓어진다.인턴 때도 moment.js 유지보수 중단으로 day.js로 마이그레이션하는 작업을 할 때도 느꼈지만 보안 정책 정말정말 중요한 듯하다. 이런 걸 알아야 기능 구현할 때도 수월하고 이슈가 줄어들고 말이다..
이래서 프로젝트 초기에 폴더 구조 설계와 기획안을 보면서 어떤 패키지가 필요할지 미리 사전 조사를 하고 세팅을 하는게 맞는 것 같다. 해외 빅테크에서는 프로젝트 기간의 절반 이상을 설계에 투자하고, 단순 코딩은 AI에게 맡긴다고 아티클을 보았던 것 같다.
나갈거 아니면 버전 관리는 필수..
유지보수 해야하면 주기적으로 빌드하고, 주기적으로 업데이트해서 배포 에러 나지 않게 관리하자.. 4년만에 모든 패키지를 업데이트한 프로젝트 파일도 놀랬을 것이다. 후..
⭐️⭐️⭐️팀워크의 힘을 믿는다⭐️⭐️⭐️
진전이 가장 많았던 배포 담당자가 해결하겠다고 했지만, 시간이 흘러도 큰 진전이 없었다.
배포 일정 지연으로 계속 다른 팀에 피해를 주는 느낌이 싫어서 팀 내,
"같이 화면 공유하며 실시간으로 해결하는거 어떤가요?" 제안했다.
우리 팀은 각자 개인 개발을 하는 분위기라 이슈 외로는 많은 소통이 없었다. 이런 제안이 괜찮을지 고민했지만, 결국 궁지에 몰리면 누구든 주도적으로 행동해야 했다.
이번 주에 2번에 걸쳐 디스코드로 실시간 이슈 공유하며 작업했다.
온라인이지만 디스코드에서 대화하니 속도가 빨랐고, 각자 알고 있는 지식이 합쳐져 시너지 효과가 났다.
당장 할 일이 없더라도 함께 그 자리에 있어주고, 논의하고, 이슈를 확인하고 시도하는 자세가 정말 중요했다.그래야 혼자 해결하는 느낌이 들지 않고 지치지 않는다.
만약 머뭇거리다가 같이 해결하자고 제안하지 않았다면 안드로이드 오픈 일정은 2-3주 늦어지지 않았을까..?
팀원을 믿고 함께하는 것의 중요성을 다시 한번 느꼈다. 혼자서는 불가능했을 문제도 함께하면 해결할 수 있다는 것을 경험했다.
우리팀 너무 너무 고생 많았다..🥹
'Programming > React-Native' 카테고리의 다른 글
기존 프로젝트에서 React-Native-CLI 실행하기 (+Window, Android Studio, VScode) (1) | 2024.07.01 |
---|