feat(pwa): PWA + TWA 화 (Android APK 빌드 대비)
- public/manifest.json + service worker(sw.js) 추가 - icon PNG 변환 (192/512/180) - public/.well-known/assetlinks.json placeholder (Bubblewrap 빌드 후 APK 서명 SHA256 채울 자리) - layout.tsx 에 manifest/theme-color/apple-touch-icon 메타데이터 + 서비스 워커 등록 스크립트 추가 Bubblewrap 으로 APK 빌드 시 https://www.momotogether.com/manifest.json 을 source 로 사용. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.momotogether.erp",
|
||||
"sha256_cert_fingerprints": ["REPLACE_WITH_APK_SHA256_AFTER_BUILD"]
|
||||
}
|
||||
}
|
||||
]
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "모모유통 ERP",
|
||||
"short_name": "모모ERP",
|
||||
"description": "모모유통 유통관리 ERP",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#1f2937",
|
||||
"lang": "ko",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 모모유통 ERP — Service Worker (PWA install criteria 충족용)
|
||||
const CACHE = 'momo-erp-v1';
|
||||
const PRECACHE = ['/', '/manifest.json', '/icon-192.png', '/icon-512.png'];
|
||||
|
||||
self.addEventListener('install', (e) => {
|
||||
e.waitUntil(caches.open(CACHE).then((c) => c.addAll(PRECACHE)).catch(() => {}));
|
||||
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();
|
||||
});
|
||||
|
||||
// API 요청은 항상 네트워크 (캐시 안 함). 정적 자원만 캐시.
|
||||
self.addEventListener('fetch', (e) => {
|
||||
const url = new URL(e.request.url);
|
||||
if (url.pathname.startsWith('/api/')) return;
|
||||
if (e.request.method !== 'GET') return;
|
||||
e.respondWith(
|
||||
fetch(e.request).catch(() => caches.match(e.request))
|
||||
);
|
||||
});
|
||||
+34
-2
@@ -1,9 +1,32 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import Script from "next/script";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "모모유통 | 유통관리 ERP",
|
||||
description: "모모유통 유통관리 ERP",
|
||||
manifest: "/manifest.json",
|
||||
applicationName: "모모유통 ERP",
|
||||
appleWebApp: {
|
||||
capable: true,
|
||||
title: "모모ERP",
|
||||
statusBarStyle: "default",
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: "/icon-192.png", sizes: "192x192", type: "image/png" },
|
||||
{ url: "/icon-512.png", sizes: "512x512", type: "image/png" },
|
||||
],
|
||||
apple: [{ url: "/icon-180.png", sizes: "180x180", type: "image/png" }],
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#1f2937",
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
userScalable: false,
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -19,7 +42,16 @@ export default function RootLayout({
|
||||
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body className="h-full">{children}</body>
|
||||
<body className="h-full">
|
||||
{children}
|
||||
<Script id="sw-register" strategy="afterInteractive">
|
||||
{`if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js').catch(() => {});
|
||||
});
|
||||
}`}
|
||||
</Script>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user