Music streaming app for Android compatible with Navidrome, Jellyfin and OpenSubsonic servers or a local library
183
stars
106
commits
TypeScript
primary language
Sep 13, 2026
updated
Music streaming app for Android compatible with Navidrome, Jellyfin and OpenSubsonic servers or a local library.
Presentation website · Get it on Google Play · Get it on Github
Wavio is now available on the Google Play Store 🎉 If you enjoy the app please leave a review on the Google Play Store to help us grow the community.
Two versions are available for 64bit (arm64-v8a) and 32bit (armeabi-v7a) architectures. If in doubt try arm64-v8a first. Simulator architectures (x86, x86_64) are not provided.
APK installs need an extra step to show up in Android Auto (see below), so the Play Store install is the recommended one.
| Channel | Latest version |
|---|---|
| Google Play Store | 1.2.0 |
| In review on Google Play | 1.3.0 |
| GitHub releases | 1.3.0 |
The Play Store version is usually a release or two behind GitHub. Every Play Store submission goes through Google's review process, which can usually take two weeks, whereas a GitHub release is published as soon as the APKs are built. If you want the newest features and fixes as early as possible, grab the APK from the releases page; if you'd rather have Android Auto working out of the box, stick with the Play Store.
Android Auto doesn't detect Wavio automatically if you installed the app via APK on Github, Android Auto detects only Play Store apps automatically. To see Wavio with a APK install on Android Auto :
Wavio is available in multiple languages thanks to the community. If you want to help translate the app, please join the Crowdin project and help us translate the app to your language.
If your language isn't listed, please open an issue to request it.
Currently supported languages: English, French, German, Italian, Spanish, Chinese, Russian.

