Skimmable phased plan for getting AniTrack onto Android for personal sideload use (no Play Store, no official F-Droid). Written for both the maintainer and as working context for AI-assisted implementation. Covers: desktop v3 parity as a mechanical step (main.go, runtime call mapping, wailsjs import rewrite), per-file Android storage shims (keyring on desktop vs EncryptedSharedPreferences via Android.Secure*), the localhost :6734 to anitrack:// deep-link OAuth redesign with per-provider dashboard changes, and the sideload run/ package commands plus Obtainium updates. Includes guardrails: small diffs, per-service file ownership, build-tagged platform files only, runnable check per phase, and open decisions (first provider, desktop parallel builds, redirect URI registration).
4.7 KiB
AniTrack → Wails v3 + Android plan
Goal: run this same app on my Android phone for personal use. Sideload the APK. No Play Store. No official F-Droid.
Non-goals: no rewrite of AniList / MAL / Simkl logic. No iOS. No store releases.
Big picture (3 steps)
- Desktop parity — get v3 building and acting like v2 on Linux.
- Android storage — swap where tokens are saved on Android only.
- Android login — replace the localhost login callback with a deep link.
Each step must run before moving on. If a step fails, stay on the previous one.
Step 0 — Done on main (already in this branch)
Fixed ignored errors in the 3 login files. Same wallet (ServiceName: AniTrack), same keys, per-file helpers:
AniListUserFunctions.go:aniRingReady()+aniRingSet(),keyring.Openerror logged,Seterrors logged with key name, badExpiresInlogged instead of silently kept.MALUserFunctions.go:malRingReady()+malRingSet(), same treatment, including refresh-token saves.SimklUserFunctions.go:simklRingReady()+simklRingSet(), same treatment.- Logouts still clear in-memory JWT even if storage is missing. No more nil-pointer panic when storage fails.
Step 1 — Desktop v3 parity (mechanical, no logic changes)
What changes and nothing else:
main.go:wails.Run(options.App{Bind: app})→application.New(Services: [app])+Window.New().app.go: move the 4 runtime calls to v3 equivalents —WindowSetTitle,WindowUnminimise/Show,EventsEmit,MessageDialog.- Go login files:
BrowserOpenURLandMessageDialogimports change fromwails/v2/pkg/runtimeto v3. Logic stays. - Frontend (11 files import
wailsjs/go/main/App, 2 importwailsjs/runtime): regenerate withwails3 generate bindings, script-replace the import paths. No Svelte rewrites. wails.json→ v3Taskfile + build/config.yml.Makefilewails build→wails3 task build.
Check: wails3 doctor, then desktop app logs in/out of all 3 services exactly like v2.
Step 2 — Android token storage (per-file shims)
Why: 99designs/keyring is desktop-only (macOS Keychain / WinCred / Linux Secret Service). No Android backend. On Android Open returns “no backend”.
Keep your organization: one file per service, same function names. Only the helper body changes by platform:
- Desktop files (
//go:build !android): keep callingkeyringviaaniRingSet / malRingSet / simklRingSet. - Android files (
//go:build android): same helper names, but callapplication.Android.SecureSet / SecureGet / SecureDelete(backed by EncryptedSharedPreferences). - Keys stay the same strings (
anilistAccessToken,MyAnimeListRefreshToken,SimklScope, …).
Check: GOOS=android compiles; login persists after app restart on emulator.
Step 3 — Android login callback (the one redesign)
Why: today each login opens the browser then listens on http://localhost:6734/callback (AniList:77, MAL:127, Simkl:71). Android WebView serves assets in-process — no localhost server, no open ports.
New flow per service (same order, different plumbing):
- App opens system browser to AniList / MAL / Simkl authorize URL.
- Provider redirects to
anitrack://callback?code=...instead ofhttp://localhost:6734/callback. - Android activity receives the deep link, hands
codeto the existingget*AuthorizationToken()function. - Rest is unchanged: save with
*RingSet(), same in-memory JWT.
Requires: add anitrack://callback redirect URI in each provider dashboard (AniList, MAL, Simkl), add intent-filter in build/android, keep desktop on localhost.
Start with ONE provider (suggest AniList) to prove the pattern, then copy to the other two.
Step 4 — Run it on my phone
Need: JDK 21, Android SDK 35 + NDK 26.3.x, ANDROID_HOME set. wails3 doctor confirms.
wails3 task android:run # emulator
wails3 task android:run:device # my phone via adb, debug APK
wails3 task android:package # release APK I sideload manually
Updates: drop APKs in GitHub Releases, point Obtainium at it. No stores.
Rules for AI doing this work
- Small diffs, one step at a time. Never rewrite domain logic to “clean it up”.
AniList*stays inAniListUserFunctions.go, MAL in its file, Simkl in its file.- New platform code goes in new
//go:buildfiles, not edits to shared logic. - Every step ends with a runnable check (see “Check” lines). Stop if it fails.
- Go stays plain Go: services are thin facades over existing funcs. No frameworks, no inheritance.
Open decisions (mine)
- First Android login: AniList only, or all 3 day one?
- Keep desktop building in parallel on this branch?
- New
anitrack://callbackURIs registered yet in the 3 dashboards?