Expo

Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리

2026.04.21·수정 2026.05.11·약 14분

이 글에서 정리하는 내용

이 글에서는 expo-web-browser를 사용할 때 무엇을 위해 쓰는지부터 openBrowserAsync와 openAuthSessionAsync의 차이로그인 후 앱으로 돌아오는 딥링크 흐름, Expo Router와 함께 쓸 때의 포인트, Android 최적화 함수까지 한 번에 정리합니다. 끝까지 읽으면 외부 링크 열기와 인증 흐름을 같은 브라우저 기능으로 보지 않고 상황에 따라 정확히 나눠서 적용할 수 있게 됩니다.

expo-web-browser는 무엇이고 왜 쓰는가

Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리 핵심 개념을 설명하는 첫 번째 본문 이미지

expo-web-browser는 앱 안에서 웹 콘텐츠를 보여주되, 일반적인 WebView처럼 앱 내부에 웹 페이지를 직접 렌더링하는 방식이 아니라 운영체제가 제공하는 시스템 브라우저 경험을 활용하는 도구로 이해하면 훨씬 정리가 쉽습니다. 실무에서는 보통 개인정보처리방침이용약관, 고객센터, 외부 결제 안내로그인 페이지처럼 앱 바깥 웹 문서를 잠깐 열어야 할 때 먼저 떠올리게 됩니다.

핵심은 이 패키지가 단순히 URL을 여는 함수 모음이 아니라는 점입니다. 어떤 메서드를 고르느냐에 따라 일반 웹페이지 열기인지, 인증 후 앱으로 다시 돌아와야 하는 흐름인지가 갈립니다. 그래서 처음부터 expo-web-browser를 WebView 대체재로만 보면 실무에서 가장 많이 막히는 인증 복귀 구조를 놓치기 쉽습니다.

WebView와 구분해서 보는 기준

// 일반 링크 열기와 인앱 렌더링은 목적이 다릅니다.
const useCases = { privacyPolicy: 'expo-web-browser', termsOfService: 'expo-web-browser', oauthLogin: 'expo-web-browser 또는 expo-auth-session', internalCustomPage: 'react-native-webview'
};

기준은 단순합니다. 외부 웹페이지를 시스템 브라우저 경험으로 안전하게 열고 닫는 것이 목적이면 expo-web-browser가 먼저입니다. 반대로 앱 내부 화면처럼 웹 콘텐츠를 깊게 제어해야 한다면 WebView가 더 맞습니다. 즉, 화면을 임베드할 것인지, 브라우저를 잠깐 호출할 것인지부터 나눠서 생각하면 선택이 쉬워집니다.

플랫폼 관점에서도 차이가 있습니다. Android에서는 Custom Tabs를 사용하고, iOS에서는 호출 방식에 따라 SFSafariViewController 또는 ASWebAuthenticationSession이 사용됩니다. 이 차이 때문에 같은 브라우저 호출처럼 보여도 실제 동작과 인증 적합성이 달라집니다.

openBrowserAsync와 일반 링크 열기

가장 먼저 익혀야 하는 메서드는 openBrowserAsync입니다. 이 메서드는 로그인 인증용이라기보다 일반적인 외부 링크 열기에 가깝습니다. 예를 들어 개인정보처리방침이벤트 안내, 공지사항, 고객센터처럼 사용자가 내용을 보고 돌아오면 되는 경우라면 이쪽이 더 자연스럽습니다.

특히 iOS에서는 openBrowserAsync가 SFSafariViewController를 사용하므로 시스템 Safari와 쿠키를 공유하는 인증 세션을 기대하면 안 됩니다. 그래서 로그인 화면도 브라우저니까 같은 함수로 열면 되겠지라고 접근하면, 나중에 인증 복귀나 세션 유지에서 어긋나는 경우가 생깁니다.

기본 사용 예시

import * as WebBrowser from 'expo-web-browser'; // 일반 웹페이지를 여는 가장 기본적인 예시입니다.
export async function openPrivacyPolicy() { const result = await WebBrowser.openBrowserAsync( 'https://example.com/privacy' ); console.log(result);
}

이 코드는 가장 단순하지만 실무에서 자주 쓰는 형태입니다. 버튼 클릭 시 외부 페이지를 열고, 사용자가 닫거나 흐름이 끝나면 결과를 받을 수 있습니다. 여기서 중요한 점은 이 방식이 로그인 성공 후 토큰을 앱으로 다시 받아오는 인증 세션용 기본값은 아니라는 점입니다. 단순 열람 목적이라면 충분하지만, 인증 결과를 안전하게 복귀시켜야 하는 시나리오라면 다음 섹션의 메서드로 넘어가야 합니다.

상황 우선 선택
약관, 공지, 정책 페이지 openBrowserAsync
OAuth 로그인, 인증 후 앱 복귀 openAuthSessionAsync

