PhotonQR
Moving files across an air gap, one screenful at a time
Every file transfer tool assumes a shared network. PhotonQR assumes the opposite: two devices that can see each other and nothing else. What comes back is a real protocol problem — framing, error correction, flow control — solved through a camera.
Flutter · Dart · AES-256-GCM · Reed–Solomon · SHA-256 · GitHub Actions
The sender renders a file as a sequence of QR frames on screen; the receiver films them through its camera and reassembles the bytes. There is no pairing step, no shared network, and no radio involved — which means the transfer works in places where every other method is either unavailable or disallowed.
Honest about being slow
At QR version 15 and twelve frames per second the ceiling is roughly four kilobytes per second before losses. A 50 KB document takes about twenty seconds; a 3 MB photo takes about twenty minutes; a 200 MB video is not practical. The Send screen states the estimate before you begin, because a user who picks a large video without being warned will reasonably conclude the app is broken when it is still going an hour later.
The protocol
Every packet is encrypted with AES-256-GCM, with the frame header bound in as associated data so a tampered header fails authentication rather than silently mis-routing a chunk. Reed–Solomon erasure coding over GF(256) means the receiver tolerates dropped and corrupted frames without a retransmit channel — which matters, because there is no back-channel to request one. The completed file is verified against the sender's SHA-256 digest before it is written.
- 01Any binary file — the protocol carries bytes, with no type restrictions.
- 02Automatic compression, skipped when it would not help: JPEG, MP4, ZIP and APK are detected and stored verbatim rather than expanded.
- 03Adaptive optimisation that diagnoses why throughput is low before changing anything.
- 04Resume across app restarts, so a long transfer survives being interrupted.
- 05Developer mode with a live protocol monitor.
No network permission at all
The application declares no network permission, and there is no code path that could use one. For a tool whose entire purpose is moving data without a network, that is the difference between a privacy claim and a structural guarantee: it cannot phone home, and you can verify that from the manifest rather than taking my word for it.
Built on Flutter 3.35.7 for Android API 24+ and iOS 12+, in a feature-first clean architecture with no circular dependencies, and wired to GitHub Actions for CI and releases.