react-native expo 네이버 로그인 (with.android 에러)

이경택·2025년 4월 8일
1

환경

에러 상황

네이버 로그인

  1. 설치

npm install @react-native-seoul/naver-login --save

  1. app.json plugins 설정
{
  "expo": {
    ...
    "plugins": [
      ...,
      [
        "@react-native-seoul/naver-login",
        {
          "urlScheme": "CUSTOM URL SCHEME"
        }
      ]
    ],
    ...
  }

urlScheme은 네이버 개발자 내 애플리케이션에 등록한 ios URL Scheme

URL Scheme은 중복되지 않는 값으로 설정해야 함.

  1. 사용하는 곳에서 useEffect 내에서 초기화
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 prebuildexpo run:android → 실패
  • android/app/src/main/java/MainApplication.kt 파일에 new RNNaverLoginPackage() 추가 → 실패
  • RNNaverLoginModule.kt 함수 선언 형식 변경 -> 성공
    깃헙 이슈를 보다가 rn 0.76 버전에서 안드로이드 앱 크래시가 난다는 이슈를 보았고 node_modules에 접근해서 빌드 파일을 변경하는 과정을 실행해 수정, 로그인 성공.

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도 정상 처리 → 크래시 없음

결론

  1. 표현식 함수 사용 시 반환 타입을 잘못 추론할 수 있음 (특히 runOnUiThread 안에서)
  2. JNI 충돌 이유는 Kotlin이 추론한 리턴값이 boolean으로 해석돼, JS에서는 void로 호출 → 타입 mismatch
  3. 함수 본문 { ... } 사용하여 반환 타입을 Unit으로 명확히 해야 해결됨

과정

  1. 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)
             }
         }
  	// ... 나머지 코드
}
  1. npm install patch-package --save-dev 명령어로 patch-package 설치
  2. package.json스크립트 추가
    (이렇게 해야 npm i 했을 때 자동으로 수정사항 반영)
    "scripts": {
      "postinstall": "patch-package"
    }
  1. 수정 한 후 npx patch-package @react-native-seoul/naver-login 실행
    → 루트에 patches 폴더에 .patch 파일이 생기면 node_modules 삭제했다가 npm i 해도 잘 반영되는 것 확인.

gitignore 추가되면 안되고 git에 커밋되어야 함.

참조
https://github.com/crossplatformkorea/react-native-naver-login
https://github.com/crossplatformkorea/react-native-naver-login/issues/207

profile
한 줄로 소개 할 수 없는 개발자

0개의 댓글