
스타트업, 제발 React Native 쓰세요 (솔직한 2년 사용기)
iOS와 Android 개발자를 따로 채용할 돈이 없어서 선택한 React Native. 생산성은 2배였지만, 네이티브 모듈과 버전 업그레이드 지옥에서 겪은 생생한 경험담을 공유합니다. 그리고 왜 Expo가 게임체인저인지 설명합니다.

iOS와 Android 개발자를 따로 채용할 돈이 없어서 선택한 React Native. 생산성은 2배였지만, 네이티브 모듈과 버전 업그레이드 지옥에서 겪은 생생한 경험담을 공유합니다. 그리고 왜 Expo가 게임체인저인지 설명합니다.
로그인 화면을 만들었는데 키보드가 올라오니 노란 줄무늬 에러가 뜹니다. resizeToAvoidBottomInset부터 스크롤 뷰, 그리고 채팅 앱을 위한 reverse 팁까지, 키보드 대응의 모든 것을 정리해봤습니다.

안드로이드는 오는데 iOS는 조용합니다. 혹은 앱이 켜져 있을 때만 옵니다. Background/Terminated 상태 처리, APNs 인증서, 그리고 Notification Channel 설정까지 완벽하게 해결합니다.

안드로이드는 Xcode보다 낫다고요? Gradle 지옥에 빠져보면 그 말이 쏙 들어갈 겁니다. minSdkVersion 충돌, Multidex 에러, Namespace 변경(Gradle 8.0), JDK 버전 문제, 그리고 의존성 트리 분석까지 완벽하게 해결해 봅니다.

Debug에선 잘 되는데 Release에서만 죽나요? 범인은 '난독화'입니다. R8의 원리, Mapping 파일 분석, 그리고 Reflection을 사용하는 라이브러리를 지켜내는 방법(@Keep)을 정리해봤습니다.

