# PWA (Progressive Web App) 가이드 이 문서는 Tr_Code 웹 애플리케이션을 안드로이드 앱으로 패키징하여 Google Play Store에 배포하는 방법을 설명합니다. ## 📋 목차 - [PWA란?](#pwa란) - [TWA (Trusted Web Activity)](#twa-trusted-web-activity) - [준비사항](#준비사항) - [Android Studio 설정](#android-studio-설정) - [앱 빌드](#앱-빌드) - [Play Store 배포](#play-store-배포) - [오프라인 기능](#오프라인-기능) - [FAQ](#faq) ## 🌐 PWA란? **Progressive Web App(PWA)**는 웹 기술로 만들어졌지만 네이티브 앱처럼 동작하는 애플리케이션입니다. ### PWA의 장점 ✅ **설치 가능** - 홈 화면에 아이콘 추가 ✅ **오프라인 작동** - 네트워크 없이도 사용 가능 ✅ **빠른 로딩** - 캐시를 통한 빠른 시작 ✅ **푸시 알림** - 사용자에게 알림 전송 ✅ **자동 업데이트** - 별도 앱 업데이트 불필요 ✅ **크로스 플랫폼** - Android, iOS, Desktop 모두 지원 ### Tr_Code PWA 특징 - **완전한 오프라인 지원**: 한 번 방문 후 네트워크 없이도 사용 가능 - **빠른 응답속도**: HTMX 기반 부분 렌더링 - **모바일 최적화**: 반응형 디자인 - **다크모드**: 자동 다크모드 지원 ## 📱 TWA (Trusted Web Activity) **TWA**는 PWA를 안드로이드 네이티브 앱으로 패키징하는 기술입니다. ### TWA vs WebView | 특징 | TWA | WebView | |------|-----|---------| | 성능 | Chrome 브라우저 엔진 사용 (빠름) | 앱 내장 (느림) | | 업데이트 | 자동 (서버만 업데이트) | 앱 재배포 필요 | | 보안 | Chrome 보안 정책 적용 | 개발자 구현 필요 | | 캐시 | Service Worker | 수동 구현 | | 크기 | 작음 (~2MB) | 큼 (WebView 포함) | ## 🛠️ 준비사항 ### 1. 도메인 및 HTTPS PWA는 HTTPS가 **필수**입니다 (localhost 제외). ```bash # 현재 구조 http://your-domain.com → NPM (Proxmox) → M1T nginx → App ``` NPM(Nginx Proxy Manager)에서 SSL 인증서를 설정하세요: - Let's Encrypt 자동 발급 - 또는 기존 인증서 업로드 ### 2. Android Studio [Android Studio 다운로드](https://developer.android.com/studio) ```bash # 시스템 요구사항 - OS: Windows 10/11, macOS, Linux - RAM: 8GB 이상 권장 - 저장공간: 10GB 이상 ``` ### 3. Java Development Kit (JDK) Android Studio에 포함되어 있지만, 별도 설치도 가능: ```bash # Ubuntu/Linux sudo apt install openjdk-17-jdk # 확인 java -version ``` ### 4. Google Play Console 계정 - [Google Play Console](https://play.google.com/console) 가입 - **일회성 등록 비용**: $25 (평생 사용) - 개발자 계정 승인까지 1-2일 소요 ## 🏗️ Android Studio 설정 ### 1. 프로젝트 생성 이미 `build.gradle` 파일이 있으므로 다음 단계를 진행합니다. ### 2. 기존 프로젝트 구조 ``` Tr_Code/ ├── app/ # Android 앱 소스 │ ├── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── res/ # 리소스 (아이콘, 문자열 등) │ │ └── java/ # Java/Kotlin 코드 ├── build.gradle # 프로젝트 빌드 설정 ├── settings.gradle # 프로젝트 설정 └── twa-manifest.json # TWA 설정 ``` ### 3. twa-manifest.json 설정 ```json { "packageId": "com.trcode.app", "host": "your-domain.com", "name": "1호선 고장코드", "launcherName": "고장코드", "display": "standalone", "themeColor": "#1f2937", "backgroundColor": "#111827", "enableNotifications": false, "startUrl": "/", "iconUrl": "https://your-domain.com/static/icon.png", "maskableIconUrl": "https://your-domain.com/static/icon-maskable.png", "splashScreenFadeOutDuration": 300, "signingKey": { "path": "android.keystore", "alias": "trcode" }, "features": { "locationDelegation": { "enabled": false }, "playBilling": { "enabled": false } } } ``` ### 4. AndroidManifest.xml 주요 설정 ```xml ``` ### 5. Digital Asset Links 설정 TWA가 작동하려면 **도메인과 앱을 연결**해야 합니다. #### 서버 측: `.well-known/assetlinks.json` ```bash # M1T 서버에 파일 생성 sudo mkdir -p /home/ckh08045/Tr_Code/static/.well-known sudo nano /home/ckh08045/Tr_Code/static/.well-known/assetlinks.json ``` ```json [{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.trcode.app", "sha256_cert_fingerprints": [ "YOUR_SHA256_FINGERPRINT_HERE" ] } }] ``` **SHA256 Fingerprint 얻는 방법:** ```bash # 키스토어에서 추출 keytool -list -v -keystore android.keystore -alias trcode # 출력에서 SHA256 찾기 # 예: AA:BB:CC:DD:EE:FF:... # 콜론(:) 제거하고 입력 ``` #### nginx 설정 추가 ```nginx # /etc/nginx/sites-available/tr_code에 추가 location /.well-known/assetlinks.json { alias /home/ckh08045/Tr_Code/static/.well-known/assetlinks.json; default_type application/json; add_header Access-Control-Allow-Origin *; } ``` ```bash # nginx 재시작 sudo systemctl reload nginx # 테스트 curl https://your-domain.com/.well-known/assetlinks.json ``` ## 🔨 앱 빌드 ### 1. 키스토어 생성 (처음 한 번만) ```bash cd /home/ckh08045/Tr_Code # 키스토어 생성 keytool -genkey -v -keystore android.keystore \ -alias trcode \ -keyalg RSA -keysize 2048 -validity 10000 # 정보 입력 # - 비밀번호 (잘 기억하세요!) # - 이름, 조직, 도시, 국가 등 ``` **⚠️ 중요**: `android.keystore` 파일과 비밀번호를 **안전하게 백업**하세요! ### 2. Gradle 빌드 설정 `build.gradle` 파일 확인: ```gradle android { compileSdkVersion 33 defaultConfig { applicationId "com.trcode.app" minSdkVersion 21 targetSdkVersion 33 versionCode 1 versionName "1.0" } signingConfigs { release { storeFile file('android.keystore') storePassword 'your_password' keyAlias 'trcode' keyPassword 'your_password' } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled false } } } ``` ### 3. 빌드 실행 **Android Studio에서:** 1. `Build` → `Select Build Variant` → `release` 선택 2. `Build` → `Build Bundle(s) / APK(s)` → `Build Bundle(s)` 3. 완료되면: `app/build/outputs/bundle/release/app-release.aab` **명령줄에서:** ```bash cd /home/ckh08045/Tr_Code # Clean ./gradlew clean # AAB (Play Store용) 빌드 ./gradlew bundleRelease # 또는 APK (테스트용) 빌드 ./gradlew assembleRelease # 출력 위치 # AAB: app/build/outputs/bundle/release/app-release.aab # APK: app/build/outputs/apk/release/app-release.apk ``` ### 4. 테스트 ```bash # APK 설치 (USB 디버깅 활성화된 안드로이드 기기) adb install app/build/outputs/apk/release/app-release.apk # 또는 Android Studio에서 Run ``` ## 🚀 Play Store 배포 ### 1. Google Play Console 준비 1. [Google Play Console](https://play.google.com/console) 로그인 2. `모든 앱` → `앱 만들기` 3. 앱 세부정보 입력: - 앱 이름: `1호선 고장코드` - 기본 언어: `한국어` - 앱/게임: `앱` - 무료/유료: `무료` ### 2. 앱 콘텐츠 작성 **개인정보처리방침** - URL 제공 (필수) - 예: `https://your-domain.com/privacy-policy` **앱 카테고리** - 카테고리: `비즈니스` 또는 `생산성` - 콘텐츠 등급: 설문조사 진행 **광고** - 광고 포함 여부 선택 ### 3. 프로덕션 릴리스 생성 1. `프로덕션` → `새 릴리스 만들기` 2. `app-release.aab` 업로드 3. 출시 노트 작성: ``` 첫 번째 릴리스 - 고장코드 조회 - TCMS 신호 조회 - MMI 코드 조회 - 오프라인 지원 ``` 4. 검토 제출 ### 4. 스토어 등록정보 **스크린샷** (필수) - 휴대전화: 2개 이상 (16:9 비율) - 7인치 태블릿: 선택사항 - 10인치 태블릿: 선택사항 **그래픽 애셋** - 앱 아이콘: 512x512 PNG - 기능 그래픽: 1024x500 PNG **설명** ``` 1호선 철도 차량 고장코드 및 TCMS 신호 조회 애플리케이션 주요 기능: ✓ 제조사별 고장코드 검색 ✓ TCMS 신호 조회 ✓ MMI 코드 데이터베이스 ✓ 오프라인 지원 ✓ 빠른 검색 및 필터링 철도 유지보수 및 정비 업무를 위한 필수 도구입니다. ``` ### 5. 심사 및 배포 - 제출 후 **1-7일** 심사 기간 - 승인되면 자동으로 Play Store에 배포 - 거부 시 피드백 확인 후 수정하여 재제출 ## 💾 오프라인 기능 ### Service Worker PWA의 오프라인 기능은 **Service Worker**로 구현됩니다. `static/sw.js` 예시: ```javascript const CACHE_NAME = 'tr-code-v1'; const urlsToCache = [ '/', '/static/css/main.css', '/static/js/main.js', '/static/icon.png', ]; // 설치 self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(urlsToCache)) ); }); // 요청 가로채기 self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => response || fetch(event.request)) ); }); // 업데이트 self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheName !== CACHE_NAME) { return caches.delete(cacheName); } }) ); }) ); }); ``` ### manifest.json `static/manifest.json`: ```json { "name": "1호선 고장코드", "short_name": "고장코드", "start_url": "/", "display": "standalone", "background_color": "#111827", "theme_color": "#1f2937", "orientation": "portrait-primary", "icons": [ { "src": "/static/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }, { "src": "/static/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } ] } ``` ### HTML에서 등록 `templates/base.html`: ```html ``` ## ❓ FAQ ### Q1: localhost로 테스트할 수 있나요? **A:** 네! PWA는 `localhost`에서 HTTPS 없이도 작동합니다. 하지만 TWA는 실제 도메인이 필요합니다. ### Q2: 앱 업데이트는 어떻게 하나요? **A:** 서버만 업데이트하면 됩니다! 앱을 다시 빌드/배포할 필요가 없습니다. 사용자가 앱을 열면 자동으로 최신 버전을 로드합니다. 단, 앱 아이콘이나 이름 변경 시에는 Play Store에 새 버전을 제출해야 합니다. ### Q3: iOS는 지원되나요? **A:** PWA 자체는 iOS에서도 작동합니다 (Safari). 하지만 TWA는 Android 전용이므로, iOS 앱을 만들려면: - **웹 앱 추가**: Safari에서 "홈 화면에 추가" - **App Store**: Apple Developer Program ($99/년) 가입 후 네이티브 앱 개발 필요 ### Q4: 서버가 다운되면 앱도 작동하지 않나요? **A:** Service Worker로 캐시를 구현하면 오프라인에서도 기본 기능은 사용할 수 있습니다. 단, 새 데이터는 서버 연결이 필요합니다. ### Q5: 데이터는 어디에 저장되나요? **A:** - **서버**: Supabase (PostgreSQL) - **클라이언트**: 브라우저 캐시 (Service Worker) - **앱 내부**: 없음 (모든 데이터는 웹에서 로드) ### Q6: 보안은 어떻게 되나요? **A:** - HTTPS 필수 (데이터 암호화) - Digital Asset Links (앱-도메인 인증) - Chrome 브라우저의 보안 정책 적용 - Supabase Row Level Security ### Q7: 앱 크기는 얼마나 되나요? **A:** TWA 앱은 매우 작습니다: - **APK/AAB**: 약 2-5MB - **설치 후**: 10-20MB (캐시 포함) 비교: 일반 네이티브 앱은 20-100MB 이상 ### Q8: Play Store 심사에서 거부될 수 있나요? **A:** 가능성 있는 거부 사유: - Digital Asset Links 미설정 - 개인정보처리방침 누락 - 앱 콘텐츠 설명 불충분 - 스크린샷 부족 모두 수정 후 재제출 가능합니다. ### Q9: 현재 서버 구조에서 PWA가 잘 작동하나요? **A:** 네! 현재 구조는 PWA에 최적화되어 있습니다: - ✅ nginx 리버스 프록시 - ✅ HTMX (빠른 로딩) - ✅ 반응형 디자인 - ✅ localhost Supabase (빠른 응답) NPM(Proxmox)에서 HTTPS만 설정하면 완벽합니다! ### Q10: 비용은 얼마나 드나요? **A:** - Google Play Console: **$25** (평생) - 도메인: 연간 $10-20 - SSL 인증서: **무료** (Let's Encrypt) - 서버: 기존 사용 중 **총 초기 비용: 약 $25-50** ## 📚 추가 자료 - [Google TWA 문서](https://developer.chrome.com/docs/android/trusted-web-activity/) - [PWA 완벽 가이드](https://web.dev/progressive-web-apps/) - [Android Studio 가이드](https://developer.android.com/studio/intro) - [Play Console 도움말](https://support.google.com/googleplay/android-developer/) ## 🆘 도움이 필요하신가요? 문제가 발생하거나 질문이 있으면 시스템 관리자에게 문의하세요. --- **작성일**: 2025-10-13 **버전**: 1.0