Josh Ramirez
← Field guide

Entry 08 of 23

Departed Summer 2025

the iPhone, offlineiOS appShipped
Three dark-mode iOS Music App screens side by side: a Music Library album grid, a Now Playing screen for Say My Name - Remix, and a Queue screen with an Up Next list
Library, player, queue — the app after the picnic-table sketch turned into Swift.

Departure

Davis Mountains, McDonald Observatory, no bars. Spotify opens to a sad face and asks if I'd like to log in. I have a free account, the MP3s are sitting in my Files app from years of scraping, and the iPhone has known how to decode audio since 2007 — somewhere in this stack the music should already be playing. So I opened Xcode in the camper and started a Swift app whose only job was to point AVAudioPlayer at a local file and press play.

Approach

4 tools

  • Swift
  • AVFoundation
  • MediaPlayer
  • MPNowPlaying

No internet at the campsite. No Spotify Premium. Audio files already on the phone. The app had to feel native enough that I would actually use it.

Field log

7 entries

  1. Aug 2025 — Davis Mountains

    Drove out to the McDonald Observatory dark-sky site. Zero LTE the whole valley. Starlink dish on the picnic table covered the laptop, but the phone in my pocket was on its own — and Spotify Free won't let you play your downloads without a check-in. The MP3s were sitting in the Files app, untouched.

  2. Day 1 — paper

    Sketched the whole app on one sheet of notebook paper. Five rectangular buttons, no icons, no styling. That was the spec.

    Hand-drawn paper wireframe of music app — five crude rectangular buttons labeled 'Play 1, Play 2, Play 3, Play 4, Auto Generated, Artists, ALL' under the title 'Music'
    Day 1 spec.
  3. First playback

    Pointed AVAudioPlayer at one bundled MP3 and called play(). Sound came out of the iPhone speaker with no router, no DNS, no account in the loop. The slide deck's 'problem' line was solved in about thirty lines of Swift.

  4. Library

    Replaced the paper buttons with a real Music Library — dark mode, square grid pulled from the file metadata. Mac DeMarco next to Debussy next to Alice DJ. Tap a cover and you drop straight into Now Playing with the right art and the right title.

    Dark-mode iPhone Music Library screen with a two-column grid of album tiles including Mac DeMarco, Debussy, Alice DJ, and Austin Farwell
    The paper boxes became a metadata-backed library.
  5. Controls

    Built the Now Playing view around 'Say My Name — Remix' as the test track. The center screen in the hero was the sanity check: artwork, title, artist, elapsed time, scrubber, transport controls, and queue button all backed by AVAudioPlayer state.

  6. Queue

    Up Next list backed by a plain array the player chews through in order. Tap a song from the library and it goes to the top; queued remixes line up underneath and roll forward when the current track ends.

  7. Lock screen

    Pushed the current track into MPNowPlayingInfoCenter and registered play / pause / next / previous on MPRemoteCommandCenter. Lock screen suddenly showed the cover and title, the AirPods squeeze worked, and CarPlay treated it like any other audio app.

From the gallery

3 figures

Composite of the iOS Music App showing the Music Library, Now Playing, and Queue screens in dark mode
The full app surface: library, player, queue.
Standalone Music Library screen with album covers and playlist durations
Local files, organized like a real library.
Original hand-drawn Music App sketch with Play buttons, Auto Generated, Artists, and All sections
The first version was just boxes and labels.

What I came back with

Local-file music library with playback, queue, and system controls.

Lesson from the terrain

When the platform's answer is 'subscribe or no music,' the iPhone underneath it is still a perfectly good audio computer — AVFoundation will play any file you point it at, and MPNowPlaying will hand that playback to the lock screen and the AirPods for free. Self-hosting your own software is mostly the willingness to write the thirty lines that the SaaS layer was charging rent for. The trip did not need Spotify; it needed a binary I owned.

Cross-links