Phandroid — the Phanpy Mastodon web client, wrapped as a native Android app with Capacitor. Install via Obtainium; see the README.
  • JavaScript 80.6%
  • CSS 18.4%
  • Kotlin 0.6%
  • Shell 0.1%
  • HTML 0.1%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Phandroid Buildhost 59ff832488 fix: generate each version's F-Droid changelog from CHANGELOG.md
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.
2026-09-12 07:40:42 +00:00
.forgejo/workflows fix: generate each version's F-Droid changelog from CHANGELOG.md 2026-09-12 07:40:42 +00:00
.github feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
android chore(release): bump to 2.0.47 (auto, upstream merge) 2026-09-11 02:22:32 +00:00
assets feat(android): branded adaptive launcher icon and splash screens 2026-07-07 18:42:24 +02:00
compose feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
design feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
fastlane/metadata/android feat(dev): distinct launcher + F-Droid icon for the dev channel 2026-07-26 20:37:16 +00:00
fdroid fix: generate each version's F-Droid changelog from CHANGELOG.md 2026-09-12 07:40:42 +00:00
public feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
readme-assets feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
scripts Merge remote-tracking branch 'upstream/main' 2026-09-04 08:18:37 +00:00
src Merge remote-tracking branch 'upstream/main' 2026-09-11 02:17:29 +00:00
tests Possibly fix issues with playwright 2026-08-18 13:48:58 +08:00
.env fix: privacy policy, native localisation, pruning, watcher state, failure reporting 2026-08-22 16:10:13 +00:00
.env.production feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
.gitattributes fix: resolve package.json by computation instead of line-based merge 2026-08-16 21:14:43 +00:00
.gitignore chore: gitignore mail.env (never commit mail config) 2026-07-09 15:43:27 +02:00
.oxfmtrc.json feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
.release.env.example fix(dist): release-gitea.sh works on bash 3.2 + auto-loads token 2026-07-08 10:24:40 +02:00
capacitor.config.json release: 2.0.0 — rename applicationId to dev.umrath.android.phanpy; drop self-host refs 2026-07-11 07:23:33 +00:00
CHANGELOG.md chore(release): bump to 2.0.47 (auto, upstream merge) 2026-09-11 02:22:32 +00:00
CHANGELOG.phanpy.md feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
crowdin.yml feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
env.schema.json feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
i18n-volunteers.json feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
index.html feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
LICENSE Initial commit 2026-07-07 17:48:47 +02:00
lingui.config.js feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
package-lock.json chore(release): bump to 2.0.42 (auto, upstream merge) 2026-09-02 08:23:41 +00:00
package.json Merge remote-tracking branch 'upstream/main' 2026-09-02 08:18:31 +00:00
PHANDROID_CUSTOMIZATIONS.md fix: privacy policy, native localisation, pruning, watcher state, failure reporting 2026-08-22 16:10:13 +00:00
playwright.config.js feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
PRIVACY.MD fix: privacy policy, native localisation, pruning, watcher state, failure reporting 2026-08-22 16:10:13 +00:00
README.md Update README.md 2026-08-30 00:03:52 +00:00
rollbar.js security: drop inherited Phanpy Rollbar client token from rollbar.js 2026-07-23 16:41:43 +00:00
SECURITY.md feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00
vite.config.js Weird fix 2026-09-02 14:36:35 +08:00
wrangler.jsonc feat: import Phanpy web app as project base 2026-07-07 18:12:48 +02:00

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). See CHANGELOG.md and PHANDROID_CUSTOMIZATIONS.md for 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 the phandroid:// 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.

  1. Install Obtainium (from F-Droid or its GitHub releases).

  2. 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
    
  3. 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.

  1. In your F-Droid client open Settings → Repositories → Add repository and paste:

    https://fdroid.umrath.dev/repo?fingerprint=732DC12007C2873A07AA5E27DB47667F5A08E392C882E13C46D1480C7727CF19
    

    The fingerprint pins the repo to its signing key — keep it in the URL.

  2. 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.

  1. Install a UnifiedPush distributor, e.g. Sunup. Open it once and grant its permissions (notifications + battery-optimization exemption — it keeps the push connection alive).
  2. In Phandroid go to Settings → Push Notifications (beta), turn it on and choose which notification types you want.
  3. 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 1721 (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/
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