A production-ready barcode + QR code scanner for Android and iOS, built with Flutter. Scan anything, get a smart result (link / email / phone / text), and keep a local history of everything you've scanned.
Dark-mode by default, Material 3, Poppins typography, and a blue → purple gradient accent. Because scanners don't have to look boring.
- Live camera scanning — QR codes, EAN/UPC barcodes, Code 39/128, ITF, Codabar and more, via
mobile_scanner(MLKit under the hood). - Continuous scanning — the camera keeps detecting until you decide to act on a result.
- Flashlight toggle and front/back camera switch right on the scanner screen.
- Smart results — the app detects the content type and offers the right action:
- URL → Open Link
- Email → Send Email
- Phone → Call
- Plain text → Copy
- Plus Copy and Share everywhere.
- Local history — every scan is saved on-device (SharedPreferences). Swipe to delete, undo, clear all, or export the whole history as a text file.
- Friendly camera permissions — a clean screen with Open Settings / Retry if access is ever denied.
- Premium feel — animated splash, pulsing scan button, animated scanning line, frosted-glass cards, haptic feedback on every successful scan, and smooth page transitions throughout.
- Flutter SDK — latest stable (3.29+ recommended), on your
PATH - Android Studio / Xcode for the platform toolchains
From the project root:
./scripts/setup.shThis scaffolds the platform folders (android/, ios/), patches the iOS camera permission and display names, runs flutter pub get, and finishes with flutter analyze. It never overwrites your lib/ code.
First run downloads the Poppins fonts from Google Fonts at runtime; if you're offline it gracefully falls back to the system font.
flutter create --platforms android,ios --org com.example --project-name scanner .
flutter pub getThen add NSCameraUsageDescription to ios/Runner/Info.plist (setup.sh does this for you):
<key>NSCameraUsageDescription</key>
<string>Scanly uses your camera to scan QR codes and barcodes.</string>flutter runPick a connected device or emulator. Tip: point your laptop webcam at any QR code — or generate one at qrcode-monkey.com — to test it.
flutter build apk --releaseYour installable APK lands here:
build/app/outputs/flutter-apk/Scanly-Mobile-1.0.0-release.apk
flutter build ios --releaseThat produces a release build (not an installable IPA yet — Apple needs a signing setup for that):
- Open
ios/Runner.xcworkspacein Xcode. - Set your team under Signing & Capabilities (this changes the bundle id from
com.example.scannerto something of your own). - Go to Product → Archive, then Distribute App → App Store Connect (or Ad Hoc / Development for a direct IPA).
Clean, feature-first structure — Riverpod for state, GoRouter for navigation:
lib/
├── main.dart # entry point
├── app/
│ ├── app.dart # root widget + theme
│ └── router.dart # GoRouter routes + transitions
├── core/
│ ├── theme/ # colors + Material 3 dark theme
│ └── utils/ # content classifier, formatters, haptics
├── features/
│ ├── home/ # home screen (hero scan button, stats, recent)
│ ├── scanner/ # scanner screen, overlay, result screen
│ └── history/ # history model, repository, provider, screen
└── shared/
├── splash/ # animated splash
└── widgets/ # gradient button, glass card, tiles, badges…
| Concern | Package |
|---|---|
| Scanning | mobile_scanner |
| State | flutter_riverpod |
| Navigation | go_router |
| Local storage | shared_preferences |
| Permissions | permission_handler |
| Share/export | share_plus |
| Links/email | url_launcher |
| Fonts | google_fonts (Poppins) |
| Animation | flutter_animate |
| Dates | intl |
Mock previews (the real thing looks even better on a device):
| Home | Scanner | History |
|---|---|---|
- Camera doesn't start on iOS — make sure
NSCameraUsageDescriptionis inios/Runner/Info.plist(setup.sh adds it). - Black screen / camera error in the emulator — the Android emulator needs a virtual camera enabled (AVD → Camera: Emulated).
flutter createcomplains about the folder name — it's fine;--project-name scannerhandles it.- Fonts look different offline — google_fonts falls back to the system font; bundle the
.ttffiles if you need strict offline fidelity.
MIT — scan away. 🎉