창업 초기, 통장 잔고는 바닥이었고 앱은 만들어야 했습니다. iOS 개발자(Swift) 한 명, Android 개발자(Kotlin) 한 명을 채용할 여력 따위는 없었죠. 평균 연봉만 따져도 1년에 1억 이상이 깨지는 일이니까요.
선택지는 하나였습니다. 크로스 플랫폼(Cross Platform). Flutter와 React Native 중 고민하다가, 제가 웹(React) 개발자 출신이라 React Native(RN)를 골랐습니다.
"JavaScript로 앱을 만든다고? 느리지 않을까? 페이스북(Meta)이 만들었다지만 믿어도 될까?" 걱정 반, 기대 반으로 시작했습니다. 그리고 2년이 지났습니다.
처음엔 천국이었습니다. "이게 된다고?" 소리가 절로 나왔으니까요.
iOS 네이티브 개발을 해보신 분은 압니다. 버튼 색 하나 바꾸고 확인하려면 '빌드' 버튼 누르고 1분 동안 멍때려야 합니다.
React Native는 Cmd + S를 누르자마자 0.5초 만에 시뮬레이터 화면이 바뀝니다.
이 피드백 루프의 속도가 개발자의 생산성을 10배로 만듭니다.
"안드로이드는 뒤로가기 버튼 처리를 따로 해야겠지?" 아뇨, 거의 안 합니다. 비즈니스 로직, API 호출, 상태 관리(Zustand), 유틸리티 함수 등 95% 이상의 코드를 iOS와 Android가 완벽하게 공유합니다. UI도 Flexbox로 통일되어 있어서, 스타일 조금만 손보면(Safe Area 정도) 양쪽 다 예쁘게 나옵니다. 하나를 만들면 둘이 생기는 1+1 행사 같습니다.
새로운 모바일 개발자를 뽑을 필요가 없습니다.
기존 웹 프론트엔드 개발자에게 "자, 이게 <div> 대신 <View>를 쓰는 거야"라고 일주일만 가르치면 바로 실제 투입이 가능합니다.
인력 구하기 힘든 스타트업에겐 이게 킬러 기능(Killer Feature)입니다.
하지만 앱이 복잡해지면서, 저는 RN을 저주하기 시작했습니다.
어느 날 React Native 버전을 올리려고 패기롭게 npm update를 쳤습니다.
그리고 프로젝트가 일주일 동안 켜지지 않았습니다.
RN은 자바스크립트 코드와 네이티브 코드(Objective-C, Java)를 본드칠로 붙여놓은 형태입니다. 버전이 안 맞으면 이 본드가 떨어져 나갑니다. 빨간 에러 메시지를 복사해서 구글링하면 2019년 스택오버플로우 답변만 나오고... 새벽 4시에 사무실에서 울 뻔했습니다.
안드로이드 기기의 파편화(Fragmentation)는 상상을 초월합니다. 제 갤럭시 S24에선 잘 되는데, 고객의 3년 된 샤오미 폰에서는 버튼이 눌리지 않고, 화웨이 폰에서는 앱이 켜지자마자 꺼집니다. 결국 자바스크립트만 하려던 저는 Android Studio를 켜고, 알지도 못하는 Gradle 설정과 Java 코드를 디버깅하고 있었습니다. "이럴 거면 그냥 네이티브 배울 걸..." 하는 현타가 옵니다.
RN은 자바스크립트 스레드와 네이티브 스레드가 브릿지(Bridge)를 통해 JSON 메시지를 주고받으며 통신합니다. 리스트를 빠르게 스크롤하거나, 복잡한 애니메이션을 돌리면 이 브릿지가 막혀서 프레임 드랍(버벅임)이 생깁니다. 물론 지금은 New Architecture (Fabric/TurboModules)가 나와서 C++로 직접 통신하므로 많이 좋아졌지만, 여전히 순정 네이티브의 그 '쫀득한' 맛을 내려면 최적화 노력이 필요합니다.
이런 단점들에도 불구하고, 타임머신을 타고 돌아가도 저는 React Native를 선택할 겁니다. 대신 이번엔 순정 RN이 아니라 Expo를 쓸 겁니다.
예전의 Expo는 "장난감" 취급을 받았습니다. 네이티브 모듈을 못 썼으니까요. 하지만 지금의 Expo(EAS)는 괴물입니다.
이제 개발자는 ios/ 폴더와 android/ 폴더를 아예 안 만듭니다.
npx expo prebuild 명령어 한 방이면, 설정 파일(app.json)을 읽어서 네이티브 폴더를 그때그때 생성해 줍니다.
이게 무슨 뜻이냐? 버전 업그레이드 지옥에서 해방된다는 뜻입니다.
앱스토어 심사는 까다롭고 오래 걸립니다. (최소 1~2일) 치명적인 버그가 생겼을 때, Expo Updates를 쓰면 심사 없이 자바스크립트 코드를 사용자 폰으로 몰래 쏘아서 고칠 수 있습니다. 이 기능 하나만으로도 Expo를 쓸 이유는 충분합니다.
많은 분들이 "RN은 느리다"고 알고 계십니다. 과거에는 Bridge라는 통로를 통해 JS와 Native가 JSON 문자열을 주고받았기 때문입니다. 초당 60프레임으로 스크롤할 때, 수많은 JSON 메시지가 브릿지를 꽉 막아서 버벅거렸죠.
하지만 React Native 0.68+부터 도입된 New Architecture는 완전히 다릅니다.
이제 RN의 성능은 네이티브와 거의 구별할 수 없는 수준에 도달했습니다.
저는 두 프레임워크를 모두 실제로 검토했었습니다.
Flutter의 장점:결국 "비즈니스 생존" 관점에서는 React Native가 더 유리한 선택이라 판단했습니다.
기술 스택은 종교가 아닙니다. 비즈니스 도구입니다.
React Native는 완벽하지 않습니다. 하지만 "가장 적은 리소스(돈/시간)로 가장 빠르게 시장에 진입하는" 최고의 무기임은 확실합니다. Flutter도 좋지만, 이미 React를 아는 웹 개발자가 세상에 넘쳐나는데 굳이 Dart를 새로 배울 이유가 있을까요?
Early-stage startup. Zero cash. Need an app. I couldn't afford hiring one iOS dev (Swift) AND one Android dev (Kotlin). Their combined salaries would burn half our runway.
The only option: Cross Platform. Between Flutter and React Native, I chose React Native because I was a web (React) dev.
"Apps with JavaScript? Won't it be slow? Can we trust Meta?" I started with half worry, half hope. And now, 2 years later.
At first, it was bliss. I found myself saying, "Wait, this actually works?"
If you've done iOS native dev, you know the pain. Change a button color, press Build, wait 1 minute.
In React Native, Cmd + S updates the screen in 0.5s.
This speed of the Feedback Loop boosts developer productivity by 10x.
"Do I need to handle the Android Back Button separately?" Rarely. Business logic, API calls, state management (Zustand), and utilities are shared 100% between iOS and Android. The UI is unified with Flexbox, so with minor tweaks (like Safe Area), it looks great on both. It feels like a "Buy 1 Get 1 Free" deal.
You don't need to hunt for expensive mobile specialists.
Grab a web frontend dev, tell them "Use <View> instead of <div>," and they are ready for production in a week.
For startups struggling to hire, this is a Killer Feature.
But as the app grew complex, I started cursing RN.
One day, I bravely ran npm update to upgrade RN.
The project didn't open for a week.
RN is like gluing JavaScript code and Native code (Obj-C, Java) together. If versions mismatch, the glue fails. Googling red errors only gives StackOverflow answers from 2019... I almost cried in the office at 4 AM.
Android fragmentation is nightmare fuel. It works perfectly on my Galaxy S24, but on a customer's 3-year-old Xiaomi, buttons don't click, and on a Huawei, it crashes on launch. Eventually, I found myself opening Android Studio, debugging Gradle configs and Java code I didn't understand. "I should've just learned Native..." I thought.
RN communicates between the JS Thread and Native Thread via a Bridge, passing JSON messages. If you scroll a list too fast or run complex animations, this bridge gets clogged, causing frame drops (jank). Although the New Architecture (Fabric/TurboModules) now uses C++ for direct communication, achieving that "buttery smooth" native feel still requires optimization effort.
Despite the pain, if I could go back in time, I'd choose React Native again. But this time, I would use Expo.
Old Expo was considered a "toy" because it blocked Native Modules. But modern Expo (EAS) is a beast.
Now, you never touch ios/ or android/ folders.
npx expo prebuild generates these folders on demand from your config (app.json).
This means Freedom from Version Upgrade Hell.
Why is EAS (Expo Application Services) such a big deal?
Before EAS, if you needed a native library (like a specific KakaoTalk Login SDK), you had to "eject" from Expo.
Running npm run eject was a one-way ticket to hell. It exposed all the native folders, and you lost the convenience of Expo.
But with CNG (Continuous Native Generation) and Config Plugins, you never eject.
You write a small plugin code in JS that tells EAS:
"Hey, when you build this app on the cloud, please inject this line into AndroidManifest.xml and add this pod to Podfile."
This means your project stays pure JavaScript. The native complexity is offloaded to the build server. This is the equivalent of "Serverless" for mobile development.
React Native had a bottleneck: the Bridge. Every scroll event, every touch had to be serialized to JSON, sent across the bridge, and deserialized. This is why animations could stutter.
But the New Architecture (enabled by default in new versions) fixes this.
With these updates, RN performance is practically indistinguishable from Native for 99% of apps.
I've tried both. Here is the realistic breakdown.
My Take: If your team knows JS, stick to React Native (Expo). The cost of switching context to Dart is higher than the performance gain.
If you start a RN project today, ignore the old tutorials. Use this modern stack:
The ecosystem has converged. If you know the modern React Web stack, you already know 80% of the React Native stack.