<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/static/coinos.apk, branch master</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=master</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-10-13T06:51:32Z</updated>
<entry>
<title>Android 1.14 (code 15) APK: UnifiedPush only without Play Services, built and signed on lap from 90bc4d3 (76:64:83:AB…). sha256 58a5c4787efbb52d3b34924e51ede844c3b17d8e20b5fc6524e24fd59f5bdfc1.</title>
<updated>2026-10-13T06:51:32Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2026-10-13T06:51:32Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=cd058495e11d76bb5afe4fe85b5131adaa387ca1'/>
<id>urn:sha1:cd058495e11d76bb5afe4fe85b5131adaa387ca1</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
</content>
</entry>
<entry>
<title>Android 1.13 (code 14) APK: sticky-immersive, built and signed on lap from bcf5f54 (the key assetlinks.json names: 76:64:83:AB…). sha256 63dac2e8b5b6b3d2d4b1f0fe4d73daa3c4c42b23bd11c81ba0d47da483efa26c.</title>
<updated>2026-10-13T06:29:31Z</updated>
<author>
<name>Adam Soltys</name>
<email>asoltys@gmail.com</email>
</author>
<published>2026-10-13T06:29:31Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=4db2b77bd249e365fc4a4f1ba22311feb60ac294'/>
<id>urn:sha1:4db2b77bd249e365fc4a4f1ba22311feb60ac294</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
</content>
</entry>
<entry>
<title>Android 1.11 (code 12): 1.9's per-theme system-bar colours, rebuilt to sit above a 1.10 test build. The navigation buttons stay white on white on Android 17 / Chrome 154 whatever the app asks for: the TWA's Custom Tab window ignores the navigation-bar colour (plain Chrome tabs are fine), reported to Chromium</title>
<updated>2026-10-09T16:30:07Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-10-09T16:30:07Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=4d0fc6bf4fd0494df1405899f51f9abbf5ab34a1'/>
<id>urn:sha1:4d0fc6bf4fd0494df1405899f51f9abbf5ab34a1</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MgAFLnkF7KrdhuyCLMNgtL
</content>
</entry>
<entry>
<title>The Android app's system bars follow the system theme, and the page's theme colour follows the app's.</title>
<updated>2026-09-28T06:58:44Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-28T06:58:44Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=318fef4880373fe5c12c366cd8b1c322771714e6'/>
<id>urn:sha1:318fef4880373fe5c12c366cd8b1c322771714e6</id>
<content type='text'>
One dark colour for both bars gave white navigation icons over a light page
under gesture navigation. The wrapper (1.9, versionCode 10) now uses the
page background in light mode and the dark theme colour in dark mode, for
the status bar and the navigation bar alike. The page updates its
theme-color meta when its own theme is applied, so a PWA's status bar and
the wrapper's follow the same switch.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
</content>
</entry>
<entry>
<title>A second Android build that can wake the wallet, because it holds it.</title>
<updated>2026-09-12T17:32:01Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-12T17:32:01Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=60e755286302647d93bc82070c61fcf93ddbc3b9'/>
<id>urn:sha1:60e755286302647d93bc82070c61fcf93ddbc3b9</id>
<content type='text'>
The TWA can't. Chrome renders the site, so the wallet's keys live in Chrome's
storage for its own origin, and nothing outside Chrome can reach them — a
UnifiedPush message could raise a notification and no more. On a phone with
Google Play Services none of this matters; without it, background answering
was simply unavailable.

So: a second flavour, io.coinos.webview, "Coinos (UnifiedPush)". The wallet
runs in a WebView this app owns, which means a push can start it off-screen
and let it answer for itself. WakeService loads it with ?wake=&lt;payload&gt; into
the same storage the visible app uses, the page subscribes and answers
whatever the payload was about, then calls CoinosHost.done() so the service
stops — capped at 25 seconds from the page and 30 from the service, because
nothing here is allowed to sit in the background costing battery. Its
foreground notification says what it's doing rather than apologising for
existing.

The WebView carries what the wallet actually needs: DOM storage and
IndexedDB, the camera for the QR scanner (granted only once Android has
granted it to us), a file chooser for attaching pictures, and links to
anywhere but coinos.io handed to a real browser.

The trade is named in the code and worth naming here: a separate app is a
separate wallet. Its storage is its own, so signing in there is signing in
again. That's why this is a second build rather than a replacement — the TWA
is untouched, still the better browser for anyone whose phone has push.

The shared push receiver now asks the system for whatever front door this
build has, and asks a per-flavour Wake class whether the wallet can be woken
at all — no flavour checks in the middle of it. Both APKs build and ship:
coinos.apk as before, coinos-unifiedpush.apk beside it.

Co-Authored-By: Claude Opus 5 (1M context) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
</content>
</entry>
<entry>
<title>UnifiedPush: reach a phone that has no Google in it.</title>
<updated>2026-09-12T17:05:10Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-12T17:05:10Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=a846211262f37238c001e5210938749294f8db6a'/>
<id>urn:sha1:a846211262f37238c001e5210938749294f8db6a</id>
<content type='text'>
Web push on Android is Firebase's, so a phone without Google Play Services —
GrapheneOS, CalyxOS, any de-Googled Android — cannot be woken by a web app at
all. UnifiedPush is the way that doesn't involve Google: the user runs a
distributor (ntfy and friends), apps ask it for an endpoint, and whoever
wants to reach the device POSTs to that endpoint.