This repository is a Bun workspace monorepo with two workspaces:
apps/mobile — the Expo mobile appapps/landing — the Astro marketing websiteA single bun install at the repo root installs both. Most scripts are exposed at the root as mobile:* / landing:* (which delegate to the relevant workspace), or you can run a workspace's own scripts with bun run --cwd apps/<workspace> <script>.
.bun-version)ANDROID_HOME (or ANDROID_SDK_ROOT) exported and platform-tools on your PATHYou do not need an NDK or CMake: the only C++ in the repo (TagLib, in apps/mobile/modules/audio-tagger) ships as prebuilt .so files committed under jniLibs/, and Gradle only packages them.
You also do not need a Sentry account to develop the app — Sentry is disabled in __DEV__ and only matters for release builds. An Expo account is optional too: it's needed for EAS builds and for the bun run mobile:start/android/ios/web scripts, but not for the bunx expo … workflow below. See Using your own Expo account.
bun install — from the repo root, not from apps/mobile. The root package.json owns patchedDependencies (patches for expo-audio, expo-font, expo-navigation-bar, lucide-react-native and zod) and bunfig.toml pins linker = "hoisted", both of which Metro and jest-expo depend on. Installing inside the workspace skips the patches and produces a layout Metro can't resolve.cp apps/mobile/.env.example apps/mobile/.env. This step is required for everyone, maintainers included — it is how the app gets its Subsonic API version and client name during local development (see Environment variables). .env is gitignored.bun run mobile:prebuild
apps/mobile/android/ and apps/mobile/ios/ are not tracked in git — they're generated from app.json and the config plugins in apps/mobile/plugins/ (Continuous Native Generation). To generate a single platform, run cd apps/mobile && bunx expo prebuild -p android; on macOS, follow an iOS prebuild with bunx pod-install.cd apps/mobile && DARK_MODE=media bunx expo run:android
The first Gradle build takes a while. This produces a debug dev-client APK — the app talks to the Metro bundler on your machine, so JS changes reload instantly and you never need to rebuild for a JS-only change.cd apps/mobile && DARK_MODE=media bunx expo start, then open Wavio on the device.DARK_MODE=media is read by the Gluestack/Tailwind setup at bundle time — keep it set or the theme resolves incorrectly.
Re-run prebuild after changing app.json or a config plugin — nothing else picks those changes up, and a JS-only change never needs it. It wipes and regenerates android/ and ios/, so never hand-edit them: native changes belong in a config plugin (apps/mobile/plugins/) or a local Expo module (apps/mobile/modules/, whose own android/ / ios/ folders are tracked source). eas build runs prebuild itself, so cloud builds always match the plugins.
expo run:androidprebuilds on its own whenandroid/is missing, so step 4 is technically optional — running it explicitly keeps config-plugin errors from getting buried in Gradle output. It needs no Expo account.
Why
bunx expoinstead ofbun run mobile:android? Themobile:start/mobile:android/mobile:ios/mobile:webscripts wrap the Expo CLI ineas env:exec --non-interactive development "…". That wrapper pulls the Taddy podcast credentials out of the EASdevelopmentenvironment, and it resolves against the Expo account and project declared inapps/mobile/app.json(owner: "jmercier"andextra.eas.projectId) — so it fails for anyone who isn't a member of that account, before Metro or Gradle ever start.That wrapper is a convenience, not a requirement: the Subsonic API version and client name come from your local
.enveither way, and podcasts can be configured by hand in Settings. Runningbunx expo …directly gives you a fully working app. If you'd rather have themobile:*scripts work too, see Using your own Expo account.Everything else (
mobile:lint,mobile:test,mobile:typecheck,mobile:prebuild) needs no Expo account.
Optional. Do this if you want the mobile:start / mobile:android / mobile:ios / mobile:web scripts to run, or if you plan to make EAS builds from your fork.
eas login (check with eas whoami)apps/mobile/app.json, change "owner" to your Expo username (or remove the field)apps/mobile, run eas init to create a project under your account — it rewrites extra.eas.projectIddevelopment environment variables the wrapper expects, if you want podcasts seeded automatically:
eas env:create --environment development --name EXPO_PUBLIC_TADDY_PODCASTS_API_USER_ID --value <your-id>
eas env:create --environment development --name EXPO_PUBLIC_TADDY_PODCASTS_API_KEY --value <your-key>
Skip this and the scripts still work — they just inject nothing extra.⚠️ Steps 2 and 3 modify apps/mobile/app.json, which is tracked. Don't commit those changes — revert with git checkout apps/mobile/app.json before opening a PR, or keep them out of your commits with git update-index --skip-worktree apps/mobile/app.json.
apps/mobile/.env.example lists every variable the app reads. For local development only the first two matter:
| Variable | Needed for | If missing |
|---|---|---|
EXPO_PUBLIC_OPENSUBSONIC_API_VERSION | Sent as v= on every Subsonic/Navidrome request | Requests go out with v=, and servers reject them with error 10 "Required parameter is missing" — login fails against any OpenSubsonic server |
EXPO_PUBLIC_CLIENT_NAME | Sent as c= on every Subsonic/Navidrome request | Same as above |
EXPO_PUBLIC_TADDY_PODCASTS_API_USER_ID / _KEY / _LANGUAGE / _COUNTRY | Seeds the Taddy podcast config | Podcasts simply need to be configured by hand in Settings; nothing else breaks |
SENTRY_AUTH_TOKEN | Sourcemap upload during release builds only | Nothing — Sentry is disabled in __DEV__ |
The values in .env.example are the correct defaults for the first two, so copying the file verbatim is enough to get a working app. Every EXPO_PUBLIC_* value is inlined into the JS bundle at build time, so none of them are secret in a shipped build.
How the same variables reach a release build is different, and worth knowing if you touch eas.json:
env block in apps/mobile/eas.json, so eas build supplies them. eas env:exec does not read those blocks — which is why a local .env is needed for development regardless of your EAS setup.SENTRY_AUTH_TOKEN live in EAS server-side environment variables (eas env:create, scoped per development / preview / production), and each eas.json profile names the environment it pulls from.Keep secrets out of .env — a local eas build --local reads both .env and EAS, so anything stray in .env ends up in a release bundle.
In order to test Android Auto, you need to :
adb forward tcp:5277 tcp:5277 and start the emulator with ~/Library/Android/sdk/extras/google/auto/desktop-head-unitUnknown sources in Android Auto's developer settings (⋮ menu > Developer settings > Unknown sources) if the app doesn't show up in the emulatoradb logcat -c && adb logcat ReactNativeJS:V CarAuto:V "*:S"Mostly functional, no carplay or widgets support yet. No plan yet to publish to the App Store.
adb logcat -c && adb logcat ReactNativeJS:V "*:S" for the real error, and watch the Metro terminal. A stale Metro cache is a common cause: restart with bunx expo start --clear. Shaking the device opens the dev menu, from which you can reload.apps/mobile/.env, so v= and c= go out empty on every Subsonic request (see Environment variables).eas env:exec errors, or "entity not authorized" — a mobile:start / mobile:android / mobile:ios / mobile:web script is resolving against an Expo project you're not a member of. Either use the bunx expo … commands from Getting started, or follow Using your own Expo account.gradlew: no such file or directory, or Gradle can't find the project — apps/mobile/android/ hasn't been generated yet, or a previous prebuild failed. Run bun run mobile:prebuild (the directory is gitignored, so a fresh clone never has it).bun install inside apps/mobile. Delete apps/mobile/node_modules and run bun install at the repo root.java -version resolves to JDK 17+ and that JAVA_HOME points at it.bun run mobile:doctor checks the project for common Expo issues.apps/landing)The landing page is a static Astro site (Tailwind v4, en/fr i18n), independent from the mobile app.
bun install (from the repo root, shared with the app)bun run landing:dev (defaults to localhost:4321)bun run landing:build (output to apps/landing/dist/)bun run landing:previewFor Astro CLI commands, run them inside the workspace: cd apps/landing && bun run astro ....
The mobile app has E2E tests that are powered by Maestro.
To run the tests, you need to have the Maestro CLI installed and need access to a iOS or Android simulator.
The test scenarios are defined in apps/mobile/maestro/flows. Each flow is a sequence of steps that are executed in order.
To run the tests, run maestro test apps/mobile/maestro/ from the repo root.
You can find more information about the test scenarios in the E2E tests README.
Run from the repo root:
bun run mobile:start: Start the app in development mode (⚠️ needs an Expo account)bun run mobile:android: Start the app in development mode on Android (⚠️ needs an Expo account)bun run mobile:ios: Start the app in development mode on iOS (⚠️ needs an Expo account)bun run mobile:web: Start the app in development mode with web support (⚠️ needs an Expo account)bun run mobile:prebuild: Prebuild the native development appbun run mobile:typecheck: Type-check the appbun run mobile:lint: Lint the codebasebun run mobile:lint:fix: Fix linting issuesbun run mobile:test: Run the test suitebun run landing:dev: Start the marketing site dev serverbun run landing:build: Build the marketing sitebun run landing:preview: Preview the built marketing sitebun run doctor (inside apps/mobile): Check the app for any potential issueseas build --profile preview --platform android (inside apps/mobile): Build the app for Android with the desired profile and platform (add --local to build locally)eas whoami: Check the current usereas login: Login to Expo⚠️ The four marked scripts are wrapped in eas env:exec against the Expo project declared in apps/mobile/app.json. Either point that project at your own account (Using your own Expo account), or skip them entirely and run cd apps/mobile && DARK_MODE=media bunx expo run:android / bunx expo start. See Getting started.
If you like the app and absolutely want to support its development, you can donate to the project on Ko-fi. I pledge to only use the funds to pay for the development of the app which means only spending it on subscriptions, hosting or hardware that directly benefits the project.
TypeScript
93.5%
Kotlin
2.9%
Swift
1.2%
Music streaming app for Android compatible with Navidrome, Jellyfin and OpenSubsonic servers or a local library
183
stars
106
commits
TypeScript
primary language
Sep 13, 2026
updated
Music streaming app for Android compatible with Navidrome, Jellyfin and OpenSubsonic servers or a local library.
Presentation website · Get it on Google Play · Get it on Github
Wavio is now available on the Google Play Store 🎉 If you enjoy the app please leave a review on the Google Play Store to help us grow the community.
Two versions are available for 64bit (arm64-v8a) and 32bit (armeabi-v7a) architectures. If in doubt try arm64-v8a first. Simulator architectures (x86, x86_64) are not provided.
APK installs need an extra step to show up in Android Auto (see below), so the Play Store install is the recommended one.
| Channel | Latest version |
|---|---|
| Google Play Store | 1.2.0 |
| In review on Google Play | 1.3.0 |
| GitHub releases | 1.3.0 |
The Play Store version is usually a release or two behind GitHub. Every Play Store submission goes through Google's review process, which can usually take two weeks, whereas a GitHub release is published as soon as the APKs are built. If you want the newest features and fixes as early as possible, grab the APK from the releases page; if you'd rather have Android Auto working out of the box, stick with the Play Store.
Android Auto doesn't detect Wavio automatically if you installed the app via APK on Github, Android Auto detects only Play Store apps automatically. To see Wavio with a APK install on Android Auto :
Wavio is available in multiple languages thanks to the community. If you want to help translate the app, please join the Crowdin project and help us translate the app to your language.
If your language isn't listed, please open an issue to request it.
Currently supported languages: English, French, German, Italian, Spanish, Chinese, Russian.

