Appearance
Usage Guide
Quick Start
Import the SDK and start the scanner with a result delegate:
swift
import UIKit
import KinegramScanSDK
class ViewController: UIViewController {
let scanSdk = KSCScanSDK()
@IBAction func buttonStartScannerTouched(_ sender: UIButton) {
scanSdk.startScanner(withDelegate: self, title: "ScanSDK Demo")
}
}
extension ViewController: KSCResultDelegate {
func found(_ results: [KSCResult]) {
for result in results {
print("Scanned result: \(result)")
}
}
}Processing Results
An array of KSCResult objects is returned by the delegate method. Each KSCResult contains the recognized data along with its type, defined by the KSCResultType enum:
swift
extension ExampleViewController: KSCResultDelegate {
func found(_ results: [KSCResult]) {
for result in results {
switch result.type {
case .MRZ:
if let mrz = result.mrz {
print("MRZ found: \(result.text)")
print(" Document Code: \(mrz.documentCode)")
print(" Issuing State: \(mrz.issuingState)")
print(" Primary Identifier: \(mrz.primaryIdentifier)")
print(" Secondary Identifier: \(mrz.secondaryIdentifier)")
print(" Nationality: \(mrz.nationality)")
print(" Document Number: \(mrz.documentNumber)")
print(" Date of birth: \(mrz.dateOfBirth)")
print(" Sex: \(mrz.sex)")
print(" Date of expiry: \(mrz.dateOfExpiry)")
print(" Optional Data 1: \(mrz.optionalData1)")
print(" Optional Data 2: \(mrz.optionalData2)")
print(" Blank Number: \(mrz.blankNumber)")
print(" Language: \(mrz.language)")
// Handle MRZ validation errors (see MRZError enum)
for error in mrz.errors {
if let e = MRZError(rawValue: error.intValue) {
print(" Error: \(e)")
}
}
}
case .NumberPlate:
if let numberPlate = result.numberPlate {
print("NumberPlate found: \(numberPlate.text)")
print(" First part: \(numberPlate.firstPart)")
print(" Second part: \(numberPlate.secondPart)")
print(" Country: \(numberPlate.country)")
}
case .IDL:
if let idl = result.idl {
print("IIN found: \(idl.iin)")
for key in idl.order {
if let key = key as? String, let value = idl.elements[key] {
print("\(key): \(value)")
}
}
}
case .Barcode:
print("Barcode format: \(result.format)")
print("Barcode text: \(result.text)")
case .IDB:
if let idb = result.idb {
print("IDB found:")
print("Country ID: \(idb.header.countryId)")
// See class KSCIDBInfo for more information
print("Signature Valid: \(idb.signatureValid)")
}
case .VDS:
if let vds = result.vds {
print("VDS found:")
print("Country ID: \(vds.header.countryId)")
// See class KSCVDSInfo for more information
print("Signature Valid: \(vds.signatureValid)")
}
case .VDSNC:
if let vdsnc = result.vdsnc {
print("VDS-NC found:")
print("Country ID: \(vdsnc.header.issuingCountry)")
// See class KSCVDSNCInfo for more information
print("Signature Valid: \(vdsnc.signatureValid)")
print("Certificate Known: \(vdsnc.certificateKnown)")
}
default:
print(result.text)
}
}
}
}Continuous Scanning
By default the scanner closes itself as soon as it finds a result. To keep it running and decide yourself whether to continue or stop — for example to show an alert for some number plates but not others — implement foundResults:continueScanning: instead of foundResults:. The scanner pauses and waits for you to call the completion block:
swift
extension ExampleViewController: KSCResultDelegate {
func found(_ results: [KSCResult], continueScanning completion: @escaping (Bool) -> Void) {
if let plate = results.first(where: { $0.type == .NumberPlate }), shouldAlert(plate) {
let alert = UIAlertController(
title: "Scan Result",
message: "Flagged plate: \(plate.numberPlate?.text ?? "")",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Continue", style: .default) { _ in
completion(true)
})
alert.addAction(UIAlertAction(title: "Stop", style: .cancel) { _ in
completion(false)
})
present(alert, animated: true)
} else {
completion(true)
}
}
}If both delegate methods are implemented, foundResults:continueScanning: takes precedence. Note that the same object may be reported again once scanning resumes if it is still in view — debounce on the fields you care about (e.g. numberPlate.text) if that matters for your use case.
MRZ Validation Errors
The mrz.errors property contains an array of NSNumber values representing validation errors found during MRZ parsing. Convert them to MRZError enum values for easier handling:
swift
for error in mrz.errors {
if let e = MRZError(rawValue: error.intValue) {
switch e {
case .ErrorDocumentNumberCheckDigit:
print("Document number check digit invalid")
case .ErrorDateOfBirthCheckDigit:
print("Date of birth check digit invalid")
case .ErrorDateOfExpiryCheckDigit:
print("Date of expiry check digit invalid")
case .ErrorCombinedCheckDigit:
print("Combined check digit invalid")
// Handle other cases…
default:
break
}
}
}See the MRZError enum in KSCMRZInfo.h for the complete list of error types.
Custom IDB Profiles
Use setIDBProfiles() to set custom IDB profiles before scanning:
swift
scanSdk.setIDBProfiles(
"[{\"tag\":9,\"name\":\"Card Access Number\",\"type\":\"C40STR\"}]"
)Custom VDS Profiles
Use setVDSProfiles() to specify custom VDS profiles:
swift
scanSdk.setVDSProfiles(
"[{\"id\":4128,\"features\":[{\"tag\":2,\"name\":\"foo\",\"type\":\"UTF8STR\"}]}]"
)The integer key (4128 in this example, which is 0x1020 hexadecimal; JSON does not support hexadecimal numbers) must be the "Document Feature Definition Reference" byte (0x10 in bit 9 to 16) and the "Document Type Category" byte (0x20 in bit 1 to 8). These bytes identify a VDS profile.
Document Feature Types
For each document feature you need to specify a tag, a name, and a type. Possible types are:
| Type | Description |
|---|---|
RAW | Binary data |
UBYTE | Unsigned char |
UINT16LE | Unsigned 16-bit integer little endian |
UINT24LE | Unsigned 24-bit integer little endian |
UINT32LE | Unsigned 32-bit integer little endian |
DATE | Unsigned 24-bit integer big endian read as "MMddyyyy" |
TIMESTAMP | Unix time stamp |
UTF8STR | UTF8 string |
C40STR | C40-encoded string |
C40MRZMRVA | C40-encoded MRVA MRZ |
C40MRZMRVB | C40-encoded MRVB MRZ |
C40MRZTD2 | C40-encoded TD2 MRZ |
C40MRZTD3 | C40-encoded TD3 MRZ |
VDS Verification
To verify a VDS, you need the certificate with which the VDS was signed.
Use setCertificates() to specify a list of certificate files before scanning:
swift
scanSdk.setCertificates(["path/to/certificate.cer"])VDS-NC / IDB Verification
To verify a VDS-NC or IDB barcode, the CSCA (Country Signing Certificate Authority) certificate of the issuing country is required. This certificate can be obtained from the ICAO master list or the BSI master list.
Use setCMS() to specify a list of master list files before scanning:
swift
scanSdk.setCMS(["path/to/masterlist.ml"])