openAuthSessionAsync와 로그인 인증 흐름

인증은 일반 링크 열기와 완전히 같은 문제로 보면 안 됩니다. 로그인 페이지를 연 뒤 인증이 끝나면 앱으로 다시 돌아와야 하고, 그 복귀 주소가 프로젝트에 등록되어 있어야 합니다. 이 흐름 때문에 expo-web-browser를 배울 때 가장 중요한 분기점이 openBrowserAsync와 openAuthSessionAsync의 차이입니다.

실무에서는 소셜 로그인이나 외부 인증 제공자를 붙일 때 openAuthSessionAsync를 먼저 검토합니다. 특히 iOS에서는 일반 브라우저 방식과 인증 세션 방식의 차이를 모르면 로그인은 됐는데 앱으로 결과를 못 넘겨받는 상황을 만나기 쉽습니다. 인증 제공자 쪽에서도 URI 허용 목록을 관리하는 경우가 많아서, 앱이 보내는 주소와 서버에 등록된 주소가 정확히 일치해야 합니다.

인증 세션 기본 흐름

import * as WebBrowser from 'expo-web-browser';
import * as Linking from 'expo-linking'; // 인증이 끝나면 앱으로 다시 돌아올 주소를 먼저 만듭니다.
export async function openLoginSession() { const redirectUrl = Linking.createURL('auth/callback'); const loginUrl = `https://example.com/login?redirect_uri=${encodeURIComponent(redirectUrl)}`; const result = await WebBrowser.openAuthSessionAsync(loginUrl, redirectUrl); console.log(result);
}

여기서는 redirectUrl이 핵심입니다. 인증 제공자는 로그인 성공 후 이 주소로 다시 보내주고, 앱은 그 주소를 받아 결과를 이어서 처리합니다. 그래서 이 코드는 단순히 브라우저를 연다기보다 브라우저 기반 인증을 앱 흐름으로 되돌리는 출발점에 가깝습니다. 또한 URI는 인증 서버의 허용 목록에도 등록되어 있어야 하므로, 앱 코드와 인증 콘솔 설정을 따로따로 보면 안 됩니다.

scheme 설정과 테스트 방법

// app.json 또는 app.config.ts에서 앱 고유 스킴을 설정합니다.
{ "expo": { "scheme": "myapp" }
} // 스킴 연결 테스트 예시입니다.
// npx uri-scheme open myapp://auth/callback --ios

scheme는 내 앱을 여는 고유 주소의 앞부분입니다. 이 값이 없으면 인증 흐름은 끝나더라도 앱이 결과를 돌려받지 못할 수 있습니다. 예를 들어 myapp://auth/callback 같은 주소가 앱으로 연결되어야 로그인 완료 후 자연스럽게 돌아올 수 있습니다. 따라서 인증 기능을 붙일 때는 브라우저 호출 코드보다 scheme 설정이 먼저 맞는지부터 확인하는 편이 안전합니다.

추가로 iOS에서는 preferEphemeralSession 옵션으로 사적인 인증 세션을 요청할 수 있습니다. 이 옵션은 브라우저의 일반 쿠키를 공유하지 않도록 요청하는 성격이므로, 기존 로그인 상태를 재사용하는 흐름보다 매번 분리된 인증 경험이 필요할 때 검토하면 됩니다.

딥링크, Expo Router, 실무 연결 포인트

Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리 적용 흐름을 설명하는 두 번째 본문 이미지

expo-web-browser를 실무에서 어렵게 만드는 이유는 브라우저를 여는 코드보다 브라우저를 닫고 다음 화면으로 이어지는 처리에 있습니다. 인증 완료 후 콜백 URL이 들어오면 그 주소를 해석해서 필요한 화면으로 보내야 하고, 경우에 따라 브라우저를 직접 닫아주는 흐름도 함께 생각해야 합니다.

Expo Router를 쓰는 프로젝트라면 딥링크 자체는 자동으로 처리됩니다. 다만 자동 처리와 인증 설계는 같은 말이 아닙니다. URL 경로를 어떤 화면에 연결할지, 성공 후 어디로 이동할지, 실패 시 어떤 화면을 보여줄지는 여전히 직접 정리해야 합니다.

Linking 이벤트로 직접 처리하는 예시

import { useEffect } from 'react';
import * as Linking from 'expo-linking';
import * as WebBrowser from 'expo-web-browser'; // Router를 직접 쓰지 않거나 수동 제어가 필요할 때의 예시입니다.
export function useAuthRedirect() { useEffect(() => { const subscription = Linking.addEventListener('url', () => { WebBrowser.dismissBrowser(); }); return () => { subscription.remove(); }; }, []);
}

