- JavaScript 80.6%
- CSS 18.4%
- Kotlin 0.6%
- Shell 0.1%
- HTML 0.1%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
F-Droid shows changelogs/<versionCode>.txt as a version's "What's New". The repo carried a committed 24.txt in both channels and both locales — versionCode 24 has not existed for a long time, so neither channel showed any release notes at all. A committed file cannot work here: the name has to follow the versionCode, and the text already lives in CHANGELOG.md. The promote step now writes it at index build time, inside the loop that already determines each channel's newest APK, taking the section for exactly that version from the branch belonging to that appId — main for .dev, prod otherwise. Both branches are fetched because the index is rebuilt for both apps out of one checkout. Ran the extraction against both channels' current CHANGELOG: dev 2.0.47 gives changelogs/69.txt, prod 2.0.18 gives changelogs/40.txt, both with the right content. Only en-US is written — CHANGELOG.md is English; the stale de-DE copies are removed rather than left pointing at nothing. |
||
| .forgejo/workflows | ||
| .github | ||
| android | ||
| assets | ||
| compose | ||
| design | ||
| fastlane/metadata/android | ||
| fdroid | ||
| public | ||
| readme-assets | ||
| scripts | ||
| src | ||
| tests | ||
| .env | ||
| .env.production | ||
| .gitattributes | ||
| .gitignore | ||
| .oxfmtrc.json | ||
| .release.env.example | ||
| capacitor.config.json | ||
| CHANGELOG.md | ||
| CHANGELOG.phanpy.md | ||
| crowdin.yml | ||
| env.schema.json | ||
| i18n-volunteers.json | ||
| index.html | ||
| LICENSE | ||
| lingui.config.js | ||
| package-lock.json | ||
| package.json | ||
| PHANDROID_CUSTOMIZATIONS.md | ||
| playwright.config.js | ||
| PRIVACY.MD | ||
| README.md | ||
| rollbar.js | ||
| SECURITY.md | ||
| vite.config.js | ||
| wrangler.jsonc | ||
Phandroid
This is a fork of Phanpy, with the goal of making it installable as an Android app.
It uses Capacitor to wrap the Phanpy web app into a native Android app — the same approach iPhanpy takes for iOS. Rather than reimplementing the UI natively, Phandroid ships the proven Phanpy web client inside an Android WebView shell and adds a thin, well-isolated layer of Android-specific tweaks (deep-link OAuth, native camera, in-app browser, hardware back button, edge-to-edge insets).
Built with LLM: this Android port — the Capacitor integration, the Android-specific override layer and the surrounding tooling — was created with the assistance of a large language model.
Status: released and installable from the self-hosted F-Droid repository at
fdroid.umrath.dev— works with F-Droid clients and Obtainium (see Installation). Supports OAuth login, native camera, an in-app browser, an Android share target, edge-to-edge UI and optional FOSS push (UnifiedPush). SeeCHANGELOG.mdandPHANDROID_CUSTOMIZATIONS.mdfor details.
Channels
Phandroid ships as two side-by-side apps, each tracking a different Phanpy branch. Install either — or both; they don't conflict (separate app id, data and OAuth scheme).
| Phandroid (stable) | Phandroid Dev (bleeding) | |
|---|---|---|
| applicationId | dev.umrath.android.phanpy |
dev.umrath.android.phanpy.dev |
| OAuth scheme | phandroid:// |
phandroiddev:// |
| tracks | Phanpy production |
Phanpy main |
| updates | curated releases — F-Droid repo / Obtainium | automatic, every upstream change — F-Droid repo / Obtainium |
Start with Phandroid. Phandroid Dev sees new Phanpy changes sooner but may break more often; it installs next to the stable app with its own accounts and settings.
Installation
⚠️ Upgrading from a pre-2.0.0 build? Reinstall required. Version 2.0.0 changes the app package id to
dev.umrath.android.phanpy. Android treats the new package as a different app, so it cannot update in place: uninstall the old Phandroid, then install this one from the F-Droid repository below. Logged-in accounts, settings and push registration do not transfer and must be set up again (the signing key and thephandroid://login are unchanged). If you added the app in Obtainium from the old source, remove it there and re-add it from the F-Droid repository below.
Phandroid is distributed as a signed APK — not on the Play Store.
Via Obtainium (recommended — auto-updates)
-
Install Obtainium (from F-Droid or its GitHub releases).
-
In Obtainium tap Add App, choose the source type F-Droid Third-Party Repo, and paste the URL for the channel you want:
https://fdroid.umrath.dev/repo?appId=dev.umrath.android.phanpy -
Tap Add, then Install — this gives you the stable Phandroid, updated automatically.
To follow Phandroid Dev (instead of, or alongside, the stable app), add a second app the same way with:
https://fdroid.umrath.dev/repo?appId=dev.umrath.android.phanpy.dev
The ?appId= in the URL selects the channel — no further options needed. Phandroid Dev installs
alongside the stable app as a separate package.
Via the F-Droid repo (auto-updates)
Add the self-hosted F-Droid repository once, then install Phandroid from it — a compatible client (the F-Droid app, Droid-ify or Neo Store) then checks it for updates automatically.
-
In your F-Droid client open Settings → Repositories → Add repository and paste:
https://fdroid.umrath.dev/repo?fingerprint=732DC12007C2873A07AA5E27DB47667F5A08E392C882E13C46D1480C7727CF19The
fingerprintpins the repo to its signing key — keep it in the URL. -
Refresh the repo — it lists both apps: Phandroid (stable) and Phandroid Dev (bleeding). Install whichever you want, or both side by side.
All APKs are signed with the developer's own key, so you can move between the F-Droid client, Obtainium and a sideloaded APK without reinstalling.
Direct APK (sideload)
Download the latest phandroid-vX.Y.Z.apk (the stable Phandroid) from the
releases page and open it to
install (allow "install unknown apps" for your browser / file manager if prompted).
The …-vX.Y.Z-dev.apk releases are Phandroid Dev — a separate app, not an update to
the stable one.
Push notifications (optional, FOSS — no Google)
Phandroid uses UnifiedPush: encrypted Web Push, decrypted on-device, with no Google/FCM.
- Install a UnifiedPush distributor, e.g. Sunup. Open it once and grant its permissions (notifications + battery-optimization exemption — it keeps the push connection alive).
- In Phandroid go to Settings → Push Notifications (beta), turn it on and choose which notification types you want.
- Allow the two prompts Phandroid then shows: the notification permission and the battery-optimization exemption (so push keeps working reliably).
Building
Phandroid is a Capacitor app: the web client is built with Vite, then wrapped by the
native Android project under android/.
Prerequisites
- Node.js 22+ and npm 10.x
- Android Studio with an Android SDK (platform android-35 and build-tools 35) — required to compile and run the APK
- A JDK 17–21 (Android Studio bundles a suitable JDK; JDK 21 is known to work)
1. Install and build the web app
npm install
npm run build # outputs to dist/
2a. Open in Android Studio (recommended)
npx cap sync android
npx cap open android
Then run the app on an emulator or a connected device from Android Studio.
2b. Or build a debug APK from the command line
Point Gradle at your SDK by creating android/local.properties with
sdk.dir=/absolute/path/to/Android/sdk, then:
npx cap sync android
JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" \
./android/gradlew -p android :app:assembleDebug
The APK is written to android/app/build/outputs/apk/debug/app-debug.apk.
Live reload during development
npx cap run android --livereload --external
Regenerating the launcher icon / splash
npx capacitor-assets generate --android
(reads assets/logo.png; the adaptive icon background colour is set in
android/app/src/main/res/values/ic_launcher_background.xml).
Credits
- Phanpy by @cheeaun — the web client Phandroid is built on.
- iPhanpy by @matfantinel — the iOS fork this approach is modeled after.