npm install @react-native-seoul/naver-login --save
{
"expo": {
...
"plugins": [
...,
[
"@react-native-seoul/naver-login",
{
"urlScheme": "CUSTOM URL SCHEME"
}
]
],
...
}
urlScheme은 네이버 개발자 내 애플리케이션에 등록한 ios URL Scheme

URL Scheme은 중복되지 않는 값으로 설정해야 함.
useEffect(() => {
NaverLogin.initialize({
appName: '애플리케이션 이름',
consumerKey: 'Client ID',
consumerSecret: 'Client Secret',
// naver에서 설정했던 URL Scheme
serviceUrlSchemeIOS: 'com.davidktlee.my-expo-app',
// 네이버 앱을 사용하는 인증 활성화 여부 (default: false)
disableNaverAppAuthIOS: true,
})
}, [])
consumerKey와 consumerSecret은 아래 사진에 나와있는 ID와 Secret

// index.tsx
function Home() {
useEffect(() => {
NaverLogin.initialize({
appName: '애플리케이션 이름',
consumerKey: 'Client ID',
consumerSecret: 'Client Secret',
// naver에서 설정했던 URL Scheme
serviceUrlSchemeIOS: 'com.davidktlee.my-expo-app',
// 네이버 앱을 사용하는 인증 활성화 여부 (default: false)
disableNaverAppAuthIOS: true,
})
}, [])
const onClick = async () => {
// 실패 response와 성공 response
const { failureResponse, successResponse } = await NaverLogin.login()
}
return (
<TouchableOpacity onPress={onClick}>
<Text>네이버 로그인</Text>
</TouchableOpacity>
)
}
안드로이드에서는 같은 순서로 했을 때 앱이 꺼져버리는 현상 발생
🚨 에러
JNI DETECTED ERROR IN APPLICATION:
the return type of CallVoidMethodA does not match boolean com.dooboolab.naverlogin.RNNaverLoginModule.login(com.facebook.react.bridge.Promise)📌 JS에서 void 함수로 호출했는데, Java Native 모듈은 boolean 반환형이라고 인식되어 충돌
“React Native ↔ Java/Kotlin ↔ JNI” 사이의 시그니처 불일치 문제
expo prebuild 후 expo run:androidandroid/app/src/main/java/MainApplication.kt 파일에 new RNNaverLoginPackage() 추가RNNaverLoginModule.kt 함수 선언 형식 변경 -> 성공node_modules/@react-native-seoul/naver-login/android/src/main/java/com/dooboolab/naverlogin 경로의 RNNaverLoginModule.kt 파일에서 login, logout, deleteToken 함수의 형식을 변경해 해결
1. Kotlin 표현식 함수가 자동으로 반환 타입을 추론
// Kotlin 표현식 함수
@ReactMethod
fun login(promise: Promise) =
UiThreadUtil.runOnUiThread {
...
}
이 경우 Kotlin은 내부 runOnUiThread의 반환값을 그대로 login()의 반환 타입으로 추론함.
문제는 runOnUiThread {}는 Unit(= void)를 반환하는 게 아니라, Runnable을 처리한 내부 반환값(종종 Boolean)이 될 수도 있다는 점.
특히, runOnUiThread { ... }가 내부에서 Boolean 반환하는 람다로 잘못 해석되면
JNI는 이걸 boolean login(...) 으로 잘못 인식하게 됨.
React Native 브리지 시, JNI가 이렇게 잘못 해석함
boolean login(Promise promise);
그래서 JS 쪽에서 void 메서드를 호출했는데, JNI는 boolean 리턴을 예상하고 → 충돌 발생 → 앱 강제 종료.
2. Java와 JS의 메서드 연결 구조
React Native의 브리지 구조는 아래처럼 연결
// JavaScript
await NativeModules.RNNaverLogin.login() // JS에서는 void (Promise 기반)
// Kotlin
@ReactMethod
fun login(promise: Promise) {
...
}
→ 여기서 Kotlin이 login(): Boolean 식으로 자동 추론해버리면
JNI가 CallBooleanMethod로 연결해버려서 충돌 발생.
// 표현식 대신 블록 사용 (명확하게 void/Unit 반환)
@ReactMethod
fun login(promise: Promise) {
UiThreadUtil.runOnUiThread {
...
}
}
👉 이렇게 하면 Kotlin은 명시적으로 Unit을 반환하므로,
Java Native에서도 void login(Promise)으로 정확히 매핑됨.
→ JNI도 정상 처리 → 크래시 없음
fun [func name]() = … 함수를 fun [function name]() { … } 으로 변경// 기존 코드
fun login(promise: Promise) =
UiThreadUtil.runOnUiThread {
loginPromise = promise
if (currentActivity == null) {
onLoginFailure("현재 실행중인 Activity 를 찾을 수 없습니다")
return@runOnUiThread
}
}
// ... 나머지 코드
}
// 수정 코드
fun login(promise: Promise) {
UiThreadUtil.runOnUiThread {
loginPromise = promise
if (currentActivity == null) {
class RNNaverLoginModule(reactContext: ReactApplicationContext) : ReactContextBa
onLoginFailure(je.localizedMessage)
}
}
// ... 나머지 코드
}
npm install patch-package --save-dev 명령어로 patch-package 설치package.json스크립트 추가 "scripts": {
"postinstall": "patch-package"
}
npx patch-package @react-native-seoul/naver-login 실행gitignore 추가되면 안되고 git에 커밋되어야 함.
참조
https://github.com/crossplatformkorea/react-native-naver-login
https://github.com/crossplatformkorea/react-native-naver-login/issues/207