This repository is a Bun workspace monorepo with two workspaces:
apps/mobile — the Expo mobile appapps/landing — the Astro marketing websiteA single bun install at the repo root installs both. Most scripts are exposed at the root as mobile:* / landing:* (which delegate to the relevant workspace), or you can run a workspace's own scripts with bun run --cwd apps/<workspace> <script>.
.bun-version)ANDROID_HOME (or ANDROID_SDK_ROOT) exported and platform-tools on your PATHYou do not need an NDK or CMake: the only C++ in the repo (TagLib, in apps/mobile/modules/audio-tagger) ships as prebuilt .so files committed under jniLibs/, and Gradle only packages them.
You also do not need a Sentry account to develop the app — Sentry is disabled in __DEV__ and only matters for release builds. An Expo account is optional too: it's needed for EAS builds and for the bun run mobile:start/android/ios/web scripts, but not for the bunx expo … workflow below. See Using your own Expo account.
bun install — from the repo root, not from apps/mobile. The root package.json owns patchedDependencies (patches for expo-audio, expo-font, expo-navigation-bar, lucide-react-native and zod) and bunfig.toml pins linker = "hoisted", both of which Metro and jest-expo depend on. Installing inside the workspace skips the patches and produces a layout Metro can't resolve.cp apps/mobile/.env.example apps/mobile/.env. This step is required for everyone, maintainers included — it is how the app gets its Subsonic API version and client name during local development (see Environment variables). .env is gitignored.bun run mobile:prebuild
apps/mobile/android/ and apps/mobile/ios/ are not tracked in git — they're generated from app.json and the config plugins in apps/mobile/plugins/ (Continuous Native Generation). To generate a single platform, run cd apps/mobile && bunx expo prebuild -p android; on macOS, follow an iOS prebuild with bunx pod-install.cd apps/mobile && DARK_MODE=media bunx expo run:android
The first Gradle build takes a while. This produces a debug dev-client APK — the app talks to the Metro bundler on your machine, so JS changes reload instantly and you never need to rebuild for a JS-only change.cd apps/mobile && DARK_MODE=media bunx expo start, then open Wavio on the device.DARK_MODE=media is read by the Gluestack/Tailwind setup at bundle time — keep it set or the theme resolves incorrectly.
Re-run prebuild after changing app.json or a config plugin — nothing else picks those changes up, and a JS-only change never needs it. It wipes and regenerates android/ and ios/, so never hand-edit them: native changes belong in a config plugin (apps/mobile/plugins/) or a local Expo module (apps/mobile/modules/, whose own android/ / ios/ folders are tracked source). eas build runs prebuild itself, so cloud builds always match the plugins.
expo run:androidprebuilds on its own whenandroid/is missing, so step 4 is technically optional — running it explicitly keeps config-plugin errors from getting buried in Gradle output. It needs no Expo account.
Why
bunx expoinstead ofbun run mobile:android? Themobile:start/mobile:android/mobile:ios/mobile:webscripts wrap the Expo CLI ineas env:exec --non-interactive development "…". That wrapper pulls the Taddy podcast credentials out of the EASdevelopmentenvironment, and it resolves against the Expo account and project declared inapps/mobile/app.json(owner: "jmercier"andextra.eas.projectId) — so it fails for anyone who isn't a member of that account, before Metro or Gradle ever start.That wrapper is a convenience, not a requirement: the Subsonic API version and client name come from your local
.enveither way, and podcasts can be configured by hand in Settings. Runningbunx expo …directly gives you a fully working app. If you'd rather have themobile:*scripts work too, see Using your own Expo account.Everything else (
mobile:lint,mobile:test,mobile:typecheck,mobile:prebuild) needs no Expo account.
Optional. Do this if you want the mobile:start / mobile:android / mobile:ios / mobile:web scripts to run, or if you plan to make EAS builds from your fork.
eas login (check with eas whoami)apps/mobile/app.json, change "owner" to your Expo username (or remove the field)apps/mobile, run eas init to create a project under your account — it rewrites extra.eas.projectIddevelopment environment variables the wrapper expects, if you want podcasts seeded automatically:
eas env:create --environment development --name EXPO_PUBLIC_TADDY_PODCASTS_API_USER_ID --value <your-id>
eas env:create --environment development --name EXPO_PUBLIC_TADDY_PODCASTS_API_KEY --value <your-key>
Skip this and the scripts still work — they just inject nothing extra.⚠️ Steps 2 and 3 modify apps/mobile/app.json, which is tracked. Don't commit those changes — revert with git checkout apps/mobile/app.json before opening a PR, or keep them out of your commits with git update-index --skip-worktree apps/mobile/app.json.
apps/mobile/.env.example lists every variable the app reads. For local development only the first two matter:
| Variable | Needed for | If missing |
|---|---|---|
EXPO_PUBLIC_OPENSUBSONIC_API_VERSION | Sent as v= on every Subsonic/Navidrome request | Requests go out with v=, and servers reject them with error 10 "Required parameter is missing" — login fails against any OpenSubsonic server |
EXPO_PUBLIC_CLIENT_NAME | Sent as c= on every Subsonic/Navidrome request | Same as above |
EXPO_PUBLIC_TADDY_PODCASTS_API_USER_ID / _KEY / _LANGUAGE / _COUNTRY | Seeds the Taddy podcast config | Podcasts simply need to be configured by hand in Settings; nothing else breaks |
SENTRY_AUTH_TOKEN | Sourcemap upload during release builds only | Nothing — Sentry is disabled in __DEV__ |
The values in .env.example are the correct defaults for the first two, so copying the file verbatim is enough to get a working app. Every EXPO_PUBLIC_* value is inlined into the JS bundle at build time, so none of them are secret in a shipped build.
How the same variables reach a release build is different, and worth knowing if you touch eas.json:
env block in apps/mobile/eas.json, so eas build supplies them. eas env:exec does not read those blocks — which is why a local .env is needed for development regardless of your EAS setup.SENTRY_AUTH_TOKEN live in EAS server-side environment variables (eas env:create, scoped per development / preview / production), and each eas.json profile names the environment it pulls from.Keep secrets out of .env — a local eas build --local reads both .env and EAS, so anything stray in .env ends up in a release bundle.
In order to test Android Auto, you need to :
adb forward tcp:5277 tcp:5277 and start the emulator with ~/Library/Android/sdk/extras/google/auto/desktop-head-unitUnknown sources in Android Auto's developer settings (⋮ menu > Developer settings > Unknown sources) if the app doesn't show up in the emulatoradb logcat -c && adb logcat ReactNativeJS:V CarAuto:V "*:S"Mostly functional, no carplay or widgets support yet. No plan yet to publish to the App Store.
adb logcat -c && adb logcat ReactNativeJS:V "*:S" for the real error, and watch the Metro terminal. A stale Metro cache is a common cause: restart with bunx expo start --clear. Shaking the device opens the dev menu, from which you can reload.apps/mobile/.env, so v= and c= go out empty on every Subsonic request (see Environment variables).eas env:exec errors, or "entity not authorized" — a mobile:start / mobile:android / mobile:ios / mobile:web script is resolving against an Expo project you're not a member of. Either use the bunx expo … commands from Getting started, or follow Using your own Expo account.gradlew: no such file or directory, or Gradle can't find the project — apps/mobile/android/ hasn't been generated yet, or a previous prebuild failed. Run bun run mobile:prebuild (the directory is gitignored, so a fresh clone never has it).bun install inside apps/mobile. Delete apps/mobile/node_modules and run bun install at the repo root.java -version resolves to JDK 17+ and that JAVA_HOME points at it.bun run mobile:doctor checks the project for common Expo issues.apps/landing)The landing page is a static Astro site (Tailwind v4, en/fr i18n), independent from the mobile app.
bun install (from the repo root, shared with the app)bun run landing:dev (defaults to localhost:4321)bun run landing:build (output to apps/landing/dist/)bun run landing:previewFor Astro CLI commands, run them inside the workspace: cd apps/landing && bun run astro ....
The mobile app has E2E tests that are powered by Maestro.
To run the tests, you need to have the Maestro CLI installed and need access to a iOS or Android simulator.
The test scenarios are defined in apps/mobile/maestro/flows. Each flow is a sequence of steps that are executed in order.
To run the tests, run maestro test apps/mobile/maestro/ from the repo root.
You can find more information about the test scenarios in the E2E tests README.
Run from the repo root:
bun run mobile:start: Start the app in development mode (⚠️ needs an Expo account)bun run mobile:android: Start the app in development mode on Android (⚠️ needs an Expo account)bun run mobile:ios: Start the app in development mode on iOS (⚠️ needs an Expo account)bun run mobile:web: Start the app in development mode with web support (⚠️ needs an Expo account)bun run mobile:prebuild: Prebuild the native development appbun run mobile:typecheck: Type-check the appbun run mobile:lint: Lint the codebasebun run mobile:lint:fix: Fix linting issuesbun run mobile:test: Run the test suitebun run landing:dev: Start the marketing site dev serverbun run landing:build: Build the marketing sitebun run landing:preview: Preview the built marketing sitebun run doctor (inside apps/mobile): Check the app for any potential issueseas build --profile preview --platform android (inside apps/mobile): Build the app for Android with the desired profile and platform (add --local to build locally)eas whoami: Check the current usereas login: Login to Expo⚠️ The four marked scripts are wrapped in eas env:exec against the Expo project declared in apps/mobile/app.json. Either point that project at your own account (Using your own Expo account), or skip them entirely and run cd apps/mobile && DARK_MODE=media bunx expo run:android / bunx expo start. See Getting started.
If you like the app and absolutely want to support its development, you can donate to the project on Ko-fi. I pledge to only use the funds to pay for the development of the app which means only spending it on subscriptions, hosting or hardware that directly benefits the project.
TypeScript
93.5%
Kotlin
2.9%
Swift
1.2%