Complete Manual for document capture in iOS applications
Estimated time: 45-60 minutes for complete configuration
What will you learn from this manual?
This manual will teach you how to implement and use JAAKStamps SDK for automated capture of identity documents in native iOS applications. No advanced technical skills required - Just follow the steps.
Before Start - Checks list
Be sure to have these elements ready:
- Xcode 12.0 + installed
- iOS 13.0 + device (physical, non-simulator)
- Cocoa
- Basic information about Swift / UIKit
- Access to a functional camera
- Test ID
Contents Index
| Section | What will you do? | Time |
|---|---|---|
| Step 1 | Configure Project and Units | 10 min |
| Step 2 | Basic implementation of SDK | 20 min |
| Step 3 | Configure Camera Permissions | 10 min |
| Step 4 | Management of responses and images | 15 min |
| Step 5 | Test document capture | 10 min |
Step 1: Configure Project and Units
Objective
Configure the development environment and add the necessary SDK.
Technical requirements
| Requirement | Version | Mandatory? |
|---|---|---|
| Xcode | 12.0+ | Yes |
| iOS | 13.0+ | Yes |
| Swift | 5.5+ | Yes |
| Cocoa | Last | Yes |
| RAM | 2GB + | Recommended |
1.1 Podfile configuration
platform :ios, '13.0'
use_frameworks!
target 'YourApp' do
# SDK JAAKStamps - Beta Version
pod 'jaak-stamps', '>= 1.0.0-beta.1', '< 1.0.0-dev'
end
1.2 Unit installation
# Instalar dependencias
pod install
# Open workspace (important: not .xcodeproj)
open YourApp.xcworkspace
1.3 Building Settings
Important
For the proper functioning of the library, you have to set up the following building setting: Using Sandboxing Script = NO
How to set up?
- At Xcode, select your project (not target)
- Go to Build Settings
- Search "Using Sandboxing Script" (you can use the search field)
- Switch Value To "No"
Why's that necessary?
The JAAKStamps library uses scripts during the build process to:
- Copy Resource Requires (ONNX models, configuration files)
- Configure native frameworks
- Validate dependencies
Script sandboxing can interfere with these processes, leading to built or run-time errors. Unabling this option allows the library to work properly.
Security note: That configuration is specific to the build process and does not affect final application security.
1.4 Frameworks Requirement
In your Xcode project, check that these frameworks are linked:
- UIKit - User interface
- AVFoundation - Access to camera
- Korea - AI processing
- Vision - Image analysis
- Foundation - Base functions
Step 2: Basic implementation of SDK
Objective
Create JAAKStamps core implementation SDK with an automated capture.
2.1 Basic Viewer
import UIKit
import JAAKStamps
class DocumentCaptureViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupDocumentCapture()
}
private func setupDocumentCapture() {
let config = JaakStampsConfig.defaultConfig()
let captureController = JaakStampsViewController(config: config)
captureController.delegate = self
captureController.modalPresentationStyle = .fullScreen
present(captureController, animated: true) {
captureController.startCapture()
}
}
}
extension DocumentCaptureViewController: JaakStampsDelegate {
func jaakStampsDidBecomeReady(_ controller: JaakStampsViewController) {
print("SDK ready for capture")
}
func jaakStamps(_ controller: JaakStampsViewController, didCompleteCapture images: CapturedImages) {
print("Capture completed")
if let frontImage = images.front.fullFrame {
processImage(frontImage, type: "front_full")
}
if let frontCrop = images.front.cropped {
processImage(frontCrop, type: "front_crop")
}
if let backImage = images.back.fullFrame {
processImage(backImage, type: "back_full")
}
if let backCrop = images.back.cropped {
processImage(backCrop, type: "back_crop")
}
controller.dismiss(animated: true)
}
func jaakStamps(_ controller: JaakStampsViewController, didFailWithError error: JaakStampsError) {
print("Error:\ (error.locatedDescription)")
controller.dismiss(animated: true)
}
func jaakStamps(_ controller: JaakStampsViewController, didUpdateStatus status: ComponentStatus) {
// Required method - basic implementation
print("Status actualizado: \(status)")
}
private func processImage(_ image: UIImage, type: String) {
print("Reprocessing image:\ (type)")
// Convert to base64 if necessary
// let base64 = image.jpegData(compressionQuality: 0.8)?.base64EncodedString()
}
}
2.2 SwiftIU (Optional) configuration
import SwiftUI
import JAAKStamps
struct DocumentCaptureView: UIViewControllerRepresentable {
@Binding var isPresented: Bool
@Binding var capturedImages: CapturedImages?
func makeUIViewController(context: Context) -> JaakStampsViewController {
let config = JaakStampsConfig.defaultConfig()
let controller = JaakStampsViewController(config: config)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: JaakStampsViewController, context: Context) {
if isPresented && !uiViewController.isProcessCompleted() {
uiViewController.startCapture()
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, JaakStampsDelegate {
let parent: DocumentCaptureView
init(_ parent: DocumentCaptureView) {
self.parent = parent
}
func jaakStampsDidBecomeReady(_ controller: JaakStampsViewController) {
print("SDK That's it.")
}
func jaakStamps(_ controller: JaakStampsViewController, didCompleteCapture images: CapturedImages) {
DispatchQueue.main.async {
self.parent.capturedImages = images
self.parent.isPresented = false
}
}
func jaakStamps(_ controller: JaakStampsViewController, didFailWithError error: JaakStampsError) {
DispatchQueue.main.async {
self.parent.isPresented = false
}
}
func jaakStamps(_ controller: JaakStampsViewController, didUpdateStatus status: ComponentStatus) {
// Required method - basic implementation
print("Status actualizado: \(status)")
}
}
}
2.3 Use in SwiftIU
struct ContentView: View {
@State private var showCapture = false
@State private var capturedImages: CapturedImages?
var body: some View {
VStack {
Button("Capture document") {
showCapture = true
}
.padding()
if capturedImages != nil {
Text("Captured document")
.foregroundColor(.green)
}
}
.fullScreenCover(isPresented: $showCapture) {
DocumentCaptureView(
isPresented: $showCapture,
capturedImages: $capturedImages
)
}
}
}
Passage 3: Configure Camera Permissions
Objective
Configure camera permissions required by iOS correctly.
3.1 Info.pist
<key>NSCameraUsageDescription</key>
<string>Esta aplicación necesita acceso a la cámara para capturar documentos</string>
3.2 Management of Code Permises
import AVFoundation
class PermissionsManager {
static func checkCameraPermission() -> AVAuthorizationStatus {
return AVCaptureDevice.authorizationStatus(for: .video)
}
static func requestCameraPermission(completion: @escaping (Bool) -> Void) {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.async {
completion(granted)
}
}
}
static func openSettings() {
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl)
}
}
}
3.3 Verification Before Capture
private func setupDocumentCapture() {
let cameraStatus = PermissionsManager.checkCameraPermission()
switch cameraStatus {
case .authorized:
startDocumentCapture()
case .notDetermined:
PermissionsManager.requestCameraPermission { granted in
if granted {
self.startDocumentCapture()
} else {
self.showPermissionAlert()
}
}
case .denied, .restricted:
showPermissionAlert()
@unknown default:
showPermissionAlert()
}
}
private func startDocumentCapture() {
let config = JaakStampsConfig.defaultConfig()
let captureController = JaakStampsViewController(config: config)
captureController.delegate = self
captureController.modalPresentationStyle = .fullScreen
present(captureController, animated: true) {
captureController.startCapture()
}
}
private func showPermissionAlert() {
let alert = UIAlertController(
title: "Camera permits",
message: "Camera access required to capture document",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Configure", style: .default) { _ in
PermissionsManager.openSettings()
})
alert.addAction(UIAlertAction(title: "Cancelar", style: .cancel))
present(alert, animated: true)
}
Step 4: Reg and Images Management
Objective
Implement complete management of the captured images and necessary conversion.
4.1 Full Image Processing
func jaakStamps(_ controller: JaakStampsViewController, didCompleteCapture images: CapturedImages) {
let documentImages = DocumentImages()
// Full front processing
if let frontFull = images.front.fullFrame {
documentImages.frontOriginal = convertToBase64(frontFull)
print("Front Original: \(documentImages.frontOriginal?.count ?? 0) chars")
}
// To process cut face
if let frontCrop = images.front.cropped {
documentImages.frontCrop = convertToBase64(frontCrop)
print("Front Crop: \(documentImages.frontCrop?.count ?? 0) chars")
}
// Reg complete (if available)
if let backFull = images.back.fullFrame {
documentImages.backOriginal = convertToBase64(backFull)
print("Back Original: \(documentImages.backOriginal?.count ?? 0) chars")
}
// Procure cut back (if available)
if let backCrop = images.back.cropped {
documentImages.backCrop = convertToBase64(backCrop)
print("Back Crop: \(documentImages.backCrop?.count ?? 0) chars")
}
// Determine document type
let documentType = images.metadata.backCaptureSkipped ? "single_sided" : "double_sided"
// To process complete document
processCompleteDocument(documentImages, type: documentType, metadata: images.metadata)
controller.dismiss(animated: true)
}
struct DocumentImages {
var frontOriginal: String?
var frontCrop: String?
var backOriginal: String?
var backCrop: String?
}
private func convertToBase64(_ image: UIImage) -> String? {
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return nil }
return imageData.base64EncodedString()
}
private func processCompleteDocument(_ images: DocumentImages, type: String, metadata: CapturedImages.Metadata) {
print("_")
print("Tipo: \(type)")
print("Total images:\ (metadata)")
print("Complete process:\ (methata.ProcesCompleted)")
// Validate that we have at least the front image
guard images.frontOriginal != nil || images.frontCrop != nil else {
print("Error: No valid face images found")
return
}
// Create payload for backend
let payload = createDocumentPayload(images, type: type, metadata: metadata)
// Send to backend or process locally
sendToBackend(payload)
print("Reprocessing document")
}
private func createDocumentPayload(_ images: DocumentImages, type: String, metadata: CapturedImages.Metadata) -> [String: Any] {
return [
"documentType": type,
"timestamp": Date().timeIntervalSince1970,
"version": "1.0.0",
"images": [
"frontOriginal": images.frontOriginal ?? "",
"frontCrop": images.frontCrop ?? "",
"backOriginal": images.backOriginal ?? "",
"backCrop": images.backCrop ?? ""
],
"metadata": [
"totalImages": metadata.totalImages,
"backCaptureSkipped": metadata.backCaptureSkipped,
"processingTime": metadata.processingTime,
"platform": "ios"
]
]
}
private func sendToBackend(_ payload: [String: Any]) {
print("Enviando a backend: \(payload.keys)")
// Implement call to your API
}
4.2 Advanced Errors Management
func jaakStamps(_ controller: JaakStampsViewController, didFailWithError error: JaakStampsError) {
print("Reaping error:\ (error.locatedDescription)")
switch error {
case .cameraPermissionDenied:
handleCameraPermissionError()
case .cameraNotAvailable:
handleCameraError()
case .modelLoadingFailed(let message):
handleMLError(message)
case .captureSessionFailed(let message):
handleCaptureError(message)
case .processingFailed(let message):
handleProcessingError(message)
default:
handleGenericError(error.localizedDescription)
}
controller.dismiss(animated: true)
}
private func handleCameraPermissionError() {
showAlert(
title: "Camera permits",
message: "Access to the camera is required to capture documents. Go to Setup to enable them."
) {
PermissionsManager.openSettings()
}
}
private func handleCameraError() {
showAlert(
title: "Camera error",
message: "The camera was unable to be accessed. Check that it isn't being used by another application."
)
}
private func handleMLError(_ message: String) {
showAlert(
title: "Processing Error",
message: "The model of AI could not be loaded. Reboot the application and try again."
)
}
private func handleCaptureError(_ message: String) {
showAlert(
title: "Capture error",
message: "Error during document capture. Try again."
)
}
private func handleProcessingError(_ message: String) {
showAlert(
title: "Processing Error",
message: "Failed to process the image. Check that the document is well lit."
)
}
private func handleGenericError(_ message: String) {
showAlert(
title: "Error",
message: "Unexpected error happened:\ (message)"
)
}
private func showAlert(title: String, message: String, action: (() -> Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
if let action = action {
alert.addAction(UIAlertAction(title: "Configure", style: .default) { _ in
action()
})
alert.addAction(UIAlertAction(title: "Cancelar", style: .cancel))
} else {
alert.addAction(UIAlertAction(title: "Entendido", style: .default))
}
present(alert, animated: true)
}
Step 5: Test document capture
Objective
Check that all functionalities of SDK They work properly.
checklist
| Element | State | Description |
|---|---|---|
| Camera permits | ☐ | App requests and gets permission |
| Automatic detection | ☐ | AI detects document automatically |
| Imaging | ☐ | Original and face / back crop |
| Basal conversion64 | ☐ | All images become |
| Errors management | ☐ | Mistakes are handled correctly |
Test process
Step A: Test Permissions
- Install Application as a physical device
- Open Application first time
- Check request automatic permits
- Grant permits for camera
Step B: Test Simple Capture
- Press Button Capture
- Position document within the framework
- To expect automatic detection (Green frame)
- Check capture automatic
- Review login to confirm processing
Step C: Test Double face document
- Capture front document
- Following instructions To turn
- Capture Reverse automatically
- Check 4 images at login
- Confirm processing success
Debugging and Troublehooting
Check Unit Compatibility
private func checkDeviceCompatibility() {
print("=== VERIFICANDO COMPATIBILIDAD ===")
let isCompatible = JAAKStampsSDK.isCompatible()
print("SDK compatible: \(isCompatible)")
let coreMLAvailable = JAAKStampsSDK.isCoreMLAvailable()
print("Core ML disponible: \(coreMLAvailable)")
let cameraStatus = PermissionsManager.checkCameraPermission()
print("Camera status:\ (cameraStatus)")
let systemReqs = JAAKStampsSDK.getSystemRequirements()
print("System requirements:\ (systemReqs)")
}
private func enableDebugMode() {
var config = JaakStampsConfig.defaultConfig()
config.debug = true
// Use configuration with activated debug
let captureController = JaakStampsViewController(config: config)
}
Common problems
| Problem | Resolution |
|---|---|
| "SDK Non-compatible " | Check iOS 13.0 + and Core ML available |
| "Camera doesn't start." | Check permits and that are not busy |
| "Non-Loading Model" | Reboot app and check available memory |
| "Capture doesn't work." | Test with physical device, non-simulator |
| "Using Sandboxing Script" | Switch to "No" at Build Settings project |
Full reference
Methods SDK
| Method | Description | Example |
|---|---|---|
| JaakStampsViewController (config:) | Driver's builder | JaakStampsViewController(config: config) |
| stardature () | Initiates capture | controller.startCapture() |
| stopCapture () | Stops capture | controller.stopCapture() |
| preLoadModel (completion:) | ML model | controller.preloadModel { success in } |
Available
| Configure | Description | When to use |
|---|---|---|
| defaultConfig () | Standard configuration | General |
| highAccuracyConfig () | High precision | Complex documents |
| highSpeedConfig () | High Speed | Rapid capture |
Response structure
| Image | Description | When it's generated |
|---|---|---|
| front.fullFrame | Full face image | Always |
| front.cropped | Front cut by AI | When detecting document |
| back.fullFame | Full back image | Only if document requires back |
| back.croped | Reverse cut by AI | When you get back |
Fits
| Method | Description | Example |
|---|---|---|
| JAAKStampsSDK.isCompatible () | Verify compatibility | JAAKStampsSDK.isCompatible() |
| JAAKStamp | Check Core ML | JAAKStampsSDK.isCoreMLAvailable() |
Problem solving
Problem: "ML model error"
// Check before use
if !JAAKStampsSDK.isCoreMLAvailable() {
showAlert(title: "Dispositivo Incompatible",
message: "That device doesn't support Core ML")
return
}
// Recharging model explicitly
captureController.preloadModel { success in
if success {
captureController.startCapture()
} else {
self.showAlert(title: "Error", message: "Can't load model")
}
}
Problem: "Camera doesn't work in simulator"
// It only works on a physical device
#if targetEnvironment(simulator)
showAlert(title: "Simulador",
message: "The capture of documents requires a physical device")
return
#endif
Problem: "Rejected permits"
// Check system configuration
private func checkPermissionStatus() {
let status = AVCaptureDevice.authorizationStatus(for: .video)
if status == .denied {
showAlert(
title: "Permisos Requeridos",
message: "Go to Setup > Privacy > Camera and enabling access for this app"
) {
PermissionsManager.openSettings()
}
}
}
Problem: "Using Sandboxing Failed Script"
// Check project configuration
private func checkBuildSettings() {
#if DEBUG
print("Check Build Settings:")
print("1. Select PROJECT (do not target)")
print("2. Build Settings > User Script Sandboxing = NO")
print("3. Clean Build Folder and Remodel")
#endif
}
Do you need some help?
Support information
- Problem description: What are you trying to do with what's going on?
- Xcode's logs: Screenshots of console errors
- Unit information: IOS model, version, memory
- Podfile Setup: Unit versions
- Type of document: INE, passport, license, etc.
Support Contact
Email: support Always include: IOS logo, configuration, version SDK
You have successfully implemented JAAKStamps SDK your iOS application. Your app can now capture documents automatically using artificial intelligence, generating optimization images for processes KYC.