Files
tetrig/sw.js
tkrmagid 0839705b97 Android(TWA) 앱 패키징 + 재실행 불가 버그 수정
Cloudflare Pages 가 /index.html 을 / 로 308 리다이렉트하는데, 서비스워커가
그 리다이렉트 응답을 캐시해 두면 navigation 요청에 응답할 수 없어(스펙상 금지)
두 번째 실행부터 ERR_FAILED 로 앱이 아예 열리지 않았다.

- sw.js: navigation 은 네트워크 우선 + 캐시된 './' 오프라인 폴백,
  프리캐시는 리다이렉트 플래그 없는 새 Response 로 복사해 저장 (tetrig-v2)
- manifest.webmanifest: start_url 을 './' 로 바꿔 리다이렉트 자체를 회피
- android/: Bubblewrap TWA 프로젝트 (kr.tkrmagid.tetrig, launchUrl '/')
- .well-known/assetlinks.json: 서명 키 SHA-256 등록 → 주소창 없는 전체화면 실행
2026-09-23 04:30:10 +09:00

51 lines
1.6 KiB
JavaScript

// TETRIG 서비스 워커 — 오프라인 캐시 (앱처럼 설치/실행)
const CACHE = 'tetrig-v2';
const ASSETS = [
'./',
'./manifest.webmanifest',
'./icon-192.png',
'./icon-512.png',
'./apple-touch-icon.png',
];
// Cloudflare Pages 는 /index.html 을 / 로 308 리다이렉트한다.
// 리다이렉트된 Response 를 그대로 캐시하면 navigation 요청에 응답할 수 없어
// (spec 상 금지) 두 번째 실행부터 ERR_FAILED 가 난다. 새 Response 로 복사해 저장한다.
async function cacheClean(cache, url) {
const res = await fetch(url, { cache: 'reload' });
if (!res.ok) return;
const body = await res.blob();
await cache.put(url, new Response(body, { status: 200, statusText: 'OK', headers: res.headers }));
}
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open(CACHE).then((c) => Promise.all(ASSETS.map((u) => cacheClean(c, u))))
);
self.skipWaiting();
});
self.addEventListener('activate', (e) => {
e.waitUntil(
caches.keys().then((keys) =>
Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))
)
);
self.clients.claim();
});
self.addEventListener('fetch', (e) => {
if (e.request.method !== 'GET') return;
// 페이지 진입: 네트워크 우선, 실패하면 캐시된 시작 문서로 오프라인 동작
if (e.request.mode === 'navigate') {
e.respondWith(
fetch(e.request).catch(async () => (await caches.match('./')) || Response.error())
);
return;
}
// 나머지 정적 에셋: 캐시 우선
e.respondWith(caches.match(e.request).then((r) => r || fetch(e.request)));
});