Android and iOS apps¶
Android app¶
mobile/ is Nessie's Android app (and the start of its iOS app: see iOS app): a Capacitor shell
around your own server. On first launch it asks for the server's address, then opens it as a
browser would: the same app, from the same server, so it's up to date whenever the server is.
"Who's listening?" works at home, and a sign-in page (Authelia…) away: pages on the server's
domain (auth.example.com for audio.example.com) open in the app, and other links in the
browser. Tick the sign-in page's Remember me, or the app signs you out with its session.
Installing it: open Settings → Server on the phone, in its browser, and tap Download the Android app under About (shown when the server's image has the app: see Releases). The first time, Android asks to allow installing apps from the browser. Inside the app, About says the app's version, and when the server comes with a newer one, how to update.
- Change server: Settings → Server, at the top (only in the app), or on the "Can't reach Nessie" page that shows when the server doesn't answer.
- At home over
http://works (the app allows it), but without offline music, as in a browser (see HTTPS). - This device is the app's own player (
PlaybackService: Media3's ExoPlayer), and the app's output until you choose another: it plays on in the background and with the screen off, with the notification, lock screen, headset and Bluetooth buttons, and the phone's volume buttons for volume. It fetches with the web view's cookies, so a sign-in page's session works; when that runs out, the music pauses and the app goes through the sign-in page again. Songs it plays to the end count as plays, sent with when they ended if the app was asleep. - Downloads are kept by the app itself (
Downloads,DownloadsService: Media3's download manager), not the web view, so the app's own player plays them: offline it plays on in the background and with the screen locked, covers on the lock screen included. Downloads carry on in the background with a notification (Android asks once whether the app may show it), use the same sign-in cookies as streaming, work over plainhttp://at home too, and stay until you remove them. Settings → Offline shows their space and the phone's free space, and has Download over Wi-Fi only: on mobile data, downloads wait (the button says Waiting for Wi-Fi) and start by themselves on Wi-Fi. - Songs it plays are kept on the phone as they stream, as in a browser (up to 1 GB unless changed under Settings → Offline → Cache size limit, the least recently played making room), and the next few in the queue are downloaded ahead (Download ahead, 3 unless changed; not while the phone's Data Saver is on), so a patchy connection doesn't stop the music. A kept or downloaded song is checked with the server once a day, and fetched again if its file changed.
- Offline (the server can't be reached), the app's player plays on: downloaded and kept songs
play, and the rest are skipped. With a VPN such as Tailscale on and no network under it, the
phone still counts as online and requests just hang, so the player finds out itself: when a song
that isn't on the phone can't start and the server doesn't answer
/healtheither, it skips to one that is (about 20 seconds) and the app shows Offline. Downloads the web view kept before the app could keep its own are cleared once, with a note to download them again. - Android Auto: Nessie shows in the car with Downloads, Playlists, Mixes and
Recently added, and a search. Choosing something plays it on the phone's player, so the app
shows it as playing when you next open it. Voice works through the assistant: "play Weather for
Tennis on Nessie" plays the best match, "play music on Nessie" what you play most. Offline, only
Downloads shows, and search looks in them. The car can start the app without the page, so the
tree comes from the server (
/v1/apps/car, in the server's own release) with the web view's cookies. An app not installed from the Play Store doesn't show in Android Auto until you turn on its developer settings (Android Auto's settings → tap Version ten times → ⋮ → Developer settings → Unknown sources).
iOS app¶
mobile/ios is the same app for iPhone and iPad, in progress: it asks for the server, opens it,
and has Change server and the "Can't reach Nessie" page, as on Android
(mobile/ios/App/App/ShellPlugin.swift, MainViewController.swift). In the iOS app, About says
the app's version and never offers the Android app: iPhones get it through Apple (TestFlight).
- This device is the app's own player (
Playback.swift: AVFoundation'sAVQueuePlayer, throughPlayerPlugin.swift, with the same calls as on Android): it plays on in the background and with the screen locked, with the lock screen, Control Center and headphone buttons, and the phone's buttons for volume. It pauses for a call and carries on after, and pauses when headphones are unplugged or Bluetooth goes. It fetches with the web view's cookies, so a sign-in page's session works; when that runs out the music pauses and the app goes through the sign-in page again. Songs it plays to the end count as plays, sent with when they ended if the app was asleep. - A song that's gone or can't be played is skipped (three in a row stop); a network that's down is retried for about five minutes, as on Android.
- Downloads are kept by the app itself (
Downloads.swift,DownloadsPlugin.swift), as on Android: they download in the background (iOS carries on with the app suspended or quit, and wakes it when they're done), with the same sign-in cookies, over plainhttp://at home too, and stay until you remove them. Offline, the app's player plays them on with the screen locked, covers on the lock screen included. Settings → Offline has the same Space and Download over Wi-Fi only as on Android. - Songs it plays are kept on the phone (
PlayedSongs.swift, up to 1 GB unless changed, the least recently played making room), and the next few in the queue are fetched ahead (Download ahead; not in Low Data Mode). The song playing streams while a copy is fetched beside it, since iOS's player doesn't hand over what it streams. A kept or downloaded song is checked with the server once a day, and fetched again if its file changed. - Offline (the server can't be reached), the player plays on: songs on the phone play, the rest are skipped. With a VPN such as Tailscale on and no network under it, the player finds out itself, as on Android.
- Opening offline: the app keeps a copy of its server's web app (
KeptCopy.swift, brought up to date from/v1/apps/web-fileswhen the app starts or comes to the front: only what changed is fetched, and a new version replaces the last only once it's whole). When the server can't be reached, that copy opens instead of "Can't reach Nessie" (OfflineScheme.swiftserves it atnessie://offline/, covers from the downloads), on Downloads, with the theme and the rest the real page last handed over. The app asks the server every 15 seconds and whenever the network changes, and opens the real page again as soon as it answers; music playing carries on, and plays made meanwhile are sent then. A server from before/v1/apps/web-filesgets no copy. - CarPlay: Nessie shows in the car with Downloads (when there are any), Playlists,
Mixes and Recently added (
CarPlaySceneDelegate.swift,CarLibrary.swift), from the same/v1/apps/caras Android Auto. Choosing a song plays it, and what it's in, on the phone's player, with the car's Now Playing screen; the app shows it as playing when you next open it. Offline, only Downloads shows. Search and Siri come later. The app needs Apple's CarPlay audio entitlement (App.entitlements); it's on the App ID, so automatic signing picks it up.
A web view in an iOS app gets no service worker for a server the user chooses, so the web app's offline (the app opening offline, downloads kept by the service worker) doesn't work there: the iOS app keeps downloads, played songs and a copy of the web app itself, as above.