PWA를 폰에 설치했는데 홈 화면 아이콘이 깨져 보인 적 있으신가요? 십중팔구 site webmanifest icon sizes 설정이 잘못된 겁니다. Android는 가장 큰 이미지를 알아서 축소해주지 않습니다. manifest.json에 선언된 값을 기준으로 아이콘을 자르고, 늘리고, 마스킹까지 거침없이 처리해버립니다.

저도 2026년에 이 문제로 정말 고생했습니다. 제가 만든 앱이 개발용으로 쓰던 Pixel에서는 완벽하게 보였는데, 삼성폰에서 테스트해보니 아이콘이 작고 찌그러져 보이더군요. 이미지 품질 문제가 아니었습니다. manifest 설정이 원인이었습니다.

manifest 파일 자체에 대해 더 자세히 알고 싶으시다면 favicon site.webmanifest 개발자 가이드를 먼저 읽어보세요. 이 글에서는 icons 배열과 명시해야 할 정확한 사이즈에만 집중합니다.

준비물

고해상도 원본 이미지(최소 512x512 픽셀)와 텍스트 에디터면 충분합니다. 원본 파일이 없다면 Mzu favicondl에서 기존 로고나 이미지로 바로 생성할 수 있습니다.

단계별로 설정하기: Manifest Icons 구성

이제 bulletproof icons 배열을 만들어봅시다. 현대 Android와 PWA 환경에서 실제로 의미 있는 세 가지 항목에 집중하겠습니다.

1. 192x192 Standard PNG

기본 베이스라인입니다. Android는 일반적인 디스플레이에서 앱 런처 아이콘을 표시할 때 이 사이즈를 사용합니다. 반드시 명시적으로 선언해야 합니다.

브라우저가 512x512 이미지를 알아서 축소해줄 거라 기대하지 마세요. Android 렌더링 엔진은 축소 과정에서 예상치 못한 보간을 적용할 때가 있어 아이콘이 뭉개져 보일 수 있습니다. 전용 192x192 PNG를 따로 준비하세요.

2. 512x512 High-Res PNG

스플래시 화면용 아이콘입니다. PWA가 실행될 때 service worker가 로드되는 동안 Android가 흰 배경 위에 이 이미지를 띄워줍니다. manifest에 아이콘을 하나만 선언해야 한다면 이걸 선택하세요 (하지만 실제로는 그러지 마세요).

3. Maskable Icon (핵심)

Android 13 이상과 최신 Chrome OS는 adaptive icon을 사용합니다. maskable icon을 선언하지 않으면 OS가 표준 아이콘을 흰 원 안에 집어넣어버립니다. 정말 보기 안 좋습니다.

maskable icon은 중앙에 'safe zone'이 필요합니다. OS가 원, 라운드 사각형 등 어떤 형태로 잘라내도 로고가 잘리지 않도록 디자인에 여백을 둬야 합니다. 디자인 측면은 maskable icon 가이드에서 자세히 다루고 있습니다.

전체 코드

지금 당장 manifest.json에 복사해서 붙여넣을 수 있는 icons 배열입니다:

{
  "name": "My Awesome App",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "/icons/icon-maskable-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

purpose 필드를 주목하세요. OS가 파일을 어떻게 사용할지 알려주는 역할입니다. 생략하면 브라우저는 any로 간주하는데, 이렇게 되면 maskable icon이 표준 아이콘으로 사용되어 이상하게 여백만 큰 아이콘이 될 수 있습니다.

자주 발생하는 실수들

코드가 맞아도 문제는 생깁니다. 제가 가장 많이 겪은 실수들입니다.

하나의 'any maskable' Icon으로 때우기

일부 개발자는 용량을 아끼려고 하나의 아이콘에 "purpose": "any maskable"을 선언합니다. 절대 하지 마세요. maskable icon은 기본적으로 여백이 내장되어 있습니다. 브라우저가 그 파일을 표준 any 요청에도 사용하면 런처 안에서 아이콘이 비정상적으로 작게 보입니다. 무조건 파일을 분리하세요.

Safe Zone 무시하기

예쁜 512x512 아이콘을 디자인했습니다. maskable로 업로드했습니다. 그런데 OS가 원으로 자르니까 로고가 반쯤 잘려나갔습니다. maskable icon은 캔버스 중앙 80% 영역(safe zone) 안에 아트워크를 위치시켜야 합니다.

sizes 속성과 실제 파일 사이즈 불일치

실제 파일은 512x512인데 manifest에 "sizes": "192x192"라고 적는 경우가 있습니다. Android는 혼란스러워합니다. OS는 실제 파일 크기보다 manifest 선언값을 우선합니다. 항상 이미지 크기와 선언값이 일치하는지 확인하세요.

프로들은 어떻게 하는가

GitHub의 PWA를 분석해보세요. 15개나 되는 다양한 PNG 사이즈를 만들지 않습니다. 표준 192, 512, 그리고 전용 maskable 버전만 제공합니다. 이게 현대적인 표준입니다. DevTools를 열어 manifest를 직접 확인해보면 됩니다.

다른 사이트들이 아이콘을 어떻게 처리하는지 분석하고 싶다면 Mzu favicondl을 사용해 manifest 설정을 다운로드하고 분석해보세요. minify된 HTML을 뒤질 필요가 없습니다.

마무리

수십 개의 아이콘 파일을 만들지 마세요. site webmanifest icon sizes 배열에 필요한 건 세 가지뿐입니다: 192x192, 512x512, 그리고 512x512 maskable 버전. 코드를 깔끔하게 유지하고 safe zone을 지키면 모든 기기에서 네이티브 앱처럼 보이는 PWA를 만들 수 있습니다.