An iOS app for reading and generating 1D and 2D barcodes. Built in SwiftUI on top of AVFoundation, Vision, and Core Image β no third-party dependencies. The point of the app is not just to decode a code, but to understand what's in it: scan a Wi-Fi QR and we'll show the SSID and offer to open Wi-Fi Settings; scan a SEPA invoice and we'll surface the IBAN, beneficiary, and amount as separate copyable rows; scan a fiscal receipt and we'll show the fiscal markers; and so on.
π± Available on the App Store: https://apps.apple.com/us/app/nettrash-scan/id6763932723 β bundle ID me.nettrash.Scan, App Store ID 6763932723. Use that link to install on a real iPhone or iPad. Source-built copies via Xcode are still recommended for testing local changes.
- Live-camera scanning of every symbology AVFoundation supports natively: QR, Aztec, PDF417, Data Matrix, EAN-8 / EAN-13, UPC-E, Code 39 (with mod-43 checksum), Code 93, Code 128, ITF-14, Interleaved 2 of 5, Codabar, and GS1 DataBar.
- Import an image from the Photo Library or Files; decoded with
VNDetectBarcodesRequest, which adds a few formats Vision recognises (microQR, microPDF417) on top. - Torch toggle, accent-coloured viewfinder corner brackets, debounced result presentation.
The decoded string is parsed and rendered as structured fields with per-row tap-to-copy. Recognised formats:
| Domain | Formats |
|---|---|
| Web / messaging | URL, mailto:, tel:, sms: / smsto: |
| Connectivity | WIFI: (SSID + password + security) |
| Geolocation | geo: |
| Identity | vCard (3.0), MECARD |
| Calendar | iCalendar VEVENT (line-folded, UTC / TZID / all-day dates) |
| Authentication | otpauth:// |
| Retail | EAN-8 / EAN-13 / UPC-E / ITF-14 product codes |
| Cryptocurrency | Bitcoin (BIP-21), Ethereum (EIP-681 with chain ID), Litecoin, Bitcoin Cash, Dogecoin, Monero, Cardano, Solana, Lightning (BOLT-11) |
| Bank payments | EPC SEPA Payment QR / GiroCode (EU), Swiss QR-bill (SPC), Czech SPD (Spayd), Slovak Pay by Square (recognition only β decoding needs LZMA), EMVCo Merchant QR with nested-template drilling for Pix, PayNow, PromptPay, CoDi, UPI-via-EMVCo, DuitNow, QRIS, FPS, NAPAS, NETS and friends, Indian UPI (upi://pay), Bezahlcode (German legacy bank:// / bezahlcode://), Serbian NBS IPS QR (Prenesi β PR / PT / PK) |
| Mobile-payment apps | Swish (Sweden, base64-JSON-encoded swish://), Vipps (Norway), MobilePay (Denmark / Finland), Bizum (Spain), iDEAL (Netherlands) |
| Receipts | Serbian SUF fiscal receipt |
Per payload type:
- URL β Open in Safari.
- Email / Phone / SMS β Compose / Call / Send via the right system app.
- Wi-Fi β Show network details, copy password, open Wi-Fi Settings.
- Location β Open in Maps.
- Contact β Add to Contacts via
CNContactViewController(delegate-driven save / cancel). - Calendar β Add to Calendar via
EKEventEditViewControllerwith iOS 17+ write-only access (full-access fallback on iOS 16). - Crypto β Open in Wallet (iOS picks an installed wallet via the URI scheme).
- Bank payments β Per-field copy (IBAN, amount, recipient, reference, INN, KPP, KBK, OKTMO, Czech variable / constant / specific symbols, β¦). Currency mapped via ISO 4217 numeric β alpha for EMVCo. Nested EMVCo templates render with a "β³" marker so individual sub-fields (Pix key, PayNow merchant ID, PromptPay phone, etc.) are individually copyable.
- UPI β Open in UPI app (iOS picks an installed UPI app β PhonePe, GPay, Paytm, BHIMβ¦).
- Mobile-payment apps β Open in via the registered URI scheme.
- Serbian SUF receipt β Open the official PURS verification page.
- All payloads β Copy raw / Share via system share sheet.
A dedicated Generate tab builds 1D / 2D codes from structured input via Core Image filters:
- Inputs β Text, URL, Contact (emits well-formed vCard 3.0), Wi-Fi (emits the standard
WIFI:payload with proper escaping). - Symbologies β QR, Aztec, PDF417, Code 128.
- Outputs β Share via system sheet, Save to Photos (with
NSPhotoLibraryAddUsageDescription), Copy image and encoded string to the pasteboard. - Live preview that re-renders on every keystroke; integer-scaled rendering for crisp module edges.
- Saved scans persist to Core Data + CloudKit (
NSPersistentCloudKitContainer) and sync across the user's devices. - Searchable list with relative timestamps and a payload-kind icon.
- Per-record detail screen with editable notes, smart actions, and delete.
The icon is a real, scannable QR code that decodes to https://nettrash.me, framed by amber viewfinder corner brackets on a navy gradient. Not decorative β every module matches the canonical encoding, so pointing the app's own scanner at the icon actually works.
CFBundleVersion comes from CURRENT_PROJECT_VERSION in the project file, and the Scan shared scheme has a post-build action that runs agvtool bump after every successful build:
cd "${PROJECT_DIR}" ; agvtool bump
agvtool bump (alias for next-version -all) rewrites CURRENT_PROJECT_VERSION directly in project.pbxproj thanks to the VERSIONING_SYSTEM = "apple-generic" build setting. Because it's a scheme post-action β not a build-phase script β it runs outside the User Script Sandbox, so Xcode's default ENABLE_USER_SCRIPT_SANDBOXING = YES doesn't block it. Same mechanism the sibling Geo app uses, ported here.
- Deployment target: iOS 26.0+ uniformly across the project root, the app target, and both test targets. (Bumping the test targets in step with the app target matters:
@testable import Scanbrings the iOS-26-built module into the test bundle, so a lower test deployment fails to link.) - Xcode: 26+ (uses the iOS 26 SDK and the Liquid Glass design system).
- Devices: iPhone and iPad (universal β
TARGETED_DEVICE_FAMILY = "1,2").
The app declares the following usage descriptions:
| Key | Used for |
|---|---|
NSCameraUsageDescription |
Live barcode scanning |
NSPhotoLibraryAddUsageDescription |
Saving generated codes to Photos |
NSContactsUsageDescription |
Add-to-Contacts UI when a vCard is scanned |
NSCalendarsUsageDescription |
Add-to-Calendar (iOS 16) |
NSCalendarsWriteOnlyAccessUsageDescription |
Add-to-Calendar (iOS 17+, write-only) |
The app never reads the user's address book, calendar, or photo library β every privileged action is mediated by a system-supplied edit-and-save UI.
If you just want to use the app, install it from the App Store β it's free, ad-free, and tracker-free:
App Store: https://apps.apple.com/us/app/nettrash-scan/id6763932723
The store listing is the right answer for end users, and is also the binary under "App Review Information" notes during App Store Connect submissions. Bundle ID me.nettrash.Scan, App Store ID 6763932723.
To build from source (recommended for testing local changes):
git clone https://github.com/nettrash/Scan.git
cd Scan
open Scan.xcodeprojCI runs on the macos-26 GitHub-hosted runner (Xcode 26 / iOS 26 SDK β required by the deployment target) via the workflow at .github/workflows/ios.yml. The workflow resolves whatever iPhone simulator the runner happens to ship with for the day, then runs build-for-testing followed by test-without-building. Equivalent locally:
xcodebuild test \
-scheme Scan \
-project Scan.xcodeproj \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro,OS=latest' \
CODE_SIGNING_ALLOWED=NOParser tests (ScanTests/ScanTests.swift) cover real-world payloads for every format the app claims to decompose β vCard, Wi-Fi, geo, mailto, sms, EPC, EMVCo, Bitcoin / Ethereum / Lightning, Swiss QR-bill, iCalendar (UTC and all-day), Serbian SUF / IPS, and round-trip checks for the composers. Run with βU in Xcode or:
xcodebuild test -scheme Scan -destination 'platform=iOS Simulator,name=iPhone 15'Scan/
ββ ScanApp.swift app entry point
ββ ContentView.swift TabView root (Scan / Generate / History)
ββ Persistence.swift Core Data + CloudKit container
β
ββ ScannerScreen.swift camera + photo / file import + result sheet
ββ CameraScannerView.swift AVCaptureSession wrapper
ββ ImageDecoder.swift VNDetectBarcodesRequest decoder
β
ββ GeneratorScreen.swift text / URL / contact / wifi β code
ββ CodeGenerator.swift Core Image filter wrappers
ββ CodeComposer.swift vCard / Wi-Fi composers
β
ββ HistoryScreen.swift searchable Core Data list
ββ ScanDetailView.swift per-record detail + actions
ββ PayloadActionsView.swift smart actions + LabelledFieldsList
β
ββ Symbology.swift AVFoundation + Vision symbology mapping
ββ ScanPayload.swift payload enum + master parser
ββ BankPaymentPayloads.swift EPC, Swiss, EMVCo (with nested drilling), Serbian
ββ RegionalPaymentPayloads.swift UPI, Czech SPD, Pay by Square, Bezahlcode, Swish, Vipps, MobilePay, Bizum, iDEAL
ββ CryptoPayload.swift BIP-21 / EIP-681 / BOLT-11 parser
ββ CalendarPayload.swift RFC 5545 VEVENT parser
β
ββ Scan.xcdatamodeld ScanRecord (id, value, symbology, timestamp, notes)
Things that have been considered and could land if there's demand:
- Switch the live scanner to VisionKit's
DataScannerViewControllerfor built-in viewfinder UI, region-of-interest, and live highlight of recognised codes. - Translation framework integration on iOS 18+ β "Translate" smart action for text / URL / contact payloads.
- Real decoding of Slovak Pay by Square payloads β would need an LZMA Swift package (e.g.
SWCompression) since iOS doesn't ship LZMA natively. Today we recognise the format and let the user route the raw token to a banking app via Share / Copy. - Localised field labels (currently English even for the Serbian and Czech formats).
- Boarding-pass (BCBP), AAMVA driver's-licence, GS1 Application Identifier decoders.
To be added β please drop a LICENSE file into the repo root.