Speaker Cleaner & Sound Fix
과학적으로 최적화된 음파 주파수를 사용하여 iPhone & iPad 스피커에서 물을 배출합니다.
PumpWater는 디바이스 스피커를 통해 정밀한 165Hz 사인파를 생성합니다. 이 주파수는 iPhone 및 iPad 스피커의 물리적 크기에 맞춰 최적화되어 있으며, 스피커 멤브레인을 최적의 속도로 진동시켜 스피커 그릴에 갇힌 물을 물리적으로 밀어냅니다.
Apple Watch의 Water Lock 기능에서 영감을 받았으며, 고급 사용자를 위해 더 넓은 주파수 범위(20Hz -- 2,600Hz)를 지원합니다.
| 기능 | 설명 |
|---|---|
| 최적화 주파수 | 165Hz 사인파 -- iPhone 스피커 물 배출에 가장 효과적인 주파수 |
| 커스텀 주파수 범위 | 20Hz ~ 2,600Hz 전체 슬라이더 제어 |
| 빠른 프리셋 | Low(165Hz), Mid(300Hz), High(500Hz) 원탭 전환 |
| 타이머 | 최대 10분까지 설정 가능, 자동 정지 기능 |
| 물 애니메이션 | Canvas + TimelineView 기반 30fps 실시간 유체 애니메이션 |
| 안전 경고 | 2,000Hz 이상 주파수 설정 시 청력 위험 경고 표시 |
| 무음 모드 지원 | 디바이스 무음 스위치가 켜져 있어도 정상 작동 (.playback 오디오 카테고리) |
| 다크 & 라이트 모드 | Liquid Glass 디자인 기반 완벽한 외관 대응 |
| 유니버설 앱 | iPhone 및 iPad 최적화 레이아웃 |
| 8개 언어 지원 | 한국어, 영어, 독일어, 스페인어, 프랑스어, 일본어, 중국어 간체 & 번체 |
| 접근성 | VoiceOver 라벨 & 힌트, Reduce Motion 대응, 44pt 최소 터치 영역 |
| 카테고리 | 기술 | 용도 |
|---|---|---|
| UI | SwiftUI | 전체 사용자 인터페이스 |
| 오디오 | AVFoundation (AVAudioEngine + AVAudioPlayerNode) |
실시간 사인파 생성 |
| 애니메이션 | Canvas + TimelineView |
30fps 물결 파형 + 물방울 파티클 |
| 디자인 시스템 | Liquid Glass (커스텀) | ultraThinMaterial, 그래디언트, 글라스 카드 |
| 상태 관리 | @Observable (Observation 프레임워크) |
HomeViewModel |
| 분석 | Firebase Analytics | 9개 이벤트 추적 |
| 원격 설정 | Firebase Remote Config | 강제 업데이트 버전 체크 |
| 광고 | Google AdMob (Banner) | 하단 배너 광고 |
| 개인정보 | App Tracking Transparency | IDFA 동의 프롬프트 |
| 모듈화 | Local Swift Packages (4개 패키지) | Clean Architecture 레이어 분리 |
| 패키지 관리 | Swift Package Manager | Firebase SDK, Google Mobile Ads SDK |
| 배포 | Fastlane | Match 코드 서명, TestFlight & App Store 업로드 |
| CI/CD | GitHub Actions | PR 빌드 검증 + 자동 TestFlight 배포 |
| 로깅 | os.log (Logger) |
오디오 엔진 구조화된 로깅 |
Clean Architecture 원칙에 따라 단방향 의존성을 가진 4개의 로컬 Swift Package로 구성되어 있습니다. Presentation과 Data는 서로 독립적인 형제 레이어이며, Domain 프로토콜을 통해서만 연결됩니다.
┌─────────────────────────────────────────────────────┐
│ App.swift │
│ (Composition Root + DI) │
│ imports: Data, Presentation, Domain │
└───────┬──────────────────┬──────────────────┬───────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Presentation │ │ Data │ │ Domain │
│ │ │ │ │ │
│ HomeView │ │ AudioEngine │ │ Protocols │
│ HomeViewModel │ │ Service │ │ Entities │
│ Components │ │ Firebase │ │ FrequencyConf │
│ Theme │ │ Analytics │ │ TimerConfig │
│ │ │ ForceUpdate │ │ │
│ (SwiftUI, │ │ Service │ │ (Foundation │
│ GoogleAds) │ │ │ │ only, zero │
│ │ │ (Firebase SDK)│ │ dependencies)│
└───────┬───────┘ └──┬─────┬──────┘ └───────────────┘
│ │ │ ▲ ▲
│ │ │ │ │
└─────────────┼─────┼─────────────────┘ │
│ │ │
└─────┼────────────────────┘
│
▼
┌───────────────┐
│ Core │
│ │
│ Audio engine │
│ settings, │
│ App Store ID, │
│ AdMob IDs │
│ │
│ (Foundation │
│ only, zero │
│ dependencies)│
└───────────────┘
의존성 방향:
- Domain -- 외부 의존 없음 (최내부 레이어). 비즈니스 규칙, 프로토콜, 엔티티, 도메인 설정 포함
- Presentation → Domain (+ GoogleMobileAds 외부 SDK)
- Data → Domain + Core (+ Firebase SDK)
- Core -- 외부 의존 없음. 인프라 상수만 포함
- App.swift → 모든 레이어 (Composition Root에서 의존성 조립)
핵심 패턴:
- Protocol-oriented DI --
AudioEngineProtocol,AnalyticsProtocol,ForceUpdateProtocol을 Domain에 정의하고, Data에서 구현 - Composition Root --
App.swift에서@UIApplicationDelegateAdaptor를 통해 모든 의존성 조립 - 형제 레이어 분리 -- Presentation과 Data가 서로 의존하지 않아 독립적 테스트 및 교체 가능
- @Observable --
HomeViewModel이 Observation 프레임워크 사용 - ViewModifier 패턴 --
LiquidGlassCard,AdaptiveBackground,ForceUpdateModifier
PumpWater-iOS/
├── PumpWater-iOS/
│ ├── PumpWater-iOS.xcodeproj/
│ ├── PumpWater-iOS/
│ │ ├── App/
│ │ │ ├── App.swift # @main, Composition Root, ATT, Splash
│ │ │ └── ContentView.swift # Preview wrapper
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/ # 앱 아이콘
│ │ │ ├── AccentColor.colorset/
│ │ │ ├── LaunchBackground.colorset/ # 스플래시 배경 (다크/라이트)
│ │ │ └── LaunchIcon.imageset/ # 스플래시 아이콘
│ │ ├── Info.plist # ATT, AdMob, SKAdNetwork, LaunchScreen
│ │ ├── {ko,en,ja,de,es,fr,zh-Hans,zh-Hant}.lproj/
│ │ │ └── InfoPlist.strings # 다국어 ATT 설명
│ │ └── GoogleService-Info.plist # Firebase 설정
│ └── Packages/
│ ├── PumpWaterCore/ # Config, 상수 (Foundation only)
│ ├── PumpWaterDomain/ # 프로토콜, 엔티티
│ ├── PumpWaterData/ # 서비스 구현체 + Firebase
│ └── PumpWaterPresentation/ # SwiftUI 뷰, 컴포넌트, 테마
│ ├── Home/ # HomeView, HomeViewModel
│ ├── Components/ # PlayButton, TimerDisplay, FrequencySlider,
│ │ # WaterAnimation, ForceUpdateView,
│ │ # PrivacyPolicyView, FrequencySafetyInfoView,
│ │ # SplashView
│ ├── Common/ # Theme (Liquid Glass), AdBannerView
│ └── Resources/ # 8개 언어 x Localizable.strings
├── fastlane/
│ ├── Fastfile # Lanes: beta, release, sync_certificates
│ ├── Appfile / Matchfile / Deliverfile
│ ├── metadata/ # 7개 로케일 메타데이터
│ └── screenshots/ # 7개 언어 스크린샷
├── .github/workflows/ci.yml # GitHub Actions CI/CD
├── Gemfile / Gemfile.lock
├── CLAUDE.md
└── README.md
요구사항: Xcode 16+, iOS 17+ 시뮬레이터 또는 실기기
xcodebuild -project PumpWater-iOS/PumpWater-iOS.xcodeproj \
-scheme PumpWater-iOS \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.5' \
buildFastlane 기반으로 배포하며, 코드 서명은 Match로 관리합니다.
# 인증서 동기화 (최초 1회)
bundle exec fastlane sync_certificates
# TestFlight 배포
bundle exec fastlane beta
# App Store 배포 (자동 출시 + 단계적 배포)
bundle exec fastlane releaseCI/CD: GitHub Actions가 모든 PR에서 빌드 검증을 수행하고, main 브랜치 push 시 자동으로 TestFlight에 배포합니다.
이 프로젝트는 Conventional Commits를 사용합니다.
<type>: <description>
| Type | 용도 |
|---|---|
feat |
새로운 기능 |
fix |
버그 수정 |
refactor |
코드 구조 개선 |
chore |
유지보수, 설정, 의존성 |
docs |
문서 |
test |
테스트 |
style |
서식, 공백 |
perf |
성능 개선 |
예시:
feat: Firebase Remote Config 기반 강제 업데이트 기능 추가
fix: iPad 오디오 엔진 크래시 수정
chore: 버전 2.0.0 Build 1 업데이트
docs: README 아키텍처 다이어그램 업데이트
이 프로젝트는 MIT License에 따라 라이선스가 부여됩니다.
v1.0.0 → v2.0.0 변경 이력
| 항목 | v1.0.0 | v2.0.0 |
|---|---|---|
| 아키텍처 | 단일 ContentView | Clean Architecture + 4개 Swift Package |
| 디자인 | 하드코딩 흰색 배경 | Liquid Glass 리디자인 |
| 최소 iOS | 14.0 | 17.0 |
| 다크 모드 | 미지원 | 완벽 지원 |
| iPad | 미지원 | 풀스크린 레이아웃 지원 |
| 광고 | 없음 | AdMob Adaptive Banner (iPhone/iPad) |
| 분석 | 없음 | Firebase Analytics 9개 이벤트 |
| 강제 업데이트 | 없음 | Firebase Remote Config |
| 다국어 | 영어만 | 8개 언어 |
| ATT | 없음 | App Tracking Transparency |
| 개인정보 | 없음 | 인앱 개인정보 처리방침 |
| 배포 | 수동 | Fastlane + GitHub Actions CI/CD |
| 애니메이션 | 없음 | Canvas + TimelineView 30fps 물 애니메이션 |
| 주파수 안전 | 없음 | 2,000Hz 이상 경고 |
| 스플래시 | 없음 | 앱 아이콘 + 페이드 아웃 |
| 무음 모드 | 작동 안함 | .playback 카테고리로 작동 |