587 lines
14 KiB
Markdown
587 lines
14 KiB
Markdown
# 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
|
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
package="com.trcode.app">
|
|
|
|
<!-- 권한 -->
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
|
|
<application
|
|
android:label="1호선 고장코드"
|
|
android:icon="@mipmap/ic_launcher"
|
|
android:theme="@style/Theme.TrCode">
|
|
|
|
<!-- TWA Activity -->
|
|
<activity
|
|
android:name="com.google.androidbrowserhelper.trusted.LauncherActivity"
|
|
android:exported="true">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.MAIN" />
|
|
<category android:name="android.intent.category.LAUNCHER" />
|
|
</intent-filter>
|
|
</activity>
|
|
|
|
<!-- Digital Asset Links (중요!) -->
|
|
<meta-data
|
|
android:name="asset_statements"
|
|
android:resource="@string/asset_statements" />
|
|
|
|
</application>
|
|
</manifest>
|
|
```
|
|
|
|
### 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
|
|
<head>
|
|
<link rel="manifest" href="/static/manifest.json">
|
|
<meta name="theme-color" content="#1f2937">
|
|
<link rel="apple-touch-icon" href="/static/icon.png">
|
|
</head>
|
|
<body>
|
|
<!-- ... -->
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/static/sw.js')
|
|
.then(reg => console.log('SW registered', reg))
|
|
.catch(err => console.log('SW registration failed', err));
|
|
}
|
|
</script>
|
|
</body>
|
|
```
|
|
|
|
## ❓ 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
|
|
|