사전 웹뷰
개념

웹뷰

gabury1고친 사람 github-actions[bot]

웹뷰는 앱 화면 안에 웹 페이지를 띄워 주는 부품입니다. 앱은 브라우저를 따로 열지 않고 자기 화면의 한 칸에서 웹 페이지를 보여 줍니다. 그 페이지를 그리는 일은 브라우저와 같은 계열의 엔진이 맡습니다. 앱 화면의 일부를 웹 기술로 만들 때 씁니다.

쉽고 빠른 이해

웹뷰는 앱 화면 안에 작은 브라우저 창을 하나 끼워 넣는 부품입니다. 쇼핑 앱에서 이벤트 배너를 누르면 앱을 떠나지 않고 웹 페이지가 뜨는 것이 대개 웹뷰입니다.

이게 없으면 웹으로 만든 화면을 보여 줄 때마다 사용자를 앱 밖의 브라우저로 내보내야 합니다. 웹에 이미 있는 화면을 앱에서 새로 만들어야 하기도 합니다.

어떻게 도나:

  1. 앱이 화면에 웹뷰 한 칸을 놓고 주소를 넘깁니다
  2. 웹뷰가 그 주소의 페이지를 받아 칸 안에 그립니다
  3. 필요하면 앱과 페이지가 서로 함수를 불러 값을 주고받습니다

대가도 있습니다. 주소창이 없어서 사용자는 지금 어느 사이트를 보는지 확인할 수 없습니다. 앱은 그 안에서 입력되는 글자를 엿볼 수 있습니다. 그래서 다른 서비스의 로그인 화면은 웹뷰로 띄우지 않습니다.

상세

건물주는 건물 안 어디에 얼마나 큰 매장을 낼지 정합니다. 매장 안은 세입자가 꾸밉니다. 그래도 건물주는 마스터키를 쥐고 있어서 언제든 매장 안에 들어갈 수 있습니다.

웹뷰는 앱 화면에 들인 그 매장입니다. 칸의 위치와 크기는 앱이 정합니다. 칸 안은 웹 서버가 보낸 페이지가 채웁니다. 그리고 앱은 마스터키를 쥔 건물주처럼 페이지 안까지 손을 넣을 수 있습니다.

앱 화면을 이루는 한 칸

앱 화면은 뷰 여러 개를 쌓아 만듭니다. 뷰는 화면에서 네모난 한 칸을 차지하고 그 칸을 그리는 부품입니다. 버튼 하나, 글상자 하나, 사진 한 장이 각각 뷰입니다.

이런 뷰는 대개 운영체제가 기본으로 주는 도구로 만듭니다. 운영체제의 도구로 만든 앱을 네이티브 앱이라고 부릅니다. 그 도구로 만든 뷰는 네이티브 뷰라고 부릅니다.

웹뷰도 뷰 가운데 하나입니다. 다른 점은 칸 안을 앱 코드가 아니라 웹 페이지가 채운다는 것입니다. 앱은 웹뷰에 주소 하나를 넘깁니다. 웹뷰는 그 주소의 페이지를 받아 와 칸 안에 그립니다.

flowchart TD
    subgraph 앱화면["앱 화면"]
        T["상단 바 · 네이티브 뷰"]
        W["웹뷰 · 웹 페이지가 채운다"]
        B["하단 탭 · 네이티브 뷰"]
        T ~~~ W ~~~ B
    end
    W -- 페이지를 받아 온다 --> S["웹 서버"]

위아래 막대는 앱이 직접 그립니다. 가운데 칸만 웹 서버에서 받아 온 페이지입니다. 사용자 눈에는 한 화면이지만 만든 쪽은 둘입니다.

브라우저에서 덜어 낸 것

웹 페이지는 세 가지 언어로 적힙니다. HTML(HyperText Markup Language)은 문서의 구조를 적습니다. CSS(Cascading Style Sheets)는 모양을 적습니다. 자바스크립트는 동작을 적습니다.

이 셋을 읽어 화면으로 그려 내는 부분을 렌더링 엔진이라고 합니다. 웹뷰에는 브라우저와 같은 계열의 렌더링 엔진이 들어 있습니다. 그래서 같은 페이지가 브라우저에서와 거의 같게 보입니다.

빠진 것은 브라우저를 둘러싼 껍데기입니다. 아래 표가 둘을 견줍니다.

브라우저 웹뷰
페이지를 그리는 엔진 ✓ ✓
자바스크립트 실행 ✓ ✓
주소창 ✓ ✗
뒤로 가기 · 새로 고침 단추 ✓ ✗
탭 · 북마크 ✓ ✗

껍데기가 없으니 뒤로 가기 같은 조작도 앱이 직접 만들어 붙입니다. 대신 앱은 그 칸을 자기 화면의 일부처럼 꾸밀 수 있습니다. 사용자는 웹 페이지를 보고 있다는 것을 알아채지 못하기도 합니다.

플랫폼마다 붙은 이름

웹뷰는 한 제품의 이름이 아니라 부품의 종류를 가리키는 말입니다. 운영체제마다 저마다의 웹뷰 부품을 줍니다. 안드로이드, iOS(아이폰의 운영체제), 윈도우가 그렇습니다. 앱 개발자가 코드에서 부르는 이름은 아래와 같습니다.

