prod 웹앱(spin.special-partners.com)을 감싸는 네이티브 셸. 화면 개발 없음. - InAppWebView: 쿠키/캐시 영속·UA(spinApp) 태그·풀투리프레시·외부링크 분기·오프라인 화면 - Android 하드웨어 뒤로가기(웹 히스토리→더블탭 종료), navy 스플래시/상태바 - 파일/카메라 업로드 권한(Android/iOS), 생체인증 잠금(local_auth) - FCM 푸시(firebase_messaging) — 설정 전 자동 비활성, 토큰은 웹 세션으로 /api/devices 등록 - prod URL 고정(app_config.dart) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
39 lines
2.2 KiB
Markdown
39 lines
2.2 KiB
Markdown
# spin-mobile
|
|
|
|
spin 웹앱(`https://spin.special-partners.com`)을 감싸는 **Flutter WebView 셸** (Android · iOS).
|
|
화면은 웹앱이 제공하고, 앱은 네이티브 경험(쿠키/캐시 영속, 스플래시, 뒤로가기, 풀투리프레시,
|
|
파일/카메라 업로드, 생체잠금, FCM 푸시)만 담당합니다. "브라우저 안 뜨는" Toss식.
|
|
|
|
## 스택
|
|
- `flutter_inappwebview` — WebView(쿠키·파일업로드·풀투리프레시·UA·JS)
|
|
- `firebase_core` + `firebase_messaging` — FCM (설정 전엔 자동 비활성)
|
|
- `local_auth` 생체잠금 · `url_launcher` 외부링크 · `connectivity_plus` · `shared_preferences`
|
|
- `flutter_native_splash` — navy 스플래시
|
|
|
|
## 구조
|
|
- `lib/app_config.dart` — prod URL·UA 태그·잠금 유예시간
|
|
- `lib/main.dart` — 진입·상태바·푸시 init
|
|
- `lib/webview_screen.dart` — 셸(웹뷰·로딩·오프라인·뒤로가기·외부링크·잠금·토큰등록)
|
|
- `lib/services/push_service.dart` · `lib/services/lock_service.dart`
|
|
|
|
## 실행 / 빌드
|
|
```bash
|
|
flutter pub get
|
|
flutter run
|
|
flutter build apk # Android (release: --release)
|
|
flutter build ios # iOS (서명 필요)
|
|
```
|
|
WebView 대상은 prod 고정(`app_config.dart`의 `baseUrl`). 웹앱은 UA의 `spinApp` 태그로 앱 실행을 감지.
|
|
|
|
## 동작
|
|
- 쿠키/세션 영속 → Keycloak 인앱 로그인 1회 후 자동 유지. 로그아웃은 웹의 계정 메뉴(공통 LOGOUT_URL)로 처리.
|
|
- 뒤로가기(Android): 웹 히스토리 뒤로 → 최상위에서 한 번 더 누르면 종료.
|
|
- 외부 링크(mailto·tel·타 호스트)는 시스템 앱, 인증 호스트는 인앱 유지.
|
|
- 풀투리프레시, 오프라인 에러 화면+다시시도, 파일/카메라 업로드(권한), 생체잠금(백그라운드 1분 후 재진입 시).
|
|
|
|
## 필요 설정 (제공 후 활성화)
|
|
- **FCM**: Firebase 프로젝트 → `flutterfire configure`(또는 수동: `google-services.json`/`GoogleService-Info.plist`
|
|
+ google-services 플러그인 + APNs). 백엔드 `FCM_CREDENTIALS_FILE`에 서비스계정 JSON. 미설정 시 자동 비활성.
|
|
- **iOS 배포**: Apple Developer 서명(번들ID `com.specialpartners.spin`), Xcode 16 권장.
|
|
- **런처 아이콘**: 정사각 PNG + `flutter_launcher_icons`(현재 기본 아이콘).
|