ExtraDigits Documentation
Learn how to integrate +2 and +5 supplemental barcode scanning into your iOS and Android apps.
You'll need an active subscription to use ExtraDigits. Subscribe here to get your API key.
Installation
Swift Package Manager (iOS)
Add ExtraDigits to your Xcode project using Swift Package Manager:
Open Package Dependencies
In Xcode, go to File > Add Package Dependencies...
Enter Repository URL
Paste the following URL:
https://github.com/extradigits/extradigits-ios.git
Select Version
Choose "Up to Next Major Version" and click Add Package.
CocoaPods (Alternative)
Add to your Podfile:
pod 'ExtraDigits', '~> 1.2'
Quick Start
Get scanning in under 5 minutes with this minimal implementation:
import SwiftUI
import ExtraDigits
struct ContentView: View {
@State private var scannedCode: String?
var body: some View {
VStack {
ExtraDigitsner(
apiKey: "ed_live_your_api_key_here"
) { result in
switch result {
case .success(let barcode):
scannedCode = barcode.fullCode
case .failure(let error):
print("Scan error: \(error)")
}
}
if let code = scannedCode {
Text("Scanned: \(code)")
.font(.headline)
.padding()
}
}
}
}
iOS Project Setup
Camera Permission
Add camera usage description to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required to scan barcodes</string>
Initialize the SDK
Initialize ExtraDigits early in your app lifecycle, typically in your App struct:
import SwiftUI
import ExtraDigits
@main
struct MyApp: App {
init() {
// Initialize with your API key
ExtraDigits.configure(apiKey: "ed_live_your_api_key_here")
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Basic Scanning
The ExtraDigitsner view handles camera setup, permission requests, and barcode detection automatically.
struct ScannerView: View {
@State private var isScanning = true
@State private var lastBarcode: SupplementBarcode?
var body: some View {
ZStack {
ExtraDigitsner(
apiKey: "ed_live_your_api_key_here",
isScanning: $isScanning,
supplementTypes: [.ean2, .ean5] // Scan both types
) { result in
switch result {
case .success(let barcode):
lastBarcode = barcode
isScanning = false // Pause after successful scan
// Haptic feedback
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
case .failure(let error):
handleError(error)
}
}
// Overlay with scan result
if let barcode = lastBarcode {
ResultOverlay(barcode: barcode) {
lastBarcode = nil
isScanning = true // Resume scanning
}
}
}
}
func handleError(_ error: ScanError) {
switch error {
case .cameraUnavailable:
print("Camera not available")
case .permissionDenied:
print("Camera permission denied")
case .invalidApiKey:
print("Invalid or expired API key")
case .subscriptionInactive:
print("Subscription is not active")
default:
print("Unknown error: \(error)")
}
}
}
Customization
Customize the scanner appearance with the ScannerStyle configuration:
let customStyle = ScannerStyle(
// Viewfinder appearance
viewfinderColor: .white,
viewfinderLineWidth: 3,
viewfinderCornerRadius: 12,
viewfinderSize: CGSize(width: 280, height: 100),
// Scanning line animation
showScanLine: true,
scanLineColor: Color.red,
// Background dimming
overlayColor: Color.black.opacity(0.6),
// Feedback
enableHaptics: true,
enableSoundFeedback: true,
successSound: "scan_success" // Custom sound file
)
ExtraDigitsner(
apiKey: "ed_live_your_api_key_here",
style: customStyle
) { result in
// Handle result
}
Handling Results
The SupplementBarcode object contains all scanned data:
| Property | Type | Description |
|---|---|---|
mainCode |
String | The primary EAN-13 or UPC-A barcode |
supplement |
String? | The +2 or +5 supplemental code (nil if none) |
supplementType |
SupplementType | .ean2, .ean5, or .none |
fullCode |
String | Combined main + supplement code |
timestamp |
Date | When the barcode was scanned |
func processBarcode(_ barcode: SupplementBarcode) {
print("Main code: \(barcode.mainCode)")
// Example: "012345678905"
if let supplement = barcode.supplement {
print("Supplement: \(supplement)")
// Example: "12345" (for +5) or "09" (for +2)
switch barcode.supplementType {
case .ean2:
// Magazine issue number
let issueNumber = Int(supplement) ?? 0
print("Magazine issue #\(issueNumber)")
case .ean5:
// Could be price, issue, or variant info
parseEAN5Supplement(supplement)
case .none:
break
}
}
print("Full code: \(barcode.fullCode)")
// Example: "012345678905-12345"
}
func parseEAN5Supplement(_ code: String) {
// For books: First digit indicates currency, rest is price
// 5 = USD, 6 = CAD, etc.
let currencyCode = code.prefix(1)
let priceValue = code.dropFirst()
if currencyCode == "5" {
let price = (Double(priceValue) ?? 0) / 100
print("Suggested price: $\(price)")
}
// For comics: Issue (3 digits) + Variant (1) + Print (1)
if code.count == 5 {
let issue = String(code.prefix(3))
let variant = code[code.index(code.startIndex, offsetBy: 3)]
let printing = code.last!
print("Issue: \(issue), Variant: \(variant), Print: \(printing)")
}
}
ISBN OCR Recognition
ExtraDigits includes powerful OCR capabilities to recognize ISBN numbers from text - no barcode required. ISBN-10 numbers are automatically converted to ISBN-13 format on the fly. This is perfect for cataloging older books, processing donations, or scanning damaged barcodes.
ISBN OCR is included with your ExtraDigits subscription at no additional cost.
Basic ISBN OCR Usage
Use the ISBNScanner view for text-based ISBN recognition:
import ExtraDigits
struct BookCatalogView: View {
var body: some View {
ISBNScanner(
apiKey: "ed_live_your_api_key_here",
mode: .textRecognition // OCR mode for printed/handwritten text
) { result in
switch result {
case .success(let isbn):
print("Found ISBN: \(isbn.number)")
print("Format: \(isbn.format)") // .isbn10 or .isbn13
print("Valid: \(isbn.isValid)") // Check digit validated
case .failure(let error):
print("Error: \(error)")
}
}
}
}
ISBN Scanner Modes
The ISBNScanner supports multiple scanning modes:
| Mode | Description | Best For |
|---|---|---|
.textRecognition |
OCR for printed ISBN text anywhere on page | Copyright pages, title pages, older books |
.handwriting |
Advanced OCR for handwritten ISBN numbers | Inventory sheets, catalog cards, notes |
.barcode |
Standard ISBN barcode scanning | Books with Bookland EAN barcodes |
.hybrid |
Combines barcode + text recognition | Maximum flexibility, scans anything |
Handling ISBN Results
The ISBNResult object provides validated ISBN data with automatic conversion options:
// Enable automatic ISBN-10 to ISBN-13 conversion
ISBNScanner(
apiKey: "ed_live_your_api_key_here",
mode: .hybrid,
autoConvertToISBN13: true // All results returned as ISBN-13
) { result in
// result.number is always 13 digits
}
func processISBN(_ isbn: ISBNResult) {
// The raw ISBN number (digits only)
let number = isbn.number // "9780134685991"
// Formatted with hyphens
let formatted = isbn.formatted // "978-0-13-468599-1"
// Original format detected (before conversion)
switch isbn.originalFormat {
case .isbn10:
print("Originally 10-digit, auto-converted to 13")
case .isbn13:
print("Already 13-digit ISBN")
}
// Check digit validation
if isbn.isValid {
// ISBN passed check digit verification
lookupBookInfo(isbn: number)
} else {
// May be a misread - prompt user to verify
showVerificationPrompt(isbn: number)
}
// Manual conversion methods (if autoConvert is off)
let isbn13 = isbn.toISBN13() // Convert ISBN-10 to ISBN-13
let isbn10 = isbn.toISBN10() // Convert ISBN-13 to ISBN-10 (978 prefix only)
// Source of the ISBN
switch isbn.source {
case .barcode:
print("Scanned from barcode")
case .printedText:
print("Recognized from printed text")
case .handwriting:
print("Recognized from handwriting")
}
}
Android Project Setup
The Android/Kotlin SDK is available via Gradle or Maven. Your subscription includes access to both platforms at no additional cost.
API Reference
ExtraDigitsner
The main SwiftUI view for barcode scanning.
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey |
String | Yes | Your ExtraDigits API key |
isScanning |
Binding<Bool> | No | Control scanning state programmatically |
supplementTypes |
[SupplementType] | No | Types to scan. Default: [.ean2, .ean5] |
style |
ScannerStyle | No | Custom appearance configuration |
onResult |
Closure | Yes | Called with Result<SupplementBarcode, ScanError> |
Supported Barcode Types
| Type | Format | Common Uses |
|---|---|---|
| EAN-13 + 2 | 13 + 2 digits | Magazines, periodicals (issue numbers) |
| EAN-13 + 5 | 13 + 5 digits | Books (price), comics (issue/variant/print) |
| UPC-A + 2 | 12 + 2 digits | US/Canada periodicals |
| UPC-A + 5 | 12 + 5 digits | US/Canada books, weighted products |
Troubleshooting
Invalid API Key Error
If you receive an invalidApiKey error:
- Verify your API key is copied correctly from the dashboard
- Ensure your subscription is active
- Check that you're using a live key (
ed_live_), not a test key
Subscription Inactive Error
This error occurs when:
- Your subscription has expired or been cancelled
- Payment method failed to process
Visit your dashboard to update payment or reactivate.
Scanning Not Detecting Supplements
If the main barcode scans but supplements are missed:
- Ensure adequate lighting on the barcode
- Hold the device steady and at the correct distance (8-12 inches)
- Make sure the entire barcode including supplement is in frame
- Check that you've enabled the correct
supplementTypes
Contact us at support@extradigits.dev for technical assistance.