Releases: nettrash/Scan
v1.8.59
Scan v1.8.59 — Release Notes
It's been a while since 1.1 — here's everything that's landed since.
Now on Mac and Vision Pro
- Mac (Catalyst). Scan now ships as a native Mac app with the same bundle ID and iCloud library. Use your built-in webcam or a Continuity Camera to scan, and pinch on the trackpad to zoom.
- Vision Pro. Apple doesn't expose Vision Pro's cameras to third-party apps, so the Scan tab there leads with Choose from Photos / Choose from Files instead of a broken viewfinder. Generate works as on iPad, and your full history syncs in.
- Same library, every device. iCloud sync now actually replicates — scan on iPhone, see it on Mac and Vision Pro a moment later.
Smarter scanning
- Pinch to zoom on the live camera, capped at 8× so you don't end up zooming into noise.
- Centred-frame focus. The recogniser only looks at the area inside the corner brackets, so a stray code at the edge of the frame can't steal a scan from the one you're aiming at.
- Multi-code disambiguation. When more than one barcode is in frame, you'll see numbered chips on each — tap the one you actually want.
- Live preview no longer freezes when a result is recognised. The sheet slides up over a still-running camera, with smart de-duplication so the same code doesn't keep re-presenting.
- Reticle releases when no codes are visible, instead of staying stuck on the last one.
Share to Scan + PDF support
- Share Extension. Scan now appears in the iOS share sheet. Send it images or PDFs from any app and decode them inline, up to 10 at once.
- PDFs are decoded end-to-end — every page is rasterised at 2× and run through the recogniser. Works in the Files importer too.
Universal Links
- Open
https://nettrash.me/scan/<payload>links straight into a result sheet with all the usual smart actions and a one-tap Save to History. Great for sharing a code as a plain link.
New payload types
- Wi-Fi: WPA3 (SAE) and Passpoint (HS20) recognised, with friendly security labels and a heads-up that Passpoint profiles need to be installed manually.
- Stablecoins: USDC / USDT / DAI tagged automatically across Ethereum (EIP-681 ERC-20 transfers), Tron (TRC-20) and Solana (Solana Pay SPL). Bare Tron addresses (
T…) are detected too. - Digital identity: DigiD, EUDI Wallet and OpenID4VC login flows recognised, with an explicit warning so a stranger's QR can't quietly log you into their session.
- Loyalty cards. Save a product barcode as a loyalty card with a merchant tag — pinned to the top of History, instantly findable in search.
- GS1 Application Identifiers in all three forms (parens, GS1 Digital Link, FNC1).
- IATA boarding passes (PDF417, RP 1740c) — passenger, PNR, route, flight, seat, sequence.
- AAMVA driver's licences (PDF417) for US states + Canadian provinces.
- Magnet links, plus richer URL recognition (WhatsApp, Telegram, Wallet
.pkpass, App Store, YouTube, Spotify, Apple Music, Google/Apple Maps). - More crypto chains: XRP, Stellar, Cosmos, LNURL, Lightning Address — and bare-address detection for legacy + bech32 Bitcoin, Ethereum, XRP, Stellar, Cosmos, bolt11, LNURL.
Generator
- Foreground / background colour pickers with a live preview and a WCAG contrast warning when you drop below 3:1.
- QR error-correction picker (L/M/Q/H), forced to H when a logo is set.
- Logo embedding with an automatic white "punch" behind it so the finder pattern stays scannable.
- SVG and PDF exports alongside PNG — true vector output that prints cleanly at any size.
- Reset to default to get back to plain black-on-white in one tap.
- Tap-outside / drag-down to dismiss the keyboard, plus a Done toolbar accessory.
History
- Favourites. Star a scan to pin it to the top, with a Favourites-only filter chip in the toolbar.
- CSV export of either the visible list (respects search + filters) or everything, RFC 4180-compliant.
Settings (new tab)
- Haptic on scan (on by default), sound on scan (off by default), continuous scanning mode that saves straight to History and shows an inline banner instead of a sheet.
- Test feedback button to compare the two.
- iCloud sync status — see at a glance whether you're signed in, with a pointer to system Settings if not.
What's New sheet
- A first-launch summary after every version bump, so you see what changed without having to come find these notes.
App Store + housekeeping
- Listed publicly on the App Store.
- Privacy policy hosted at https://nettrash.me/appstore/scan/privacy.html.
- Refreshed app icon — the QR motif now reads as a scanner in the dock and Spotlight.
- 90 parser tests in CI (up from 38) keeping all the new payload types honest.
v1.1.22
Full Changelog: v1.1...v1.1.22
v1.1
Full Changelog: v1.0.10...v1.1
v1.0.10
Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
CFBundleVersion (build number) is the value of CURRENT_PROJECT_VERSION
in the project file and is now auto-incremented by the app target's
build-phase script via agvtool next-version -all.
v1.0.10
Added
App shell
-
Replaced the default Xcode SwiftUI + Core Data template with a real
three-tab app: Scan, Generate, History. -
App icon is a real, scannable QR code pointing to
https://nettrash.me, framed by amber viewfinder corner brackets on a
navy gradient. Verified pixel-accurate against the canonical encoding. -
Build number (
CFBundleVersion) auto-increments via a scheme
post-action on theScanshared scheme that runs
cd "${PROJECT_DIR}" ; agvtool bumpafter every successful build.
agvtool bump(alias fornext-version -all) rewrites
CURRENT_PROJECT_VERSIONinproject.pbxprojdirectly — no
build-phase script and so no User Script Sandbox to fight.
Same mechanism the siblingGeoapp uses; ported wholesale.Earlier iterations tried two other approaches that didn't survive
contact with reality: aPBXShellScriptBuildPhasederiving the
build number fromgit rev-list --count HEAD(Xcode 14+'s default
ENABLE_USER_SCRIPT_SANDBOXING = YESblocks the script from
reading.git/, so it printed "Could not determine git commit
count" and left the version unchanged); and pure manual bumping
via Editor → Increase Build Number (worked but easy to forget).
The post-action approach is sandbox-friendly and runs automatically.
Live camera scanner
ScannerScreen+CameraScannerView(UIViewControllerRepresentable
wrappingAVCaptureSession+AVCaptureMetadataOutput).- Symbologies: QR, Aztec, PDF417, Data Matrix, EAN-8, EAN-13, UPC-E,
Code 39 (and mod-43 checksum), Code 93, Code 128, ITF-14, Interleaved 2
of 5, Codabar, GS1 DataBar variants where the device supports them. - Camera-permission flow with descriptive failure messaging.
- Torch toggle.
- Accent-coloured viewfinder corner brackets (no decorative outline —
scan area is implied by the brackets). - Result-debouncing so repeated reads of the same code in quick
succession don't spam the result sheet.
Image import (still scans)
- Import from Photo Library (
PhotosPicker) and Files
(fileImporter). ImageDecoderrunsVNDetectBarcodesRequeston a background queue;
surfaces decoded codes through the same result sheet as live scans.- Vision-symbology mapping into the app's
Symbologyenum, including
microQR / microPDF417 / GS1 DataBar variants. - Decoding spinner; pauses the live session while reading.
Smart payload decomposition
ScanPayload is parsed from the decoded string and rendered as
labelled, copyable fields. Recognised:
- URLs (
http/https) - Email (
mailto:with subject/body params) - Phone (
tel:) - SMS / SMSTO (
sms:,smsto:NUMBER:BODY) - Wi-Fi (
WIFI:T:…;S:…;P:…;H:…;;) with backslash-escape support - Geolocation (
geo:lat,lon?q=…) - vCard 3.0 and MECARD contacts
- iCalendar VEVENT with RFC-5545 line-folding, UTC / TZID / all-day
date forms, escape-sequence unescaping,mailto:stripped from organizer - One-time-password URIs (
otpauth://) - EAN-8 / EAN-13 / UPC-E / ITF-14 product codes (driven by
symbology, not text content) - Cryptocurrency wallet URIs:
- Bitcoin (BIP-21)
- Ethereum (EIP-681 with
@chainId) - Litecoin, Bitcoin Cash, Dogecoin, Monero, Cardano, Solana
- Lightning (BOLT-11)
- Bank payments:
- EPC SEPA Payment QR (GiroCode) — line-based, v001 / v002
- Swiss QR-bill (SPC) — full address-block parsing (S / K),
creditor + ultimate creditor + ultimate debtor, QRR / SCOR / NON
reference types - Czech SPD (Spayd) — asterisk-delimited
SPD*1.0*ACC:…*AM:…*…*;
surfaces IBAN, amount + currency, recipient, message, due date,
variable / constant / specific symbols (X-VS/X-KS/X-SS),
with+-to-space decoding per SPD escaping rules - Slovak Pay by Square — recognised heuristically (header prefix
plus all-base32hex check); decoding requires LZMA which iOS doesn't
ship, so the result sheet labels the format and offers Copy / Share
so the raw token can be passed to a banking app - Russian unified payment (
ST00012/ST00011) — pipe-separated
fields with friendly English labels for the well-known keys;Sum
converted from kopecks to rubles - EMVCo Merchant QR — top-level TLV walker plus recursive drilling
into Tag 62 (Additional Data: Bill number / Mobile number / Store
label / Reference label / Customer label / Terminal label / Purpose
of transaction) and Tags 02–51 (Merchant Account Information).
Recognises 14 known scheme GUIDs and renames the parent row by
scheme: Pix, PayNow, NETS, PromptPay, CoDi,
UPI, FPS (Hong Kong), DuitNow (Malaysia), QRIS
(Indonesia), NAPAS (Vietnam), and friends. Sub-fields render with
a "↳" marker for individual tap-to-copy. 28-currency ISO 4217
numeric→alpha mapping; static / dynamic initiation-method labels. - Indian UPI (
upi://pay) — VPA, payee name, amount + currency
(defaults INR), note, merchant code, transaction ID, and reference
URL all surfaced as labelled fields - Bezahlcode (German legacy
bank:///bezahlcode://) — full
field mapping (beneficiary, IBAN, BIC, amount, currency, purpose,
creditor / mandate IDs) - Serbian NBS IPS QR (Prenesi) —
K:value | …format with
PR / PT / PK kind labels, percent-decoded recipient names, validates
required K / R / V fields
- Mobile-payment apps (regional URI schemes):
- Swish (Sweden,
swish://payment?data=<base64-JSON>) —
base64-decoded JSON exposes payee, amount, message, currency - Vipps (Norway,
vipps://) — phone number, amount, message,
merchant ID, order text - MobilePay (Denmark / Finland,
mobilepay://) — phone, amount,
comment, locked-amount flag - Bizum (Spain,
bizum://) — phone, amount, concept - iDEAL (Netherlands,
ideal://) — IBAN, amount, beneficiary,
description, reference
- Swish (Sweden,
- Receipts:
- Russian FNS retail receipt — Europe/Moscow timestamp parsed to a
Date, sale / refund / expense / expense-refund classification - Serbian SUF fiscal receipt — recognised by
suf.purs.gov.rs
host (exact match or proper subdomain — lookalike domains rejected);
"Verify Receipt" action opens the official PURS verification page
- Russian FNS retail receipt — Europe/Moscow timestamp parsed to a
Smart actions per payload
- URL → Open in Safari.
- Email / Phone / SMS → Compose / Call / Send via the right system app.
- Wi-Fi → Show details, copy password, open Wi-Fi Settings.
- Location → Open in Maps.
- Contact → Add to Contacts via
CNContactViewControllerwith a
CNContactViewControllerDelegatecoordinator (Done / Cancel dismiss
the sheet correctly). - Calendar → Add to Calendar via
EKEventEditViewController,
usingrequestWriteOnlyAccessToEventson iOS 17+ andrequestAccess(to:.event)
on iOS 16. Denial alert directs the user to Settings. - Crypto → Open in Wallet (iOS picks an installed wallet via the URI
scheme). - UPI → Open in UPI app (handed off via
upi:scheme so iOS picks
an installed UPI app — PhonePe, GPay, Paytm, BHIM…). - Mobile-payment apps (Swish / Vipps / MobilePay / Bizum / iDEAL) →
Open in via the registered URI scheme. - Product code → Look up via web search.
- Serbian SUF → Verify Receipt (opens PURS site).
- All payloads → global Copy + Share buttons; per-field tap-to-copy on
bank / receipt / crypto / Serbian / Czech / UPI / calendar payloads.
Generation
- New Generate tab in the TabView.
- Inputs: Text, URL, Contact, Wi-Fi.
- Symbologies: QR (correction level M), Aztec, PDF417, Code 128.
- Outputs: Share (system sheet), Save to Photos (uses
PHPhotoLibrary.requestAuthorization(for: .addOnly)for least
privilege), Copy (puts both image and encoded string on
UIPasteboardviasetObjects). - Composers:
- vCard 3.0 with CRLF line endings,
FN/Nsplit, and proper
text-value escaping. - WIFI: payload with backslash-escaped special chars; password field
omitted when "None" security is selected.
- vCard 3.0 with CRLF line endings,
- Live preview that re-renders on every keystroke; integer-scaled
rendering for crisp module edges; multi-line-content warning when
Code 128 is paired with content that contains newlines.
History
ScanRecordCore Data entity (id, value, symbology, timestamp,
notes) replacing the template's stubItementity.NSPersistentCloudKitContainerso saved scans sync across the user's
iCloud devices.- Searchable list with relative timestamps and a payload-kind SF Symbol
per row. - Empty state via a
ContentUnavailableView(with an iOS 16 fallback). - Per-record detail screen with editable notes, smart actions, share,
delete.
Permissions / Info.plist
NSCameraUsageDescriptionfor the live scanner.NSPhotoLibraryAddUsageDescriptionfor Save-to-Photos in the
generator.NSContactsUsageDescriptionfor Add-to-Contacts.NSCalendarsUsageDescriptionandNSCalendarsWriteOnlyAccessUsageDescription
for Add-to-Calendar.- All keys also mirrored as
INFOPLIST_KEY_*build settings, since the
project usesGENERATE_INFOPLIST_FILE = YES.
Tests
ScanTestscovers parser ...