플랫폼 부품 이름 안에서 도는 엔진 계열
안드로이드 WebView Chromium
iOS WKWebView WebKit
윈도우 WebView2 Chromium · Microsoft Edge 와 같은 엔진

이름은 달라도 하는 일은 셋 다 같습니다. 앱 화면에 칸 하나를 내고 그 안에 웹 페이지를 그립니다.

웹뷰를 쓰는 까닭

앱은 새 판을 내려면 앱 스토어 심사를 거칩니다. 사용자가 업데이트를 받아야 바뀐 화면을 봅니다. 웹뷰로 띄운 화면은 웹 서버에 있는 페이지입니다. 서버에서 고치면 다음에 열 때 바로 바뀝니다.

쇼핑 앱이 이벤트 페이지를 웹뷰로 띄우는 까닭이 이것입니다. 이벤트는 자주 바뀌고 기간도 짧습니다. 배너를 누르면 앱을 떠나지 않고 웹 페이지가 뜹니다.

웹에 이미 있는 화면을 다시 만들지 않아도 됩니다. 이용 약관이나 고객 센터처럼 웹사이트에 있는 페이지를 앱 안에 손대지 않고 붙입니다.

한 번 만든 웹 화면을 안드로이드 앱과 iOS 앱이 함께 쓸 수도 있습니다. 화면 대부분을 웹뷰로 채우고 바깥 껍데기만 네이티브로 만든 앱을 하이브리드 앱이라고 부릅니다.

앱과 페이지를 잇는 통로

웹 페이지는 혼자서 기기 기능을 부르지 못합니다. 카메라나 주소록이 그렇습니다. 앱은 이런 기능을 쓸 수 있습니다.

그래서 웹뷰는 앱과 페이지가 서로 부를 수 있는 통로를 둡니다. 이 통로를 흔히 자바스크립트 브리지라고 부릅니다. 앱은 자기 함수에 이름을 붙여 페이지의 자바스크립트에 내놓습니다. 페이지는 그 이름으로 앱 함수를 부릅니다. 페이지가 쓸 기기 기능마다 앱이 이런 함수를 하나씩 만들어 내놓아야 합니다.

반대 방향도 됩니다. 앱은 페이지 안에서 자바스크립트 한 줄을 실행해 페이지에 값을 넘깁니다. 아래는 웹 페이지에서 사진을 올릴 때 두 방향이 차례로 쓰이는 흐름입니다.

sequenceDiagram
    participant 사용자
    participant 페이지 as 웹 페이지
    participant 앱 as 앱 코드
    사용자->>페이지: 사진 올리기 단추를 누른다
    페이지->>앱: 브리지로 카메라를 열어 달라고 부른다
    앱->>사용자: 카메라 화면을 띄운다
    사용자->>앱: 사진을 찍는다
    앱->>페이지: 자바스크립트를 실행해 사진을 넘긴다

페이지는 카메라를 직접 만지지 않습니다. 앱에 부탁하고 결과만 받습니다. 이 통로로 페이지가 앱의 권한을 빌려 쓰는 셈입니다.

그래서 앱은 웹뷰에 열어 줄 주소를 좁혀 둡니다. 모르는 사이트의 페이지가 이 통로를 부르면 앱이 가진 권한이 그 사이트로 새어 나갑니다.

앱이 쥔 권한과 로그인 화면

웹뷰 안의 페이지는 앱의 손 안에 있습니다. 앱은 페이지에 자바스크립트를 넣어 실행할 수 있습니다. 사용자가 입력 칸에 치는 글자도 읽을 수 있습니다.

쿠키도 앱이 읽을 수 있습니다. 쿠키는 웹사이트가 브라우저 쪽에 맡겨 두는 작은 값입니다. 로그인 상태를 흔히 여기에 담습니다. 그래서 쿠키를 가져가면 그 사용자인 척 요청을 보낼 수 있습니다.

사용자 쪽에는 확인할 수단이 없습니다. 주소창이 없어서 지금 보는 페이지가 진짜 그 사이트인지 알 수 없습니다. 브라우저가 주소창 옆에 띄우는 안전한 연결 표시도 없습니다.

앱은 웹뷰 위에 자기 화면을 겹쳐 그릴 수도 있습니다. 사용자가 보는 것과 실제로 누르는 것을 어긋나게 만들 수 있다는 뜻입니다. 이렇게 겹쳐 그려 엉뚱한 것을 누르게 하는 공격이 클릭재킹입니다.

앞에서 본 위험이 한꺼번에 몰리는 화면이 다른 서비스 계정으로 로그인하는 화면입니다. 새로 받은 앱에서 이미 쓰던 포털 계정으로 로그인하는 장면을 떠올려 봅시다. 사용자는 뜬 화면에 포털 비밀번호를 칩니다. 이 화면이 웹뷰라면 앱은 그 비밀번호를 읽을 수 있습니다.

