테마 전환
디바이스 구분 방법
게임웹뷰는 iOS · Android 두 플랫폼과 폰 · 태블릿 두 폼팩터에서 동작합니다.
플랫폼별 처리나 태블릿 레이아웃이 필요할 때 아래 코드로 기기를 구분할 수 있습니다.
- 의존성이 없습니다.
파일 하나를 복사해 그대로 사용하세요. - 구분 기준은 User-Agent 문자열이며, iPadOS 예외 한 건만
navigator.maxTouchPoints를 함께 사용합니다. - 카카오톡 인앱 웹뷰 여부(
isKakaoTalk)도 함께 구분합니다.
구분이 필요한 대표적인 경우
| 상황 | 이유 |
|---|---|
웹뷰 접기(keepBrowser) UI 노출 | 접기는 카카오톡 안의 iPhone 에서만 제공합니다. 태블릿에서는 웹뷰가 접히지 않고 그대로 종료됩니다. 게임웹뷰 SDK: keepBrowser 참고 |
| 태블릿 레이아웃 | 큰 화면에 맞춘 배치가 필요한 경우. 게임 공통 제작 가이드 참고 |
| 플랫폼별 처리 | Android 하드웨어 백 버튼 처리 등 |
코드
ts
export type DeviceInfo = {
/** 'unknown' 은 iOS·Android 가 아닌 환경 (데스크톱 브라우저 등). */
platform: 'ios' | 'android' | 'unknown';
isIOS: boolean;
isAndroid: boolean;
/** iPad 및 Android 태블릿. 폴더블 폰의 펼침 상태는 태블릿이 아닙니다. */
isTablet: boolean;
/** 카카오톡 인앱 웹뷰 여부. 게임웹뷰를 포함합니다. */
isKakaoTalk: boolean;
};
const UNKNOWN_DEVICE: DeviceInfo = {
platform: 'unknown',
isIOS: false,
isAndroid: false,
isTablet: false,
isKakaoTalk: false,
};
/**
* 터치 스크린 보유 여부.
*
* iPadOS 13+ 는 Safari '데스크톱용 사이트' 모드에서 User-Agent 를 `Macintosh` 로 보고합니다.
* 이 경우 User-Agent 만으로는 데스크톱 macOS 와 구분되지 않으므로 터치 지원 여부로 구분합니다.
* (데스크톱 macOS 는 두 값 모두 거짓, iPadOS 는 참)
*/
function hasTouchScreen(win: Window): boolean {
const maxTouchPoints = win.navigator?.maxTouchPoints ?? 0;
if (maxTouchPoints > 1) {
return true;
}
return win.document !== undefined && 'ontouchend' in win.document;
}
function readUserAgent(win: Window): string {
return win.navigator?.userAgent ?? '';
}
export function getDeviceInfo(win: Window = window): DeviceInfo {
const userAgent = readUserAgent(win);
if (!userAgent) {
return UNKNOWN_DEVICE;
}
// 카카오톡 인앱 웹뷰는 iPad 토큰을 유지하므로 이 분기를 타지 않습니다.
// 카카오톡 외부(일반 Safari)에서 페이지가 열리는 경우를 위한 안전망입니다.
const isDesktopModeIPad = /Macintosh/i.test(userAgent) && hasTouchScreen(win);
const isIOS = /iPhone|iPad|iPod/i.test(userAgent) || isDesktopModeIPad;
// 레거시 Windows Phone User-Agent 가 'Android 4.0' 을 포함해 오탐됩니다.
const isAndroid = /Android/i.test(userAgent) && !/Windows Phone/i.test(userAgent);
// Android 태블릿은 User-Agent 에서 'Mobile' 토큰이 빠집니다.
// iOS 는 iPad 토큰으로 구분합니다 — iPad 에도 'Mobile' 토큰이 있어 위 규칙을 쓸 수 없습니다.
const isTablet =
/^(?=.*android)(?!.*mobile).*/i.test(userAgent) || /iPad/i.test(userAgent) || isDesktopModeIPad;
// 카카오톡 인앱 웹뷰는 iOS·Android 모두 User-Agent 에 KAKAOTALK 토큰을 넣습니다.
const isKakaoTalk = /KAKAOTALK/i.test(userAgent);
const platform = isIOS ? 'ios' : isAndroid ? 'android' : 'unknown';
return {platform, isIOS, isAndroid, isTablet, isKakaoTalk};
}사용 방법
ts
declare function applyTabletLayout(): void;
declare function registerAndroidBackHandler(): void;
declare function showCollapseButton(): void;
const {isIOS, isAndroid, isTablet, isKakaoTalk} = getDeviceInfo();
if (isTablet) {
applyTabletLayout();
}
if (isAndroid) {
registerAndroidBackHandler();
}
// 접기는 카카오톡 안의 iPhone 에서만 제공합니다. Android 와 태블릿은 대상이 아닙니다.
if (isKakaoTalk && isIOS && !isTablet) {
showCollapseButton();
}User-Agent 는 페이지 수명 동안 바뀌지 않습니다.
모듈 로드 시 한 번 호출해 결과를 재사용해도 됩니다.
platform 값은 isIOS · isAndroid 와 항상 일치합니다.
편의를 위한 중복이므로 어느 쪽을 써도 됩니다.
판정 규칙
| 항목 | 규칙 | 근거 |
|---|---|---|
isIOS | User-Agent 에 iPhone · iPad · iPod 중 하나.또는 Macintosh + 터치 보유 | 카카오톡 인앱 웹뷰는 기기 토큰을 유지합니다.Macintosh 조건은 카카오톡 외부 iPadOS 대응용입니다 |
isAndroid | User-Agent 에 Android, 단 Windows Phone 제외 | 레거시 Windows Phone User-Agent 가 Android 4.0 을 포함해 오탐됩니다 |
isTablet | 셋 중 하나: ① android 가 있고 mobile 이 없음 ② User-Agent 에 iPad ③ Macintosh + 터치 보유 | ① Android 는 폰에만 Mobile 토큰을 넣어 태블릿에서는 생략됩니다. ② iPad 에도 Mobile 토큰이 있어 ①번 규칙을 iOS 에 쓸 수 없습니다. ③ User-Agent 에 iPad 토큰이 없는 유일한 iPad 케이스입니다 |
isKakaoTalk | User-Agent 에 KAKAOTALK | 카카오톡 인앱 웹뷰는 iOS · Android 모두 이 토큰을 넣습니다. 게임웹뷰도 인앱 웹뷰이므로 true 입니다 |
User-Agent 예시
카카오톡 26.7.0 기준입니다.
끝부분에는 카카오톡 버전과 웹뷰 구분값이 붙습니다.
text
iPhone Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15
Mobile/15E148 KAKAOTALK/26.7.0 ...
iPad Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15
(KHTML, like Gecko) Mobile/15E148 KAKAOTALK/26.7.0 ...
Android Mozilla/5.0 (Linux; Android 14; SM-S928N; wv) AppleWebKit/537.36
Mobile Safari/537.36; ... KAKAOTALK 2426700iPad 예시의 Mobile/15E148 을 주의해서 보세요.
iPad 에도 Mobile 토큰이 있습니다.
이 때문에 Android 의 Mobile 토큰 규칙을 iOS 에 적용할 수 없습니다.
환경별 판정 결과
구현을 검증할 때 참고하세요.
O = true, - = false 입니다.
| 환경 | isIOS | isAndroid | isTablet | isKakaoTalk |
|---|---|---|---|---|
| iPhone: 게임웹뷰 | O | - | - | O |
| iPad: 게임웹뷰 | O | - | O | O |
| Android 폰: 게임웹뷰 | - | O | - | O |
| Android 태블릿: 게임웹뷰 | - | O | O | O |
| iPhone: Safari | O | - | - | - |
| iPad: Safari | O | - | O | - |
| iPad: Safari 데스크톱용 사이트 모드 | O | - | O | - |
| iPod touch: Safari | O | - | - | - |
| Android 폰: Chrome | - | O | - | - |
| Android 태블릿: Chrome | - | O | O | - |
| 폴더블 폰 펼침: Chrome | - | O | - | - |
| 데스크톱: macOS Safari · Chrome | - | - | - | - |
| 데스크톱: Windows Chrome (터치 포함) | - | - | - | - |
데스크톱 환경에서는 platform 이 'unknown' 이 됩니다.
User-Agent 를 읽을 수 없는 경우에도 예외를 던지지 않고 'unknown' 을 반환합니다.
주목할 두 가지가 있습니다.
- iPad 데스크톱용 사이트 모드와 데스크톱 macOS Safari 는 User-Agent 문자열이 완전히 같습니다.
maxTouchPoints없이는 구분할 수 없습니다. - 폴더블 폰 펼침 상태는 화면이 태블릿만큼 넓지만 태블릿이 아닙니다.
화면 크기 기반 판정이 실패하는 대표적인 경우입니다.
사용하면 안 되는 방식
아래 방식은 위 표의 환경 중 일부에서 오판을 일으킵니다.
| 방식 | 문제 |
|---|---|
screen.width · window.innerWidth 로 태블릿 판정 | 폴더블 폰 펼침 상태(짧은 변 약 674px)를 태블릿으로 오판합니다. iPad 에서 카카오톡이 split view 로 표시되면 innerWidth 가 기기 크기와 무관해지는 문제도 있습니다 |
iOS 에 "Mobile 토큰이 없으면 태블릿" 규칙 적용 | iPad 에도 Mobile 토큰이 있어 iPad 를 폰으로 오판합니다.Android 전용 규칙입니다 |
navigator.platform 사용 | Deprecated 된 API 이며, iPadOS 는 MacIntel 을 반환해 데스크톱과 구분되지 않습니다 |
navigator.userAgentData 단독 사용 | Chromium 계열 전용입니다. iOS 에는 존재하지 않아 iPhone · iPad 판정이 전부 실패합니다 |
| 카카오톡 버전으로 기능 지원 여부 분기 | 패치 · 백포트 빌드에서 버전 비교가 어긋납니다. 기능 지원 여부는 해당 메서드의 실제 존재를 확인하는 방식으로 판단하세요 |
기기 구분과 레이아웃 판단은 분리하세요.
기기 종류는 User-Agent, 레이아웃은 viewport 또는 media query 를 사용합니다.
iPad split view 처럼 기기 크기와 표시 영역이 일치하지 않는 상황이 있습니다.
적용 범위
이 코드는 기기 종류(플랫폼 · 폼팩터)와 카카오톡 인앱 웹뷰 여부를 구분합니다.
isKakaoTalk 은 카카오톡 안에서 열렸는지만 알려줍니다.
게임웹뷰인지 일반 인앱브라우저인지까지 구분하지는 않습니다.
게임은 언제나 게임웹뷰에서 실행되므로 이 구분이 필요한 경우는 드뭅니다.
동작이 예상과 다른 기기를 발견하면 해당 기기의 User-Agent 문자열과 함께 카카오디벨로퍼스 데브톡으로 알려주세요.
판정 규칙에 반영하겠습니다.
참고 문서
- 게임웹뷰: 게임웹뷰의 역할과 전체 개발 순서
- 게임웹뷰 SDK: keepBrowser: 접기를 iPhone 에서만 노출해야 하는 이유
- 게임 공통 제작 가이드: 태블릿 레이아웃 기준
- 심사 체크리스트: 단말기 확인 항목