react native 프로젝트 내부 App.tsx에 WebView로 배포되어있는 웹 사이트를 띄운 즉 패키징 프로젝트 입니다.
다름이 아니라, 제가 카카오톡 로그인 기능을 구현하려는 와중, IOS에서는
// if (!window.Kakao) {
// console.error(‘Kakao SDK not found’);
// return;
// }
// if (!window.Kakao.isInitialized()) {
// window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_CLIENT_ID);
// }
// window.Kakao.Auth.authorize({
// redirectUri: process.env.NEXT_PUBLIC_KAKAO_REDIRECT_URI!,
// throughTalk: true,
// });
이렇게 로그인을 구현했을 때 정상적으로 동작을 하는데,
ANDROID 에서는, ERR_UNKNOWN_URL_SCHEME 라는 에러가 발생을 합니다.
혹시 도움을 좀 받을 수 있을까요?
안드로이드에서 ERR_UNKNOWN_URL_SCHEME 에러가 발생하는 것은 인텐트 스킴을 오픈하지 못하는 문제로 보입니다. 이는 웹뷰에서 카카오톡 앱을 실행하려고 할 때 발생하는 일반적인 이슈입니다.
해결 방법은 다음과 같습니다:
AndroidManifest에 카카오톡 패키지명 선언 : 안드로이드 앱의 AndroidManifest.xml 파일에 카카오톡 패키지명을 선언해야 합니다.
<manifest package="com.example.sample">
<queries>
<package android:name="com.kakao.talk" />
</queries>
...
</manifest>
웹뷰의 shouldOverrideUrlLoading 메소드 구현 : 웹뷰에서 인텐트 스킴 URL을 처리할 수 있도록 shouldOverrideUrlLoading 메소드를 구현해야 합니다.
리액트 네이티브 프로젝트에서는 직접 네이티브 코드를 수정할 수 없으므로, react-native-webview 라이브러리의 커스텀 안드로이드 구현을 참고하여 조치해야 합니다.
이 두 가지 방법을 통해 안드로이드에서 카카오톡 로그인 기능을 정상적으로 동작시킬 수 있을 것입니다.
추가적인 도움이 필요하시면 언제든지 문의해주세요.
[ @tim.l @woody.ho ]
답변 감사드립니다.
혹시 한 가지 궁금한 점이, 맨 처음 로그인 시에는 아이디와 비밀번호를 요구하고 그 이후에는 요구를 안하는 것이 맞나요?
tim.l
7월 11, 2025, 4:36오전
4
네, 브라우저에 카카오계정 로그인 세션이 유지지되는 동안은 요구하지 않습니다.
카카오계정과 함께 로그아웃 또는 항상 ID/PW 입력받기 옵션 도 있습니다.
export const kakaoLogin = () => {
// console.log(‘카카오 로그인 실행됨’);
if (typeof window === ‘undefined’) return;
if (!window.Kakao) {
console.error(‘Kakao SDK not found’);
return;
}
if (!window.Kakao.isInitialized()) {
window.Kakao.init(process.env.NEXT_PUBLIC_KAKAO_CLIENT_ID);
}
window.Kakao.Auth.authorize({
redirectUri: process.env.NEXT_PUBLIC_KAKAO_REDIRECT_URI!,
throughTalk: true,
});
};
제가 웹단에서 이렇게 사용 중에 있는데요,
react native
android 하위에 src > main > …
MainApplication.java 파일들과 같은 선상에 CustomWebViewClient, Manager, Package.java 파일들을 생성하여 사용중에 있는데,
카카오톡이 열리지 않네요…
tim.l
7월 11, 2025, 4:46오전
6
인텐트 스킴 호출 할 수 있도록 하이브리드앱 처리 하셨을까요?
tim.l:
하이브리드앱
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
Log.d(TAG, "URL intercepted: " + url);
return handleCustomScheme(view, url);
}
이런식으로 사용했습니다
AndroidManifest.xml에도 queries 에 package 추가헀구요…
tim.l
7월 11, 2025, 4:53오전
8
react native 프로젝트 라고 하셨는데 해당 로직이 실행되나요?
제가 구현한 방식은 CustomWebView를 생성한 것인데,
Android에서만 react-native-webview 대신 CustomWebView를 감싼 형식으로 진행을 했습니다
tim.l
7월 11, 2025, 5:28오전
10
Log.d(TAG, "URL intercepted: " + url); 로그가 찍히던가요?
tim.l
7월 11, 2025, 5:46오전
13
react-native-webview 대신 CustomWebView를 감싼 형식으로 진행
위내용에 대해 어떤 방식인지 잘 이해하지 못했는데요.
로그가 찍힌다고 하셨으니 후킹은 되는 상황으로 이해 했습니다.
앱 호출이 실패하면 S.browser_fallback_url로 이동하도록 구현 하는데요.
https://developer.chrome.com/docs/multidevice/android/intents/
intent의 S.browser_fallback_url에 대한 파싱을 구현하셨을까요?
https://developers.kakao.com/docs/latest/ko/javascript/hybrid#android-execute-kakaotalk
테스트한 기기에 카카오톡은 설치 및 로그인되어 있는 상태인가요?
넵! 카카오톡 앱은 설치되어있습니다!
import React, {forwardRef} from ‘react’;
import {Platform, requireNativeComponent, ViewStyle} from ‘react-native’;
import {WebView, WebViewProps} from ‘react-native-webview’;
interface CustomWebViewProps {
ref?: any;
source?: {
uri?: string;
html?: string;
};
style?: ViewStyle | ViewStyle ;
onLoad?: () => void;
bounces?: boolean;
onMessage?: (event: {nativeEvent: {data: string}}) => void;
javaScriptEnabled?: boolean;
domStorageEnabled?: boolean;
sharedCookiesEnabled?: boolean;
allowsInlineMediaPlayback?: boolean;
mediaPlaybackRequiresUserAction?: boolean;
onNavigationStateChange?: (navState: any) => void;
allowFileAccess?: boolean;
allowUniversalAccessFromFileURLs?: boolean;
mixedContentMode?: ‘never’ | ‘always’ | ‘compatibility’;
originWhitelist?: string ;
onShouldStartLoadWithRequest?: (event: {url: string}) => boolean;
injectedJavaScript?: string;
}
const CustomWebViewNative =
requireNativeComponent(‘MyCustomWebView’);
export const CustomWebView = forwardRef<any, CustomWebViewProps>(
(props, ref) => {
if (Platform.OS === ‘android’) {
const androidProps = {
ref,
source: props.source,
style: props.style,
javaScriptEnabled: props.javaScriptEnabled,
domStorageEnabled: props.domStorageEnabled,
allowFileAccess: props.allowFileAccess,
allowUniversalAccessFromFileURLs:
props.allowUniversalAccessFromFileURLs,
mixedContentMode: props.mixedContentMode,
mediaPlaybackRequiresUserAction: props.mediaPlaybackRequiresUserAction,
injectedJavaScript: props.injectedJavaScript,
};
return <CustomWebViewNative {...androidProps} />;
}
return <WebView ref={ref} {...(props as WebViewProps)} />;
},
);
CustomWebView.displayName = ‘CustomWebView’;
export default CustomWebView;
이렇게 구현해두고,
로 사용중이였습니다
tim.l
7월 11, 2025, 5:55오전
15
handleCustomScheme 구현부와 로그 공유해주시겠어요?
tim.l:
handleCustomScheme
private boolean handleCustomScheme(WebView view, String url) {
Log.d(TAG, "🔍 Handling URL: " + url);
// Intent 스킴 처리 (가장 먼저 확인)
if (url.startsWith("intent:")) {
Log.d(TAG, "🟡 Intent scheme detected: " + url);
return handleIntentScheme(view, url);
}
// 카카오톡 관련 URL 처리
if (url.startsWith("kakaotalk://") || url.startsWith("kakaokompass://")) {
Log.d(TAG, "🟢 Kakao app scheme detected: " + url);
return launchExternalApp(view, url);
}
// 기타 커스텀 스킴 처리
if (url.startsWith("kakao:") || url.startsWith("talk:")) {
Log.d(TAG, "🟠 Custom kakao scheme detected: " + url);
return launchExternalApp(view, url);
}
// 카카오 OAuth URL 처리
if (url.contains("kauth.kakao.com")) {
Log.d(TAG, "🔵 Kakao OAuth URL detected: " + url);
return false; // WebView에서 처리하여 OAuth 진행
}
// HTTP/HTTPS는 WebView에서 처리
if (url.startsWith("http://") || url.startsWith("https://")) {
Log.d(TAG, "🌐 HTTP/HTTPS URL - loading in WebView: " + url);
return false; // WebView에서 처리
}
Log.d(TAG, "❓ Unknown scheme, attempting external launch: " + url);
return launchExternalApp(view, url);
}
tim.l
7월 11, 2025, 6:03오전
18
엇
handleCustomScheme 여기서 문제 있을거라 생각했는데…
Log.d(TAG, " Handling URL: " + url); 여기 수행 안되었나요?
tim.l
7월 11, 2025, 6:04오전
20
그다음 아래 로직 수행 안되었나요?
// Intent 스킴 처리 (가장 먼저 확인)
if (url.startsWith(“intent:”)) {
Log.d(TAG, " Intent scheme detected: " + url);
return handleIntentScheme(view, url);
}