왜 Blink 브라우저에 WebKit이 들어갈까? - 브라우저 User Agent의 '호환성 거짓말'


최근 네이버 Whale 브라우저의 User Agent를 분석하다가 흥미로운 발견을 했습니다.

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) 'Chrome/136.0.0.0', 'Whale/4.32.315.22', 'Safari/537.36'

분명히 Whale은 Blink 엔진을 사용하는데, 왜 User Agent에는 AppleWebKit이 들어있을까요? 이것은 웹 브라우저 역사상 가장 흥미로운 “호환성의 거짓말”과 관련이 있습니다.

브라우저 엔진 진화의 역사

1. KHTML에서 시작된 모든 것 (1998)

모든 것은 KDE 프로젝트의 KHTML 엔진에서 시작되었습니다.

1998년: KHTML 렌더링 엔진 개발 (KDE 프로젝트)

2. Apple의 WebKit 탄생 (2003)

Apple이 Safari 브라우저를 위해 KHTML을 포크하여 WebKit을 만들었습니다.

KHTML → WebKit (Apple이 포크)

3. Google Chrome의 등장 (2008)

Google이 WebKit 기반으로 Chrome을 개발했습니다. 이때까지는 Chrome도 진짜 WebKit을 사용했습니다.

WebKit → Chrome (Google이 WebKit 기반으로 개발)

4. Blink의 독립 (2013)

Google이 멀티프로세스 아키텍처와 성능 최적화를 위해 WebKit에서 Blink를 포크했습니다.

WebKit → Blink (Google이 포크)

현재 상황: 실제 vs User Agent

실제 브라우저 구조

네이버 Whale의 실제 구조:

  • 렌더링 엔진: Blink
  • JavaScript 엔진: V8
  • 그래픽스 엔진: Skia
  • 네트워킹: Chromium Network Stack

User Agent에 표시되는 내용:

  • 🤥 AppleWebKit/537.36 (실제로는 사용하지 않음)
  • 🤥 (KHTML, like Gecko) (역사적 호환성)
  • Chrome/136.0.0.0 (Chromium 기반임을 표시)
  • Whale/4.32.315.22 (실제 브라우저 정보)

왜 이런 “거짓말”을 할까?

1. 웹사이트 호환성 문제

많은 웹사이트들이 User Agent 문자열로 브라우저를 감지합니다:

// 잘못된 예시 - 많은 웹사이트가 이렇게 함
if (userAgent.includes('WebKit')) {
  // Safari/Chrome 스타일 CSS 적용
  applyWebKitStyles();
} else {
  // 다른 브라우저 스타일 적용
  applyOtherStyles();
}

만약 Blink 브라우저가 User Agent에서 WebKit을 제거한다면, 기존 웹사이트들이 제대로 동작하지 않을 수 있습니다.

2. 역사적 연속성

Blink는 WebKit에서 포크된 엔진이므로, 근본적으로는 같은 뿌리를 가집니다. API와 기능의 상당 부분이 호환됩니다.

3. 개발자 편의성

웹 개발자들이 복잡한 브라우저 감지 로직을 작성하지 않아도 되도록 합니다.

다른 브라우저들도 마찬가지

Chrome

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36

Microsoft Edge

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edge/131.0.0.0

Opera

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 OPR/117.0.0.0

모든 Chromium 기반 브라우저가 동일하게 AppleWebKit/537.36을 포함합니다!

개발자를 위한 실용적 가이드

❌ 잘못된 브라우저 감지

// 이렇게 하면 안 됩니다!
if (userAgent.includes('WebKit')) {
  console.log('Safari 브라우저입니다'); // 틀림!
}

위 코드는 Chrome, Edge, Whale 등 모든 Blink 브라우저에서도 true를 반환합니다.

✅ 올바른 브라우저 감지

function detectBrowser() {
  const ua = navigator.userAgent;
  
  if (ua.includes('Whale/')) {
    return { name: 'Whale', engine: 'Blink' };
  } else if (ua.includes('Edge/')) {
    return { name: 'Edge', engine: 'Blink' };
  } else if (ua.includes('Chrome/')) {
    return { name: 'Chrome', engine: 'Blink' };
  } else if (ua.includes('Safari/') && !ua.includes('Chrome/')) {
    return { name: 'Safari', engine: 'WebKit' };
  } else if (ua.includes('Firefox/')) {
    return { name: 'Firefox', engine: 'Gecko' };
  }
  
  return { name: 'Unknown', engine: 'Unknown' };
}

