[바이브코딩 도전기] 아이폰 홈 화면에서 앱처럼 보이게 만든 시행착오 — apple-touch-icon과 PWA 아이콘 삽질기

가계부 웹앱을 NAS에 올리고 나서 제일 먼저 한 일이 아이폰 홈 화면에 추가하는 거였다. Safari에서 공유 버튼 누르고 “홈 화면에 추가” 탭하면 앱처럼 쓸 수 있다는 걸 알고 있었으니까. 그런데 막상 해보니 아이콘 자리에 그냥 웹페이지 스크린샷이 들어가 있었다. 이름도 URL 그대로였고.

대수롭지 않게 생각했다가, 쓸 때마다 눈에 거슬려서 결국 손을 댔다. 그게 생각보다 꽤 돌아가는 길이었다.

SVG 아이콘을 쓰고 있었던 게 문제였다

처음에 파비콘은 SVG로 만들어뒀다. 브라우저 탭에서는 잘 보였고, 딱히 불편함이 없었다. 그런데 iOS Safari는 apple-touch-icon으로 PNG 파일을 요구한다. SVG를 링크해줘도 그냥 무시한다.

공식 문서를 찾아보면 “180×180 PNG를 <head>에 링크하라”고 나온다. 간단해 보이는데, 실제로 해보면 신경 쓸 게 몇 가지 있다.

PNG 파일 만들기 — macOS 터미널로 해결

SVG를 PNG로 변환하는 방법은 여러 가지다. 온라인 변환 사이트도 있고, Figma나 Illustrator를 쓸 수도 있다. 나는 macOS 터미널에서 qlmanagesips를 조합해서 처리했다.

qlmanage로 SVG를 일단 PNG로 뽑아내고, sips로 크기를 조정하는 방식이다.

# SVG → PNG 변환 (qlmanage)
qlmanage -t -s 512 -o ./icons/ icon.svg

# sips로 크기별로 리사이즈
sips -z 180 180 icon_512.png --out apple-touch-icon.png
sips -z 192 192 icon_512.png --out icon-192.png
sips -z 32 32 icon_512.png --out favicon-32.png

크기는 180(apple-touch-icon), 192, 512(PWA manifest용), 32(파비콘 fallback) 이렇게 네 가지를 만들었다. 512짜리를 원본으로 두고 나머지를 거기서 줄이는 게 품질 면에서 낫다.

한 가지 주의할 점은 qlmanage 출력 파일명이 예측 불가능하게 붙는 경우가 있다는 거다. 실행하고 나서 실제로 어떤 이름으로 저장됐는지 확인하고 다음 명령어를 쓰는 게 안전하다.

HTML head에 넣어야 할 것들

PNG를 만들었으면 <head>에 링크를 추가한다.

<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
<link rel="manifest" href="/manifest.webmanifest">

apple-touch-iconsizes 속성 없이 써도 되는데, 명시적으로 적어두는 편이 낫다. 그리고 rel="manifest"도 같이 넣어줘야 PWA 관련 설정이 먹힌다.

manifest.webmanifest 파일 작성

이 파일이 없으면 홈 화면 추가 시 이름이 URL로 뜨거나, 아이콘이 제대로 안 잡히는 경우가 있다. 내용은 JSON 형식이고 크게 복잡하지 않다.

{
  "name": "내 가계부",
  "short_name": "가계부",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#4a90d9",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

display: "standalone"으로 설정하면 홈 화면에서 실행했을 때 Safari의 주소창과 탭 바가 숨겨진다. 진짜 앱처럼 보이는 핵심 설정이다.

theme_color는 상태바 색상에 영향을 준다. iOS에서는 효과가 제한적이지만, Android Chrome에서는 주소창 색이 바뀌어서 꽤 티가 난다.

적용하고 나서도 안 보였던 이유

파일 다 만들고 링크도 넣었는데 처음엔 여전히 스크린샷 아이콘이 나왔다. 알고 보니 이미 홈 화면에 추가해둔 아이콘은 캐시된 상태라 바뀌지 않는 거였다. 기존 아이콘을 지우고 다시 추가했더니 바로 반영됐다.

Safari 자체 캐시도 문제가 될 수 있다. 설정 → Safari → 방문 기록 및 웹 사이트 데이터 지우기를 한 번 해보는 게 확실하다. 귀찮지만 이 단계를 빠뜨리면 “왜 안 되지?” 하고 한참 헤맬 수 있다.

MIME 타입도 확인해야 한다

manifest.webmanifest 파일을 서버에서 올바른 MIME 타입으로 내려줘야 한다. Nginx라면 mime.types에 아래 줄을 추가하거나 확인한다.

application/manifest+json  webmanifest;

이게 빠져 있으면 브라우저가 manifest를 읽긴 하는데 경고를 뱉거나 무시하는 경우가 있다. NAS에서 직접 Nginx를 운영하는 경우라면 꼭 확인해볼 만한 부분이다.

이번 편에서 같이 작업한 것들

아이콘 작업만 한 건 아니었다. 같은 시기에 몇 가지를 병행해서 고쳤다.

튜토리얼 툴팁이 화면 요소에 가려지는 문제가 있었다. 특정 카드나 버튼 위에 툴팁이 떠야 하는데, 그 요소의 z-index가 더 높아서 툴팁이 뒤로 숨어버리는 상황이었다. stacking context 문제였다. 툴팁 DOM을 <body> 바로 아래로 옮기고, CSS에서 z-index를 명시적으로 높여주는 방식으로 해결했다.

월급명세서 쪽도 손봤다. 정기급여 외에 수시로 들어오는 급여 항목 이름을 직접 입력할 수 있게 했다. DB 컬럼 하나 추가하고, API와 화면을 같이 수정했다. 작은 변경처럼 보이지만 실제로 쓰다 보면 항목 이름이 고정돼 있으면 꽤 불편하다.

카드 내역 쪽은 변경이 좀 많았다. 기간 필터를 추가하고, 여러 건을 선택해서 태그나 메모를 한 번에 수정하는 일괄 처리 기능도 붙였다. 체크박스 드래그 선택할 때 첫 번째 행이 토글이 안 되는 버그도 있었는데, 드래그 시작 시점에 직접 토글하는 방식으로 고쳤다.

카드사별 결제일과 사용기간 오프셋 설정도 추가했다. 예를 들어 결제일이 15일이고 오프셋이 -1개월이면, 6월 15일에 결제된 내역은 5월 사용분으로 자동 분류된다. 기존에 입력해둔 거래가 이 기준으로 재분류될 수 있어서, 적용 전에 어떻게 바뀌는지 미리 확인하는 게 중요하다.

정리하자면

iOS Safari에서 홈 화면 아이콘을 제대로 보이게 하려면 결국 세 가지가 필요하다. PNG 아이콘, <head>의 링크 태그, 그리고 manifest.webmanifest. SVG로 퉁치려 하면 안 된다는 걸 몸으로 배웠다.

변환 도구는 뭘 써도 상관없다. macOS 기본 도구로 충분히 되고, 온라인 변환기를 써도 된다. 핵심은 결과물이 PNG여야 한다는 것, 그리고 적용 후에는 기존 홈 화면 아이콘을 지우고 다시 추가해야 변경이 반영된다는 것.

작은 부분인데 막상 안 되면 이유를 찾는 데 시간이 걸린다. 이 글이 같은 삽질을 줄이는 데 조금이라도 도움이 됐으면 한다.


NAS에 직접 만든 개인 가계부 만들기 시리즈는 계속 업데이트됩니다.


시리즈 글 모아보기

댓글 남기기