- 2025년에도 iPhone에서 MP3 음악을 자유롭게 재생하는 것에는 제한이 많음
-
Apple 및 써드파티 앱은 대부분 유료 서비스이거나 사용자 편의성이 부족함
- 직접 만든 앱은 풀텍스트 검색, iCloud 지원, 로컬 우선 환경 등을 제공함
- React Native 등 크로스플랫폼 접근은 파일 시스템 제약과 안정성 문제로 한계가 있었음
- SwiftUI와 SQLite 기반 설계로, 독립적·확장성 높은 음악 관리 경험 구현함
개요
2025년에도 iPhone에서 사용자가 직접 소유한 MP3 파일을 자유롭게 재생하기 어렵다는 현실에 대한 불편함을 직접 해결하고자, 개발자가 스스로 음악 플레이어 앱을 만들게 된 과정과 결과를 소개함. Apple의 음악 서비스와 외부 앱 모두 다양한 제한과 유료화 모델을 가진 반면, 직접 구현한 앱은 사용자 음악 파일 관리 및 재생에 최적화된 경험을 제공함.
음악 플레이어를 스스로 만든 이유
- Apple Music과 iCloud Music Library 등 클라우드 기반 동기화 기능이 유료 서비스 구독을 해야만 동작함
- 구독을 중단할 경우 자동 동기화 및 음악 폴더 접근이 전부 차단됨
- 기존의 음악 라이브러리 통합, 범용 기기 활용성에 대한 소유자 권한 부재를 체감함
- "구매한 스마트폰을 활용해 꼭 필요한 기능은 스스로 만들 수도 있다"는 자기결정성을 실현하고자 함
Apple과 타사 음악 재생 솔루션 분석
Apple 기본 앱
- Files 앱을 이용해 iCloud 폴더에서 음악 파일을 재생할 순 있으나, 재생목록 관리, 메타데이터 정렬, 큐 조작 등 기본적 기능이 부실함
-
음악 감상에 최적화되지 않은 사용자 경험 제공함
서드파티 앱
- 앱스토어에는 다양한 외부 앱이 있으나, 구독 기반 과금 모델이 많고 앱마다 기능 수준이 상이함
- Doppler 등 일부 유료(단품 결제) 앱도 있으나, 대규모 iCloud 폴더에서의 검색·임포트 경험이 매끄럽지 못함
“빌더 모드”로 나아간 기술적 여정
- 직접 음악 플레이어 앱을 만들어야겠다고 결심함
- 요구 기능: iCloud 폴더 전체에 대한 빠른 풀텍스트 검색, 공식 음악 앱 수준의 음악 관리 기능(큐, 재생목록, 정렬 등)과 직관적 인터페이스
React Native 첫 시도
- Swift 경험상의 불편함(이전에는 async/await 미지원 등)으로 React Native/Expo를 선호함
- 오픈소스 템플릿 활용 등으로 UI 구현은 무난했으나, 파일 시스템(iCloud 폴더) 접근 및 동기화 처리에서 앱 크래시와 기능적 한계를 느꼈음
- iOS 샌드박스 정책상 명시적 권한 없이 외부 폴더 접근이 불가능함을 깨닫고 Swift로 전환함
SwiftUI 선택 및 이유
- SwiftUI의 선언적 UI 패러다임, 현대적 async/await 및 Swift Actor 지원 활용
-
UI와 데이터 로직 철저 분리로, 클린한 데이터 플로우 및 도메인 동시성 처리 구현
- LLM(OpenAI o1, DeepSeek 등) 활용 최적화 효과, 생성된 UI 코드의 의존성 최소화에 기여함
앱 아키텍처 및 데이터 모델
백엔드 스타일 논리 계층
-
웹/클라우드 기반 스타트업 개발 경험을 바탕으로, 논리계와 UI/ViewModel을 철저히 분리
-
도메인 레이어(Swift actors) 가 주요 비즈니스 로직(임포트, 검색, 큐 등)을 보유, 스레드 안전성 확보
- UI 업데이트는 ViewModel 통해 깔끔히 분할, 파일동기화·재생·UI 간 의존도 최소화로 유지보수성 향상
SQLite로 풀텍스트 검색 구현
- iOS 11 이상부터 별도 설정 없이 FTS5 지원 SQLite 사용 가능
-
외부 검색 인덱스/서버 필요 없이 빠른 검색 지원
- SQLite.swift 라이브러리로 일반 쿼리 처리, FTS 쿼리에는 직접 SQL 문 사용
FTS 테이블 구조
-
songs_fts: 곡의 artist, title, album, albumArtist 등 인덱싱
-
source_paths_fts: 파일 경로, 파일명 인덱싱
- 메인 테이블과 나란히 존재하며, UI에선 검색(READ) 전용 사용
- 인덱스 업데이트는 DB 트랜잭션으로 처리해 데이터 일관성 유지
퍼지(Fuzzy) 검색 및 랭킹
- 입력값 뒤에 와일드카드 자동 추가, BM25 기반 관련도 순 정렬
- 전체적으로, 네트워크 의존성 없는 예측 가능 데이터 구조와 강력한 로컬 검색 환경이 실현됨
iOS 파일 시스템 및 북마크(Bookmarks) 활용
- iOS는 macOS와 달리 security-scoped bookmarks를 지원하지 않아, 외부 파일 확장 접근 지속성 부족함
-
경로 정보만 저장되어 재접근 시 사용자가 다시 권한을 승인해야 함
- 해결책: 접근 허용 시점에 파일 자체를 앱 샌드박스로 사본 저장
- 백그라운드에서 자동 복사해 파일 인덱싱 속도 개선
- 기기 리부팅 후 외부 파일 직접 재생은 여전히 어렵지만, iOS의 파일 접근 제약이 심각함을 보여줌
AVFoundation 기반 재생 및 인터페이스 설계
-
AVFoundation 프레임워크와 AVURLAsset 사용해 오디오 파일 메타데이터 분석
- track number 등 일부 필드는 수동 파싱(ID3 태그 활용)
- 오디오 재생에는 AVAudioPlayer 사용, 컨트롤 센터 연동 위해 MPRemoteCommandCenter·Delegate 프로토콜 구현
개발 후 느낀 점 및 Apple 정책에 대한 고찰
불편했던 점
-
Xcode의 제약적 환경: SwiftUI 실시간 프리뷰는 발전적이나, VSCode·Flutter의 편의성에 미치지 못함
-
에디터 융통성 부족: Neovim, VSCode에서 Swift LSP 활용하려면 추가 설정 필요 및 완성도 낮음
-
일부 SDK 구석은 Objective-C 위주: 메타데이터 검색 등에서 현대 Swift 친화적 API 부족
-
iCloud 연동 디버깅 번거로움: SwiftUI 프리뷰에서 클라우드 기능 완전 구현 불가, 직접 목업 구성 필요
긍정적인 점
-
Async/await로 I/O 바운드 동시성 코드 작성이 현저히 수월해짐
-
풍부한 네이티브 라이브러리: 오픈소스 바인딩 한계에서 벗어나 더 다양한 기능 개발 가능
-
SwiftUI의 선언적 UI 설계: React 방식 강점과 높은 생산성 실감
결론: 개발이 더 쉬워져야 하지 않을까
- 1.5주 개발로 로컬/오프라인 음악 플레이어 목적 달성
- 실제론 앱 자체 배포에도 제한 존재: 개발자 인증서 없이 7일 후 사용 불가, 연간 $99 개발자 등록 필요
- EU DMA Act 이후에도 사이드로딩 완전 개방 아님, 개인·취미 개발자에겐 여전히 제약 지속
-
PWAs 역시 iOS에선 주요 API 미지원 등 제한(Web Bluetooth/USB/NFC, Background Sync 등)
-
AI로 개발 장벽은 낮아졌으나, iOS만은 인위적 규정으로 진입 장벽 높음
-
독립 개발자·사용자 권한 제한은 여전하며, iOS의 폐쇄성은 여전히 혁신에 장애 요인임