Page MenuHomePhabricator

[Cashtab] Use capacitor to build an android app
ClosedPublic

Authored by bytesofman on Aug 13 2025, 22:08.

Details

Reviewers
Fabien
Group Reviewers
Restricted Project
Commits
rABC3f9369b96513: [Cashtab] Use capacitor to build an android app
Summary

Extend storage API to also handle android capacitor storage. Init capacitor app with android.

This code is mostly generated, but there are some manual edits in the android/ dir

  1. Camera permissions in the manifest
  2. main activity file is customized so the view is not edge-to-edge, i.e. we keep below the status bar

I am assuming the defaults in the generated .gitignores in the android directory are sensible. It seems like we do need a lot of these files in the repo as they could be expected to change, e.g. the camera permissions in the manifest, the main activity file, the various asset files used for splash screens and logos.

Going forward, changes would not be expected to impact so many files.

Note on storage
Originally I looked at the Preferences API, which is good for simple key value storage. However it is not recommended for a lot of storage (i.e. not really more than 1 mb).

Cashtab storage is simple key value. However with token caching, transaction history, and the ability to create an unlimited number of wallets, it could easily exceed 1mb. So, I refactored to use sqlite.

Sqlite is ... overkill for Cashtab's key value storage. But it is not expected to slow down the app at larger sizes in the way that Preferences could. Going forward...well sqlite is just way better than key value storage. Could make the app way better, store all tx history, better queries, etc. Apparently there are some ways to use sqlite in a webapp too, using wasm libs. But this kind of optimization would be for another time.

For now, we use key value store so that there is no difference in how storage is written / accessed between any supported platforms.

Test Plan

./start-android.sh

Need android studio and a lot of patience to get that working. But if everything is set up, then plugging your android phone into your laptop with usb debug enabled and running, this command should pull up the app. camera scan should work, app should look same as the webapp. can check logs (another android studio exercise but doable) to confirm it is on android storage.

Known issues

  1. The faucet claims do not work (recaptcha only works for cashtab.com)
  2. May see a splash screen before qr scanner loads
  3. Some style issues, screen width issues, android vs web styling

I think it's worth landing this now. Those issues can be cleaned up in the time it will take to get an approved Play Store account. And, even with the issues, I think the app would be worth publishing as-is.

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

remove no newline from non-icon files, rebase for camera

remove newline from xml assets, update launcher background to cashtab bg primary

bytesofman edited the test plan for this revision. (Show Details)

removing unused dep, backing out unused status bar fix

use sqlite instead of preferences for android storage

lint, remove bad hardcoded estimates

remove unused method in android adapter

bytesofman edited the summary of this revision. (Show Details)
bytesofman edited the test plan for this revision. (Show Details)
Fabien requested changes to this revision.Aug 15 2025, 20:46
Fabien added a subscriber: Fabien.
Fabien added inline comments.
cashtab/android/.idea/compiler.xml
4 ↗(On Diff #55269)

Note to reviewers: this is supporting about 99.8% of the devices according to https://apilevels.com/

cashtab/android/app/capacitor.build.gradle
12 ↗(On Diff #55269)

at some point we should refactor the storage so keys are stored in some secure storage/keystore

cashtab/android/app/proguard-rules.pro
21 ↗(On Diff #55269)

This can probably be removed

cashtab/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
26 ↗(On Diff #55269)

this can be removed

cashtab/android/app/src/main/java/cash/bitcoinabc/cashtab/MainActivity.java
1 ↗(On Diff #55269)

was meant to be ecash.bitcoinabc.cashtab ?

cashtab/android/app/src/main/res/drawable-land-hdpi/splash.png
1 ↗(On Diff #55269)

Do we need these capacitor images ? If yes can they be replaced with something more appropriated ?

cashtab/android/app/src/main/res/values/strings.xml
5 ↗(On Diff #55269)

ditto

cashtab/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
18 ↗(On Diff #55269)

remove

cashtab/android/gradlew.bat
94 ↗(On Diff #55269)

remove

cashtab/android/variables.gradle
2 ↗(On Diff #55269)

weird, it's 21 everywhere but here

This revision now requires changes to proceed.Aug 15 2025, 20:46

adjusted according to feedback

  • note the appId has changed, so we do not expect the same storage from before. If you ran the apk before, expect now to NOT have those wallets
  • I think the secure storage mod should be explored in its own diff, already a lot to review here just with the android stuff + storage identical. the migration could be easy but also we don't really have to migrate before we publish, and might take some time to publish.
cashtab/android/.idea/compiler.xml
4 ↗(On Diff #55269)

Note that this was not intentionally selected, capacitor default. So it could be changed but probably no reason to do this in the init diff.

cashtab/android/app/capacitor.build.gradle
12 ↗(On Diff #55269)

I'll take a look to see if this is reasonable in this MVP (i.e. can it be done only in the android adaptor), because it would be nice to avoid this migration.

In the future, though,

  • Should use available sqlite wasm libs for web and extension
  • Cashtab should be refactored to use sqlite storage instead of simple key value storage

In this way we could store tx history with comments, have faster queries, cache things more easily, and also keep a standard syntax across platforms.

Update: i got into this implementation...seems reasonable but imo it should be its own diff. Doing a migration for only alpha app users (or not migrating at all) is reasonable, and adding this unique storage configuration only in the android adaptor is a complication unique to the other logic in this diff.

cashtab/android/app/src/main/java/cash/bitcoinabc/cashtab/MainActivity.java
1 ↗(On Diff #55269)

looking into this, apparently the usual structure here is

com.company.appname .. i.e. "reverse domain name convention"

so for this, options would be

cash.e.cashtab
org.bitcoinabc.cashtab
com.cashtab.cashtab

...hm

probably "org.bitcoinabc.cashtab" is the best, esp since the publisher will probably be bitcoinabc

lmk thoughts on something else.

cashtab/android/app/src/main/res/drawable-land-hdpi/splash.png
1 ↗(On Diff #55269)

k more android TIL here

android 12+ generates splash screens from launcher icons

previously they used to be their own thing

updated using custom branding and matching these sizes

cashtab/android/variables.gradle
2 ↗(On Diff #55269)

some AI asking checks

apparently this is the supported android API level (23)

the 21 refers to the version of java used to compile the code

so .. 97.6% of devices instead of 99.8

bytesofman marked 5 inline comments as done.
bytesofman edited the summary of this revision. (Show Details)
bytesofman edited the test plan for this revision. (Show Details)

rebase, update splash screens, new app id, remove empty tests and some unused boilerplate

Fabien requested changes to this revision.Aug 18 2025, 20:23
Fabien added inline comments.
cashtab/android/.idea/misc.xml
5 ↗(On Diff #55277)

Macro newlinebernie:

cashtab/android/gradlew.bat
92 ↗(On Diff #55277)

Actually you can remove the whole file, we don't care building on windows and I'm sure it's not been tested

This revision now requires changes to proceed.Aug 18 2025, 20:23
bytesofman marked an inline comment as done.

lose the bat, newline

bytesofman added inline comments.
cashtab/android/gradlew.bat
92 ↗(On Diff #55277)

🎯

This revision is now accepted and ready to land.Aug 18 2025, 21:44
This revision was automatically updated to reflect the committed changes.
bytesofman marked an inline comment as done.