직접 Linking 이벤트를 다룰 때는 브라우저가 자동으로 닫히지 않는 상황까지 같이 고려하는 편이 좋습니다. 그래서 콜백 URL을 받았을 때 dismissBrowser를 호출해 흐름을 마무리하는 패턴이 자주 나옵니다. 반대로 Expo Router를 쓰고 있다면 라우트가 URL과 자연스럽게 연결되기 때문에 딥링크 구조를 이해하기가 한결 편해집니다. 파일 기반 라우팅을 쓰는 프로젝트라면 auth/callback 같은 경로를 앱 라우트 구조 안에서 함께 설계해두면 읽는 사람도 흐름을 따라가기 쉽습니다.

다만 이 부분에서 한 가지를 더 구분해야 합니다. openBrowserAsync나 일반 창으로 딥링크를 되돌리는 패턴에서는 Linking 이벤트와 dismissBrowser가 유효하지만, openAuthSessionAsync를 iOS 인증 세션으로 사용할 때는 수동 Linking 이벤트를 같이 붙이지 않는 편이 안전합니다. 인증 세션은 자체적인 복귀 처리 방식이 있고, 여기에 별도 이벤트를 겹치면 오히려 흐름이 꼬일 수 있습니다.

Android에서 알아두면 좋은 준비 함수

import { useEffect } from 'react';
import * as WebBrowser from 'expo-web-browser'; // Android에서는 브라우저 준비와 정리 함수를 함께 둘 수 있습니다.
export function useWarmUpBrowser() { useEffect(() => { WebBrowser.warmUpAsync(); WebBrowser.mayInitWithUrlAsync('https://example.com/login'); return () => { WebBrowser.coolDownAsync(); }; }, []);
}

이 부분은 모든 화면에 무조건 넣는 기능은 아니지만, 자주 브라우저를 호출하는 인증 화면이나 외부 링크 중심 화면이라면 열리는 체감 속도를 다듬는 데 도움이 됩니다. mayInitWithUrlAsync는 첫 로딩 가능성이 높은 URL을 미리 알려주는 용도에 가깝고, coolDownAsync는 warmUpAsync나 mayInitWithUrlAsync로 만든 서비스 바인딩을 정리하는 역할을 합니다. 즉, 성능 최적화와 정리 코드를 한 세트로 보는 편이 맞습니다.

정리

expo-web-browser는 외부 웹페이지를 여는 도구처럼 보이지만, 실무에서는 일반 링크 열기와 인증 세션 열기를 구분해서 쓰는 것이 핵심입니다. 정책 페이지처럼 보고 돌아오면 되는 문서는 openBrowserAsync가 잘 맞고로그인처럼 인증 후 앱으로 다시 돌아와야 하는 흐름은 openAuthSessionAsync와 딥링크 설정을 함께 봐야 합니다. 여기에 Expo Router를 사용 중이라면 URL 기반 화면 연결을 더 자연스럽게 정리할 수 있고, Android에서는 warmUpAsync와 coolDownAsync로 호출 경험까지 다듬을 수 있습니다.

로그인 인증 흐름을 구성할 때 토큰 저장은 Expo SecureStore 토큰 저장, 인증 후 화면 복귀 구조는 Expo Router app 폴더 구조 글과 함께 보면 흐름이 더 분명해집니다.

많이 받는 질문

Q. expo-web-browser와 react-native-webview는 같은 용도로 봐도 되나요?
같게 보면 정리가 잘 안 됩니다. expo-web-browser는 시스템 브라우저 경험을 호출하는 쪽에 가깝고, react-native-webview는 앱 내부에 웹 콘텐츠를 직접 렌더링하는 쪽에 가깝습니다. 외부 정책 페이지나 인증 창은 전자가, 앱 안에서 깊게 제어할 웹 화면은 후자가 더 맞습니다.

Q. 로그인 버튼도 openBrowserAsync로 열면 안 되나요?
열리는 것 자체는 가능할 수 있지만, 인증 후 앱으로 돌아오는 흐름까지 생각하면 openAuthSessionAsync가 더 적절한 경우가 많습니다. 특히 리디렉션과 인증 결과 복귀가 필요한 경우에는 인증 세션용 메서드 기준으로 보는 편이 안전합니다.

Q. Expo Router를 쓰면 딥링크 설정을 아예 신경 쓰지 않아도 되나요?
라우팅 연결은 많이 편해지지만, 앱 스킴과 인증 제공자에 등록할 URI까지 자동으로 해결되는 것은 아닙니다. Router는 URL과 화면 연결을 단순하게 만들어주고, 인증 복귀를 성립시키는 기본 전제는 여전히 scheme와 올바른 URL 설정입니다.

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

“Expo WebBrowser 사용법: 외부 링크와 로그인 복귀 처리”에 대한 6개의 생각

댓글 남기기