A standalone, watch-first podcast player for Wear OS by SJTech.
Import by QR, listen offline, and leave the phone behind.
WearPod by SJTech is a standalone Wear OS podcast app prototype built for round watches first.
It does not depend on a phone companion app. The current goal is simple: import feeds through a phone-assisted QR flow, browse episodes, play audio, download episodes offline, and keep the core listening loop usable on a small wearable screen.
| Home | Subscriptions | Podcast detail |
|---|---|---|
![]() |
![]() |
![]() |
| Player | Queue | Downloads |
|---|---|---|
![]() |
![]() |
![]() |
- Start a phone-assisted QR import session for RSS or OPML input on mobile
- Start a phone-assisted QR export session and download an OPML backup on mobile
- Manage subscriptions without a phone companion app
- Favorite subscriptions and surface them on the home screen
- Browse episode lists with filters for
All,Unplayed, andDownloaded - Stream audio with
Media3 - Download episodes for offline playback with
WorkManager - View download queue, failures, and completed offline episodes
- Configure download behavior:
- Wi-Fi only downloads
- auto-download latest
0-3episodes - background auto-download
- Run periodic background feed refresh every
6,12, or24hours - Control playback queue:
- previous / next episode
- switch within the current queue
- seek backward / forward
- cycle playback speed
- adjust media volume from player controls and hardware volume keys
- Use a sleep timer from the player for
15,30, or60minutes
WearPod is intentionally a watch-first client, not a podcast platform.
Current scope:
- standalone Wear OS app
- public RSS feeds
- lightweight on-watch library and playback
- phone-assisted import for awkward text entry
- offline listening on the watch
Out of scope for this iteration:
- phone sync
- cloud accounts
- podcast discovery backend
- private or paid feed authentication
The current app is organized around three root watch pages:
Home: continue listening, favorites, quick contextSubscriptions: import and manage subscribed feedsDownloads: queue, failures, offline library, and refresh settings
Secondary screens:
Phone importPodcast detailPlayerDownload & refresh settings
- Kotlin
- Jetpack Compose for Wear OS
- Media3
- WorkManager
- Coil 3
- Room for subscriptions, episodes, and favorites
- DataStore Preferences for playback memory, download settings, and sleep timer
- Android Studio with Wear OS support
- JDK 17
- Android SDK / build tools compatible with:
compileSdk = 36minSdk = 30targetSdk = 36
- A Wear OS emulator or physical watch
If the Gradle wrapper can download normally in your network environment:
./gradlew assembleDebug
./gradlew testDebugUnitTestIf wrapper downloads are blocked, use the system Gradle binary instead:
gradle assembleDebug --no-daemon
gradle testDebugUnitTest --no-daemonThe repository includes an Android workflow that builds an unsigned release APK:
- runs on
push,pull_request,workflow_dispatch, and GitHubrelease - uploads
app-release-unsigned.apkas a workflow artifact - attaches the same unsigned APK to the GitHub Release page when a release is published
adb devices
adb -s <device-id> install -r app/build/outputs/apk/debug/app-debug.apkadb -s <device-id> shell am start -n com.sjtech.wearpod/.MainActivityThe QR-based phone import flow depends on the lightweight relay in relay/.
cd relay
npm install
npm startFor emulator testing, the default local setup is:
- watch API base:
http://10.0.2.2:8787 - relay public URL:
http://localhost:8787
For a real deployment, point both the app and the relay to a public HTTPS URL:
./gradlew assembleDebug -PwearpodImportRelayApiBaseUrl=https://your-relay.example.com
PUBLIC_BASE_URL=https://your-relay.example.com npm startThe repo includes a reusable deployment script for Docker-based servers:
bash scripts/deploy-relay.shYou can also pin a specific Git ref or commit:
bash scripts/deploy-relay.sh 327d431d9a1469c588dbefd8ebae058c70e9884eUseful environment overrides:
PUBLIC_BASE_URL=https://wearpod.linsblog.cn \
HOST_BIND=127.0.0.1 \
PORT=8787 \
bash scripts/deploy-relay.sh mainThe project supports local-only release signing without committing secrets to git.
- Copy the template:
cp release-signing.properties.example release-signing.properties-
Fill in your real keystore path and passwords in
release-signing.properties. -
Build a signed release when you are ready:
./gradlew assembleReleaseThe real release-signing.properties file is ignored by git. You can also provide the same values through Gradle properties or environment variables:
WEARPOD_RELEASE_STORE_FILEWEARPOD_RELEASE_STORE_PASSWORDWEARPOD_RELEASE_KEY_ALIASWEARPOD_RELEASE_KEY_PASSWORD
DEBUG builds auto-import a sample feed if the app has no existing subscriptions yet:
https://feed.xyzfm.space/xpa79uvcn9lw
This is only meant to make emulator testing faster.
The relay keeps a short-lived import session in memory and lets the phone submit:
- one RSS URL, or
- one OPML file
The watch stays responsible for the actual feed fetch and import into local storage.
The app now uses a split persistence model:
Roomstores subscriptions, episodes, and favorite relationshipsDataStore Preferencesstores playback memory, download settings, and sleep timer state
On first launch after upgrading from older builds, WearPod automatically migrates the legacy wearpod_state.json file into the new storage model.
WearPod currently uses:
EpisodeDownloadWorkerfor per-episode downloadsSubscriptionRefreshWorkerfor periodic subscription refresh
Background refresh only runs when:
- it is enabled in settings
- there is at least one subscription
- the device has connectivity
- the battery is not low
app/src/main/java/com/sjtech/wearpod/ui- Compose screens, interaction logic, and watch-specific presentation
app/src/main/java/com/sjtech/wearpod/ui/components- reusable watch UI primitives
app/src/main/java/com/sjtech/wearpod/data- models, repository, store, and RSS parsing
app/src/main/java/com/sjtech/wearpod/playbackMediaSessionServiceand player gateway
app/src/main/java/com/sjtech/wearpod/download- offline download scheduling and workers
app/src/main/java/com/sjtech/wearpod/sync- periodic subscription refresh scheduling and worker
docs/plans- design notes and implementation planning artifacts
- Public RSS feeds only
- No authentication for private or paid feeds
- QR import currently depends on a separately running relay service
- No cloud sync across watch / phone / web
- Storage is now split across Room and DataStore, but schema migration coverage is still minimal beyond the initial legacy JSON import
- Audio output guidance for Bluetooth / unsuitable output still needs a more explicit UX
Verified locally with:
gradle assembleDebug --no-daemon
gradle testDebugUnitTest --no-daemonThis project is released under the MIT License.
The next meaningful steps are:
- Stabilize the existing OPML export flow
- Private / paid feed support
- Search
- Better audio output and Bluetooth guidance
- Stronger persistence and recovery behavior





