MAKING · 웹 기술
웹게임을 앱처럼: 홈 화면 설치와 오프라인 플레이(PWA)
앱스토어 없이 웹게임을 홈 화면에 설치하고 오프라인에서도 돌아가게 만드는 PWA의 구성 요소, 캐시 전략, 설치 방법, 업데이트할 때 주의할 점을 정리했습니다.
스택 타워와 로또르르는 홈 화면에 설치할 수 있습니다. 앱스토어를 거치지 않았는데도 아이콘을 누르면 주소창 없는 전체 화면으로 열리고, 스택 타워는 비행기 모드에서도 플레이됩니다. 이런 웹 앱을 PWA(Progressive Web App)라고 부릅니다. 이 글은 PWA를 이루는 요소와 만들 때 주의할 점을 정리합니다.
PWA를 이루는 세 가지
- HTTPS — 서비스 워커는 보안 연결에서만 동작합니다.
- 웹 앱 매니페스트 — 앱 이름, 아이콘, 시작 주소, 화면 모드를 적은 JSON 파일입니다.
- 서비스 워커 — 페이지와 네트워크 사이에서 요청을 가로채 캐시로 응답할 수 있는 스크립트입니다. 오프라인 동작의 핵심입니다.
매니페스트 예시
{
"name": "My Web Game",
"short_name": "My Game",
"start_url": "/",
"display": "standalone",
"background_color": "#0A1519",
"theme_color": "#0A1519",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
display: standalone이면 주소창 없이 앱처럼 열립니다. HTML의 <head>에 <link rel="manifest" href="/manifest.json">로 연결합니다. 아이콘은 최소 192px와 512px 두 가지를 준비하는 것이 좋습니다.
서비스 워커와 캐시 전략
서비스 워커는 처음 방문할 때 설치되며, 이때 게임에 필요한 파일을 미리 캐시에 담아 둘 수 있습니다. 그다음부터는 요청 종류에 따라 응답 방식을 고릅니다.
| 전략 | 동작 | 어울리는 대상 |
|---|---|---|
| 캐시 우선 | 캐시에 있으면 바로 쓰고, 없을 때만 네트워크 | 게임 코드, 이미지, 폰트 같은 정적 파일 |
| 네트워크 우선 | 네트워크를 먼저 시도하고 실패하면 캐시 | 자주 바뀌는 데이터 |
| 네트워크 전용 | 항상 네트워크, 실패하면 오류 처리 | 랭킹 등록처럼 오프라인으로 대신할 수 없는 요청 |
const CACHE = "game-v12";
const FILES = ["/", "/index.html", "/icon-192.png"];
self.addEventListener("install", (e) => {
e.waitUntil(caches.open(CACHE).then((c) => c.addAll(FILES)));
});
self.addEventListener("fetch", (e) => {
if (e.request.method !== "GET") return; // 점수 등록 같은 요청은 건드리지 않음
e.respondWith(
caches.match(e.request).then((hit) => hit || fetch(e.request))
);
});
스택 타워처럼 단일 HTML 파일에 그래픽과 사운드를 코드로 생성하는 구조는 PWA와 특히 잘 맞습니다. 캐시할 파일이 적어서 첫 설치가 가볍고, 한 번 캐시되면 네트워크 없이 완전히 동작합니다. 온라인 랭킹처럼 네트워크가 필요한 기능만 연결될 때 동작하게 나누면 됩니다.
업데이트할 때 가장 많이 겪는 문제
PWA를 처음 만들면 "고쳐서 배포했는데 사용자 화면이 안 바뀐다"는 문제를 꼭 만납니다. 캐시 우선 전략은 옛 파일을 계속 보여 주기 때문입니다.
- 캐시 이름에 버전을 붙입니다. 배포할 때
game-v12를game-v13으로 바꾸고, 새 서비스 워커의activate단계에서 옛 캐시를 지웁니다. - 서비스 워커 파일 자체는 캐시가 오래 남지 않게 설정합니다. 브라우저가 새 버전을 확인할 수 있어야 합니다.
- 새 버전은 다음 실행부터 적용됩니다. 기본 동작에서는 열려 있는 탭이 모두 닫혀야 새 서비스 워커가 활성화됩니다. 게임 도중에 갑자기 바뀌는 것보다 이 편이 안전하지만, 필요하면 "새 버전이 있어요" 안내를 띄우고 새로 고침을 유도할 수 있습니다.
기기에 저장한 기록은 영원하지 않다
오프라인 게임은 최고 기록, 코인, 업적을 브라우저 저장소에 남깁니다. 하지만 저장 공간이 부족하거나 사용자가 사이트 데이터를 지우면 함께 사라질 수 있습니다. 중요한 진행 상황이라면 navigator.storage.persist()로 영구 저장을 요청해 볼 수 있고, 온라인일 때 서버에 백업하는 기능을 두는 것도 방법입니다. 무엇보다 사용자에게 "기록은 이 기기에 저장된다"는 사실을 알려 두는 것이 좋습니다.
사용자 입장에서 설치하는 법
- 안드로이드(크롬) — 주소창 오른쪽 메뉴(⋮)에서 홈 화면에 추가 또는 앱 설치를 누릅니다. 조건을 갖춘 사이트에서는 설치 안내가 자동으로 뜨기도 합니다.
- 아이폰(사파리) — 아래쪽 공유 버튼을 누르고 홈 화면에 추가를 고릅니다.
- PC(크롬·엣지) — 주소창 오른쪽의 설치 아이콘을 누르면 별도 창으로 실행되는 앱이 됩니다.
PWA가 어울리는 경우
짧게 자주 여는 게임, 매주 한 번 쓰는 도구처럼 다시 찾아오는 서비스라면 PWA의 이점이 큽니다. 앱스토어 심사와 설치 장벽 없이 주소 하나로 배포하고, 원하는 사람만 홈 화면에 설치하면 됩니다. 반대로 한 번 보고 끝나는 페이지라면 굳이 서비스 워커를 붙일 필요는 없습니다.