🎯 더 나은 접근법: 기능 감지

User Agent 감지보다는 **기능 감지(Feature Detection)**를 우선 사용하세요:

// async/await 지원 체크
function supportsAsyncAwait() {
  try {
    new Function('return (async function(){})()');
    return true;
  } catch (e) {
    return false;
  }
}

// Chromium 기반 브라우저 통합 감지
function isChromiumBased() {
  const ua = navigator.userAgent;
  return ua.includes('Chrome/') || 
         ua.includes('Whale/') || 
         ua.includes('Edge/') ||
         ua.includes('Opera/');
}

// 실제 엔진 감지
function getActualEngine() {
  if (isChromiumBased()) {
    return 'Blink';
  } else if (navigator.userAgent.includes('Safari/') && 
             !navigator.userAgent.includes('Chrome/')) {
    return 'WebKit';
  } else if (navigator.userAgent.includes('Firefox/')) {
    return 'Gecko';
  }
  return 'Unknown';
}

React 하이브리드 앱 개발 시사점

Whale 브라우저에서 async/await 사용

네이버 Whale은 Blink 엔진을 사용하므로 Chrome과 동일한 모든 기능을 지원합니다:

  • async/await 완전 지원 (Chrome 55+와 동일)
  • Progressive Web Apps (PWA) 지원
  • Service Workers, Background Sync
  • Chrome DevTools로 디버깅 가능
  • 모든 최신 웹 표준 지원

안전한 async/await 사용 패턴

// 기능 감지 + 폴백 패턴
function createAsyncFunction() {
  if (supportsAsyncAwait()) {
    return async function fetchData() {
      try {
        const response = await fetch('/api/data');
        return await response.json();
      } catch (error) {
        console.error('Error:', error);
      }
    };
  } else {
    // Promise 폴백
    return function fetchData() {
      return fetch('/api/data')
        .then(response => response.json())
        .catch(error => console.error('Error:', error));
    };
  }
}

// 사용
const fetchData = createAsyncFunction();
fetchData().then(data => {
  console.log('Data:', data);
});

User Agent 버전 번호의 의미

AppleWebKit/537.36

AppleWebKit/537.36
  • 537.36: WebKit SVN 리비전 번호 기반
  • 실제로는 Blink를 사용하지만 호환성을 위해 고정값 사용
  • 대부분의 Chromium 기반 브라우저가 동일한 번호 사용
  • Apple의 실제 WebKit과는 완전히 다른 코드베이스

결론: 개발자가 기억해야 할 것들

🎯 핵심 메시지

  1. User Agent의 WebKit ≠ 실제 WebKit 엔진
  2. Whale, Chrome, Edge는 모두 실제로는 Blink 엔진 사용
  3. User Agent의 WebKit은 호환성을 위한 “거짓말”
  4. 개발 시에는 기능 감지를 우선하고 브라우저 감지는 보조로

📱 한국 시장에서의 의미

StatCounter 데이터에 따르면 한국에서의 브라우저 점유율:

  • Chrome Desktop: 26.77%
  • Chrome for Android: 24.28%
  • Samsung Internet: 15.06%
  • Safari iPhone: 10.59%
  • Whale: 9.43% 🐋

네이버 Whale은 한국에서 9.4%의 점유율을 가진 무시할 수 없는 브라우저입니다. 다행히 Chromium 기반이므로 Chrome과 동일하게 개발하면 됩니다.

💡 실무 권장사항

  1. 기능 감지 우선: typeof, in 연산자, try-catch를 활용
  2. Chromium 기반 브라우저 통합 처리: Whale, Chrome, Edge를 동일하게 취급
  3. User Agent는 참고용: 브라우저별 특수 기능이 필요할 때만 사용
  4. 폴리필과 트랜스파일링: Babel로 호환성 보장

이제 Whale 브라우저의 User Agent에 WebKit이 들어있는 이유를 아시겠죠? 이것은 웹의 역사와 호환성을 위한 선택이었습니다. 개발자로서는 이런 “거짓말” 때문에 혼란스러울 수 있지만, 기능 감지를 우선하는 모던한 개발 방식을 사용한다면 큰 문제가 되지 않습니다.


이 글이 도움이 되셨다면 댓글로 의견을 남겨주세요! 브라우저 호환성과 관련된 다른 궁금한 점이 있으시면 언제든 질문해주세요. 🚀



Written by@[namu]
모바일, 스마트폰, 금융, 재테크, 생활 정보 등