THE WRAPPER speaks the protocol directly — four broadcasts each way, so it
pulls in no library; an APK this small has no business growing a Kotlin
runtime for eight intents. It asks the distributor on every launch (the call
is idempotent, and it's how a distributor installed later gets noticed),
raises a notification when a message arrives, and acknowledges it so the
distributor stops resending.

THE ENDPOINT reaches the web app on the launch URL as ?up=, the same road
payment intents already travel — because the distributor talks to the app and
only the web app knows which pubkeys are worth watching. It's registered with
the notifier in place of a browser subscription, for notifications and for
NWC alike, and needs neither permission nor push service.

THE NOTIFIER sends to either kind: one deliver() that POSTs the payload to a
UnifiedPush endpoint, or hands it to web-push as before. Same payloads, same
404/410 pruning. The endpoint is the only secret there, so it's never logged
in full.

Verified: a POST to a live ntfy endpoint delivers the payload byte for byte,
so the app parses exactly what the notifier sent; the APK builds, carries the
receiver, and is signed with the certificate assetlinks already pins (v1.6).
tools/unifiedpush-test.js drives a browser with no push service and checks
the endpoint is taken off the URL, kept, and registered.

Honest about the limit: a UnifiedPush message wakes the ANDROID app, not
Chrome's service worker, and the wallet's keys live in the browser's storage
where nothing here can reach them. So a zap request arrives as a notification
you tap, and the wallet answers when it opens — one tap instead of none.
Automatic answering while closed still needs a browser with a push service.

Co-Authored-By: Claude Opus 5 (1M context) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
</content>
</entry>
<entry>
<title>Android APK: fix the white status bar (TWA had no system-bar color set).</title>
<updated>2026-09-07T04:10:39Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-07T04:10:39Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=050c944036c32200618f78f1924c81b8c881bb91'/>
<id>urn:sha1:050c944036c32200618f78f1924c81b8c881bb91</id>
<content type='text'>
androidbrowserhelper defaults the TWA status/navigation bars to white when no color is declared — the PWA doesn't hit this because it uses the manifest theme_color. Added STATUS_BAR_COLOR / NAVIGATION_BAR_COLOR meta-data (light + dark variants) pointing at new color resources set to the PWA's theme_color #15171a, so the top bar matches the dark app chrome. Bumped to versionCode 6 / versionName 1.5 and rebuilt static/coinos.apk (meta-data verified present via aapt).

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>Android wrapper v1.4: the launcher icon now truly matches the PWA. Two discoveries via on-device screenshot comparison: (1) Chrome's maskable handling ZOOMS the PWA icon so far that the logo's outer ring is cropped away entirely — the PWA tile is actually the middle ring + half-moon only, so the adaptive foreground now renders from icon-inner.svg (the icon.svg minus its white disc and outer ring); (2) this launcher displays ~91% of the adaptive layer rather than the spec's 66% viewport, so the size was tuned empirically against side-by-side screenshots (three iterations: 61% too small, 84% too big, 77% matches). Published as 1.4 on zapstore; versionCode 5</title>
<updated>2026-09-05T07:07:41Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-05T07:07:41Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=87c7ab1802c6fb9ee45b3bd608f683d9c0804eb3'/>
<id>urn:sha1:87c7ab1802c6fb9ee45b3bd608f683d9c0804eb3</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>Android wrapper v1.2: launcher label is "Coinos" (capital C) and the icon matches the PWA exactly — the PWA's "maskable" icon turned out to be the plain transparent-background logo that Chrome plates on white, so the APK now ships a proper adaptive icon doing the same (white background layer, logo scaled into the 66% safe zone, launcher applies its mask); legacy mipmaps regenerated to match. Published to zapstore as release 1.2 and installed END-TO-END from the store on a real phone: the phone's Zapstore 0.2.7 couldn't read zsp's event schema ("app no longer exists") — updated to 1.1.2 and the flow ran clean: listing under the recognized coinos profile → Trust dialog → Play Protect first-seen scan → installed → launches mainnet v3 beta fullscreen</title>
<updated>2026-09-05T07:00:43Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-05T07:00:43Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=07c83cccabb1a95a1272fcc582f588de2b4483b4'/>
<id>urn:sha1:07c83cccabb1a95a1272fcc582f588de2b4483b4</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
<entry>
<title>Android wrapper v1.1: scheme + NFC intents move onto a per-intent trampoline (IntentActivity, noHistory) — a TWA already on screen ignores a new intent delivered to its still-alive launcher, so a second lightning: tap did nothing; the trampoline maps the URI to ?u= form and relaunches the TWA with CLEAR_TOP, which navigates the open app. Verified on a real phone over adb: URL-bar-less fullscreen (assetlinks verified after the site began serving /.well-known/assetlinks.json — the deploy hook's dist/* glob was blind to dot-directories, fixed on cs), lightning: intent lands on Send with the invoice filled, and a second bitcoin: intent fired while the app was open navigated it (BIP-21 parsed, address + amount). NFC NDEF filters ride the trampoline for bolt cards / NDEF tags</title>
<updated>2026-09-05T03:53:13Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-05T03:53:13Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=e5e375d8ea2f1193ffe01ff02639f002f91f8035'/>
<id>urn:sha1:e5e375d8ea2f1193ffe01ff02639f002f91f8035</id>
<content type='text'>
Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz
</content>
</entry>
</feed>
