LocalWave is an offline-first music player for iOS that enables full control of your personal MP3 library without relying on Apple Music or iTunes Match. Built with SwiftUI and structured using a layered MVVM + Actor-based architecture, LocalWave prioritizes offline use and searchability. It was designed out of frustration with Apple's closed ecosystem and lack of decent support for self-hosted MP3 libraries. Link to the article
In 2025, Apple still restricts basic MP3 playback unless you pay for services like Apple Music or iTunes Match. LocalWave was built from scratch as a personal response to these limitations. It allows users to:
- Import MP3 files from iCloud or Files app using persistent bookmarks
- Build and search their own curated music libraries
- Avoid subscriptions or cloud lock-in
- Leverage native performance and Swift concurrency for a smooth user experience
- Artists / Albums / Songs Views: Browse, sort, and search with artwork and metadata
- Full-Text Search (FTS5): Search across title, artist, album, and path with SQLite-powered fuzzy matching
- Playlists: Create custom playlists with drag-and-drop reordering
- Library Sync: Import music folders recursively from iCloud using background sync services
- AVFoundation-Based Audio Playback: Full support for MP3s with lock screen controls
- Mini and Full Player UI: Seamless transitions and persistent playback
- Queue Management: Shuffle, repeat, and reorder tracks
- Background Playback: Continues playing while the app is backgrounded
- Persistent File Access via Security-Scoped Bookmarks: Stores references safely in SQLite
- Fallback File Copying: Copies MP3s into app container while bookmarks are still valid
- Multi-source Import: Add and merge multiple folder trees into a unified library
- Powered by SQLite FTS5: Fast and lightweight search without any cloud dependencies
- BM25 Ranking: Smart search results prioritization
- Async Upserts and Transaction Handling: Keeps search indexes reliable and performant
- Swift Actors: State-safe, concurrency-friendly domain logic
- MVVM Layering: Clear separation between View, ViewModel, Repository, and Domain layers
- SQLite with FTS5: Used instead of CoreData for tighter schema and query control
- iOS 15.0+
- Xcode 13.0+
- Swift 5.5+
- Clone the repository:
git clone https://github.com/nexo-tech/localwave.git- Open the project in Xcode:
cd localwave
open localwave.xcodeproj- Build and run the project (⌘R)
LocalWave follows a clean-layered MVVM architecture with a backend-style separation of logic:
- Models: Core types for songs, albums, metadata, and state
- Repositories: Async interfaces over SQLite using raw SQL and SQLite.swift
- Actors: Swift actors encapsulate business rules (search, import, playback queue)
- ViewModels: Subscribe to actors and provide bindable UI state
- Views: SwiftUI-based UI rendering from ViewModel output
- Services: Playback, file access, metadata parsing, remote control handling
localwave/
├── Sources/
│ ├── Features/
│ │ ├── Common/
│ │ ├── Library/
│ │ ├── Player/
│ │ └── Sync/
│ ├── Models/
│ ├── Repositories/
│ └── Services/
└── Tests/
| Domain | Actor / Repo | FTS Table | Indexed Columns |
|---|---|---|---|
| Library Songs | SQLiteSongRepository |
songs_fts |
artist, title, album, albumArtist |
| File Import Paths | SQLiteSourcePathSearchRepository |
source_paths_fts |
fullPath, fileName |
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Apple Developer Documentation (AVFoundation, SwiftUI, Combine)
SQLiteandSQLite.swiftAVAudioPlayerandMPRemoteCommandCenter- GitHub contributors for open-source ID3 parsing examples
Oleg Pustovit - @nexo_v1
Project Link: https://github.com/nexo-tech/localwave