OAuth 2.0(Open Authorization)은 이런 로그인을 위한 규약입니다. 사용자는 비밀번호를 앱에 넘기지 않습니다. 포털의 로그인 화면에서 로그인한 뒤 동의 화면을 봅니다. 동의 화면은 앱이 가져갈 정보를 보여 주고 사용자에게 허락을 받는 화면입니다.

그래서 네이티브 앱은 이 로그인 화면과 동의 화면을 웹뷰로 띄워서는 안 됩니다.

대신 기기의 기본 브라우저나 인앱 브라우저 탭으로 엽니다. 인앱 브라우저 탭은 앱 위에 겹쳐 뜨지만 브라우저가 직접 그리는 창입니다. 앱은 그 안을 들여다보지 못합니다. 브라우저에 이미 로그인해 둔 사용자라면 비밀번호를 다시 치지 않아도 됩니다.

서버에서 본 웹뷰 요청

웹뷰가 보내는 요청은 서버에서 보면 브라우저 요청과 거의 같습니다. 같은 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 규약) 요청이 같은 주소로 옵니다. 서버 코드는 대개 둘을 가를 필요가 없습니다.

가려야 할 때 보는 곳은 사용자 에이전트 문자열입니다. 요청을 보낸 프로그램이 자기를 소개하는 한 줄입니다. 요청 헤더 가운데 User-Agent 헤더에 실려 옵니다. 플랫폼에 따라 여기에 웹뷰라는 표시가 붙습니다.

이 값은 앱이 바꿔 적을 수 있습니다. 화면 모양을 가르는 데는 씁니다. 권한을 가르는 근거로는 못 씁니다.

로그인 상태는 따로 챙겨야 합니다. 웹뷰의 쿠키 저장소는 기기 브라우저의 것과 따로 있습니다. 사용자가 브라우저에서 로그인해 두었어도 웹뷰에서는 로그인 안 된 상태로 보입니다.

앱에 이미 로그인한 사용자라면 앱이 로그인 상태를 웹뷰에 넘겨 줘야 같은 사람으로 이어집니다. 액세스 토큰은 서버가 로그인한 사용자에게 내주는 증표 문자열입니다. 앱은 이 토큰을 요청 헤더에 실어 첫 페이지를 엽니다. 웹뷰의 쿠키 저장소에 로그인 쿠키를 미리 넣어 두는 방법도 있습니다.

웹뷰가 맞는 화면과 안 맞는 화면

지금까지 본 장단을 화면 종류별로 모으면 아래와 같습니다. 가르는 기준은 둘입니다. 서버에서 자주 고치나, 그리고 앱이 엿보면 안 되는 화면인가입니다.

화면 웹뷰 까닭
자주 바뀌는 이벤트 · 공지 맞는다 서버에서 고치면 바로 바뀐다
약관 · 고객 센터 맞는다 웹에 이미 있는 페이지를 붙인다
자기 서비스의 주문 · 결제 맞는다 한 벌로 두 플랫폼이 함께 쓴다
다른 서비스의 로그인 · 동의 안 맞는다 앱이 입력과 쿠키를 엿볼 수 있다
기기 기능을 계속 쓰는 화면 안 맞는다 기능마다 앱이 통로 함수를 내놓아야 한다
모르는 외부 링크 안 맞는다 사용자가 사이트를 확인할 수 없다

위 세 줄은 모두 앱을 만든 쪽이 페이지도 만든 경우입니다. 아래 세 줄은 페이지 주인이 따로 있거나 기기 기능이 주인공인 경우입니다.

관련 항목

웹뷰가 속하는 상위 분류

뷰 · 사용자 에이전트 · 임베디드 브라우저 · UI 컴포넌트 · 모바일 개발

웹뷰 안에서 페이지를 그리는 구성 요소

렌더링 엔진 · 자바스크립트 엔진 · HTML · CSS · 자바스크립트 · DOM

웹뷰를 구현한 플랫폼 부품과 엔진

Android WebView · WKWebView · WebView2 · Chromium · WebKit · Microsoft Edge

웹뷰를 대신할 수 있는 다른 수단

브라우저 · 인앱 브라우저 탭 · Custom Tabs · SFSafariViewController · 네이티브 앱 · 프로그레시브 웹 앱

웹뷰로 화면을 짓는 앱 구조와 프레임워크

하이브리드 앱 · 크로스플랫폼 프레임워크 · Apache Cordova · Capacitor · Ionic

앱과 페이지가 값을 주고받는 통로

자바스크립트 브리지 · postMessage · URL 스킴 · 딥 링크

웹뷰를 노리는 보안 공격

클릭재킹 · 피싱 · 교차 사이트 스크립팅 · 세션 하이재킹 · 자격 증명 탈취

웹뷰 로그인을 막는 인가 규약

OAuth 2.0 · OAuth 2.0 for Native Apps · 인가 서버 · PKCE · 소셜 로그인 · OpenID Connect

서버가 웹뷰 요청을 알아보는 단서

사용자 에이전트 문자열 · User-Agent 헤더 · 쿠키 · 세션 쿠키 · 액세스 토큰 · HTTP 헤더

다른 이름: WebView · web view · 웹 뷰