Complete Manual for Facial Detection and Filling at iOS Applications

Estimated time: 45-60 minutes for complete configuration


What will you learn from this manual?

That manual will teach you how to implement and use JAAKVisage SDK for automated face detection and video recording 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 12.0 + device (physical, non-simulator)
  • Cocoa
  • Basic information about Swift / UIKit
  • Access to a functional camera
  • Facial Test Identification Paper

Contents Index

SectionWhat will you do?Time
Step 1Configure Project and Units10 min
Step 2Basic implementation of SDK20 min
Step 3Configure Camera Permissions10 min
Step 4Record and file management15 min
Step 5Test facial detection10 min

Step 1: Configure Project and Units

Objective

Install JAAKVisage SDK and configure the development environment.

Technical requirements

RequirementVersionMandatory?
Xcode12.0+Yes
iOS12.0+Yes
Swift5.0+Yes
CocoaLastYes
Physical cameraRequiredYes (non-simulator)

1.1 Cocoa-Pods installation

# Instalar CocoaPods si no lo tienes
sudo gem install cocoapods

# Create Podfile in your project
cd /ruta/a/tu/proyecto
pod init

1.2 Podfile configuration

platform :ios, '12.0'

target 'YourApp' do
  use_frameworks!

  # SDK JAAKVisage - Beta Version
  pod 'jaak-visage', '>= 1.0.0-beta.1', '< 1.0.0-dev'
end

1.3 Unit installation

# Run installation
pod install

# Important after installation:
# 1. Close Xcode completely if open
# 2. Open .xcworkspace file (NOT .xcodeproj)
open YourApp.xcworkspace

Configure required for compilation

If you find sandboxing errors at compile The project, deactivated User Sandboxing Script:

  1. Select your target at Xcode
  2. Go to Build Settings
  3. Search "Using Sandboxing Script"
  4. Switch Value To "No"

Step 2: Basic implementation of SDK

Objective

Create JAAKVisage's basic implementation SDK with automatic detection and recording.

2.1 Basic Viewer

import UIKit
import JAAKVisage
import AVKit

class ViewController: UIViewController {
    private var detector: JAAKVisageSDK?
    private var recordedVideos: [RecordedVideo] = []

    // UI Elements
    private var statusLabel: UILabel!
    private var videosTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupDetector()
    }

    private func setupUI() {
        view.backgroundColor = .systemBackground
        title = "Face Detection"

        // Status label
        statusLabel = UILabel()
        statusLabel.text = "Ready to detect face"
        statusLabel.textAlignment = .center
        statusLabel.numberOfLines = 0
        statusLabel.font = .systemFont(ofSize: 16)
        statusLabel.translatesAutoresizingMaskIntoConstraints = false

        // Reinitiation button
        let restartButton = UIButton(type: .system)
        restartButton.setTitle("Reiniciar Detector", for: .normal)
        restartButton.backgroundColor = .systemBlue
        restartButton.setTitleColor(.white, for: .normal)
        restartButton.layer.cornerRadius = 8
        restartButton.translatesAutoresizingMaskIntoConstraints = false
        restartButton.addTarget(self, action: #selector(restartDetector), for: .touchUpInside)

        // Table view for videos
        videosTableView = UITableView()
        videosTableView.delegate = self
        videosTableView.dataSource = self
        videosTableView.register(UITableViewCell.self, forCellReuseIdentifier: "VideoCell")
        videosTableView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(statusLabel)
        view.addSubview(restartButton)
        view.addSubview(videosTableView)

        // Layout constraints
        NSLayoutConstraint.activate([
            statusLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 320),
            statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),

            restartButton.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 16),
            restartButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            restartButton.heightAnchor.constraint(equalToConstant: 44),
            restartButton.widthAnchor.constraint(equalToConstant: 160),

            videosTableView.topAnchor.constraint(equalTo: restartButton.bottomAnchor, constant: 16),
            videosTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            videosTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            videosTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

    private func setupDetector() {
        // 1. Basic configuration
        var config = JAAKVisageConfiguration()
        config.videoDuration = 5.0
        config.disableFaceDetection = false
        config.enableInstructions = true

        // 2. Initiate detector
        detector = JAAKVisageSDK(configuration: config)
        detector?.delegate = self

        // 3. Create preview view
        if let previewView = detector?.createPreviewView() {
            previewView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(previewView)

            NSLayoutConstraint.activate([
                previewView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
                previewView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
                previewView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
                previewView.heightAnchor.constraint(equalToConstant: 300)
            ])

            previewView.layer.cornerRadius = 16
            previewView.clipsToBounds = true
        }

        // 4. Initiate detection
        do {
            try detector?.startDetection()
        } catch {
            print("Error starting detection:\ (error)")
        }
    }

    // MARK: - Actions
    @objc private func restartDetector() {
        do {
            try detector?.restartDetection()
            statusLabel.text = "Reinitiated successfully"
        } catch {
            statusLabel.text = "Failed to reset:\ (error.locatedDescription)"
        }
    }

    // MARK: - Video Playback
    private func playVideo(data: Data, fileName: String) {
        let tempDir = FileManager.default.temporaryDirectory
        let tempURL = tempDir.appendingPathComponent(fileName)

        do {
            try data.write(to: tempURL)
            let player = AVPlayer(url: tempURL)
            let playerController = AVPlayerViewController()
            playerController.player = player

            present(playerController, animated: true) {
                player.play()
            }
        } catch {
            print("Error creating temporary file:\ (error)")
        }
    }
}

// Structure for video engraving
struct RecordedVideo {
    let fileName: String
    let data: Data
    let recordedAt: Date
    let size: Int

    var formattedDate: String {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .medium
        return formatter.string(from: recordedAt)
    }

    var sizeString: String {
        return ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file)
    }
}

// MARK: - JAAKVisageSDKDelegate
extension ViewController: JAAKVisageSDKDelegate {
    func faceDetector(_ detector: JAAKVisageSDK, didUpdateStatus status: JAAKVisageStatus) {
        DispatchQueue.main.async {
            self.statusLabel.text = "Estado: \(status.rawValue)"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didCaptureFile result: JAAKFileResult) {
        DispatchQueue.main.async {
            let video = RecordedVideo(
                fileName: result.fileName ?? "video_\(Date().timeIntervalSince1970).mp4",
                data: result.data,
                recordedAt: Date(),
                size: result.fileSize
            )
            self.recordedVideos.append(video)
            self.videosTableView.reloadData()
            self.statusLabel.text = "Video capturado: \(video.fileName)"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didEncounterError error: JAAKVisageError) {
        DispatchQueue.main.async {
            self.statusLabel.text = "Error:\ (error.locatedDescription)"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didDetectFace message: JAAKFaceDetectionMessage) {
        if message.faceExists && message.correctPosition {
            DispatchQueue.main.async {
                self.statusLabel.text = "Retiring face"
            }
        }
    }
}

// MARK: - UITableView DataSource & Delegate
extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return recordedVideos.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell", for: indexPath)
        let video = recordedVideos[indexPath.row]
        cell.textLabel?.text = video.fileName
        cell.detailTextLabel?.text = "\(video.formattedDate) • \(video.sizeString)"
        cell.accessoryType = .disclosureIndicator
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let video = recordedVideos[indexPath.row]
        playVideo(data: video.data, fileName: video.fileName)
    }
}

2.2 SwiftIU implementation

import SwiftUI
import JAAKVisage
import AVKit

struct ContentView: View {
    @StateObject private var visageManager = VisageManager()

    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                // Detector with Wrapper UIKit
                VisageViewWrapper(manager: visageManager)
                    .frame(height: 400)
                    .clipShape(RoundedRectangle(cornerRadius: 16))
                    .padding(.horizontal)

                // Status
                VStack(spacing: 8) {
                    Text(visageManager.statusMessage)
                        .font(.body)
                        .foregroundColor(.primary)

                    Text("Estado: \(visageManager.currentStatus.rawValue)")
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .padding(.horizontal, 8)
                        .padding(.vertical, 4)
                        .background(Color.blue.opacity(0.1))
                        .cornerRadius(4)
                }
                .padding()
                .background(Color.gray.opacity(0.1))
                .cornerRadius(8)
                .padding(.horizontal)

                // Controles
                Button("Reiniciar Detector") {
                    visageManager.restartDetector()
                }
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)

                // Videos grabados
                if !visageManager.recordedVideos.isEmpty {
                    VStack(alignment: .leading, spacing: 12) {
                        Text("Videos Grabados (\(visageManager.recordedVideos.count))")
                            .font(.headline)
                            .padding(.horizontal)

                        ForEach(visageManager.recordedVideos.reversed()) { video in
                            VideoRowView(video: video)
                                .padding(.horizontal)
                        }
                    }
                    .padding(.bottom)
                }
            }
        }
    }
}

// Simplified Manager with video player
class VisageManager: ObservableObject {
    @Published var statusMessage = "Ready to detect face"
    @Published var currentStatus: JAAKVisageStatus = .notLoaded
    @Published var recordedVideos: [RecordedVideo] = []

    private(set) var configuration: JAAKVisageConfiguration
    private var visageUIView: JAAKVisageUIView?

    init() {
        var config = JAAKVisageConfiguration()
        config.videoDuration = 5.0
        config.disableFaceDetection = false
        config.enableInstructions = true
        self.configuration = config
    }

    func setVisageUIView(_ view: JAAKVisageUIView) {
        self.visageUIView = view
        // Auto-start detection
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            view.startDetection()
        }
    }

    func restartDetector() {
        do {
            try visageUIView?.restartDetector()
            statusMessage = "Reinitiated successfully"
        } catch {
            statusMessage = "Failed to reset:\ (error.locatedDescription)"
        }
    }
}

// Wrapper to use UIKit in SwiftIU
struct VisageViewWrapper: UIViewRepresentable {
    let manager: VisageManager

    func makeUIView(context: Context) -> JAAKVisageUIView {
        let view = JAAKVisageUIView()
        view.backgroundColor = UIColor.black
        manager.setVisageUIView(view)
        return view
    }

    func updateUIView(_ uiView: JAAKVisageUIView, context: Context) {
        if !uiView.isSetup {
            let detector = JAAKVisageSDK(configuration: manager.configuration)
            detector.delegate = manager

            let previewView = detector.createPreviewView()
            uiView.addSubview(previewView)
            previewView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                previewView.topAnchor.constraint(equalTo: uiView.topAnchor),
                previewView.leadingAnchor.constraint(equalTo: uiView.leadingAnchor),
                previewView.trailingAnchor.constraint(equalTo: uiView.trailingAnchor),
                previewView.bottomAnchor.constraint(equalTo: uiView.bottomAnchor)
            ])

            uiView.faceDetector = detector
            uiView.previewView = previewView
            uiView.isSetup = true
        }
    }
}

// Extension of manager as delegate
extension VisageManager: JAAKVisageSDKDelegate {
    func faceDetector(_ detector: JAAKVisageSDK, didUpdateStatus status: JAAKVisageStatus) {
        DispatchQueue.main.async {
            self.currentStatus = status
            self.statusMessage = "Estado: \(status.rawValue)"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didCaptureFile result: JAAKFileResult) {
        DispatchQueue.main.async {
            // Almacenar video grabado
            let video = RecordedVideo(
                fileName: result.fileName ?? "video_\(Date().timeIntervalSince1970).mp4",
                data: result.data,
                recordedAt: Date(),
                size: result.fileSize
            )
            self.recordedVideos.append(video)
            self.statusMessage = "Video capturado: \(result.fileName ?? "desconocido")"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didEncounterError error: JAAKVisageError) {
        DispatchQueue.main.async {
            self.statusMessage = "Error:\ (error.locatedDescription)"
        }
    }

    func faceDetector(_ detector: JAAKVisageSDK, didDetectFace message: JAAKFaceDetectionMessage) {
        if message.faceExists && message.correctPosition {
            DispatchQueue.main.async {
                self.statusMessage = "Retiring face"
            }
        }
    }
}

// Structure for video engraving
struct RecordedVideo: Identifiable {
    let id = UUID()
    let fileName: String
    let data: Data
    let recordedAt: Date
    let size: Int

    var formattedDate: String {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .medium
        return formatter.string(from: recordedAt)
    }

    var sizeString: String {
        return ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file)
    }
}

// Simplified video view
struct VideoRowView: View {
    let video: RecordedVideo
    @State private var showingPlayer = false

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                VStack(alignment: .leading) {
                    Text(video.fileName)
                        .font(.subheadline)
                        .fontWeight(.medium)
                    Text("Size:\ (video .sizeString)")
                        .font(.caption)
                        .foregroundColor(.secondary)
                }

                Spacer()

                Button("Reproducir") {
                    showingPlayer = true
                }
                .font(.caption)
                .foregroundColor(.white)
                .padding(.horizontal, 12)
                .padding(.vertical, 6)
                .background(Color.blue)
                .cornerRadius(6)
            }
            .padding()
            .background(Color(.systemGray6))
            .cornerRadius(8)

            // Basic player
            if showingPlayer {
                if #available(iOS 14.0, *) {
                    SimpleVideoPlayer(videoData: video.data)
                        .frame(height: 200)
                        .cornerRadius(8)
                        .padding()
                }

                Button("Cerrar") {
                    showingPlayer = false
                }
                .font(.caption)
                .foregroundColor(.white)
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(Color.red)
                .cornerRadius(8)
            }
        }
    }
}

@available(iOS 14.0, *)
struct SimpleVideoPlayer: View {
    let videoData: Data
    @State private var player: AVPlayer?

    var body: some View {
        Group {
            if let player = player {
                VideoPlayer(player: player)
                    .cornerRadius(8)
            } else {
                Rectangle()
                    .fill(Color.black)
                    .overlay(
                        ProgressView("Cargando video...")
                            .foregroundColor(.white)
                    )
                    .cornerRadius(8)
            }
        }
        .onAppear {
            setupPlayer()
        }
        .onDisappear {
            cleanup()
        }
    }

    private func setupPlayer() {
        let tempDir = FileManager.default.temporaryDirectory
        let tempURL = tempDir.appendingPathComponent(UUID().uuidString).appendingPathExtension("mp4")

        do {
            try videoData.write(to: tempURL)
            player = AVPlayer(url: tempURL)
        } catch {
            print("Error:\ (error)")
        }
    }

    private func cleanup() {
        player?.pause()
        player = nil
    }
}

Passage 3: Configure Camera Permissions

Objective

Configure camera permissions required by iOS correctly.

3.1 Info.pist

Method 1 - Modern Xcode (recommended):

  1. Select your target at Xcode
  2. Go to the tab "Info"
  3. In "Custom iOS Target Properties," click "+"
  4. Search and select "Privacy - Camera Usage Description"
  5. Add the description: "That application needs access to the camera to detect faces"

Method 2 - Info.pist file (alternative):

<key>NSCameraUsageDescription</key>
<string>Esta aplicación necesita acceso a la cámara para detectar rostros</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 Monitoring Before Detection

private func checkPermissionsAndStart() {
    let cameraStatus = PermissionsManager.checkCameraPermission()

    switch cameraStatus {
    case .authorized:
        startDetection()
    case .notDetermined:
        PermissionsManager.requestCameraPermission { granted in
            if granted {
                self.startDetection()
            } else {
                self.showPermissionAlert()
            }
        }
    case .denied, .restricted:
        showPermissionAlert()
    @unknown default:
        showPermissionAlert()
    }
}

private func showPermissionAlert() {
    let alert = UIAlertController(
        title: "Camera permits",
        message: "Access to camera required for facial detection",
        preferredStyle: .alert
    )

    alert.addAction(UIAlertAction(title: "Configure", style: .default) { _ in
        PermissionsManager.openSettings()
    })

    alert.addAction(UIAlertAction(title: "Cancelar", style: .cancel))

    present(alert, animated: true)
}

Track 4: Record and Archives Management

Objective

Implement complete management of recorded videos and file processing.

4.1 Response architecture

JAAKFileResult:

public struct JAAKFileResult {
    public let data: Data           // Binary information about the video
    public let base64: String       // Video encoded at base64
    public let mimeType: String?    // Tipo MIME (video/mp4)
    public let fileName: String?    // Name of file
    public let fileSize: Int        // File size in bytes
}

4.2 Videos processing

private func processVideoFile(_ fileResult: JAAKFileResult) {
    print("_")
    print("Name: {fileResultWhat's his name? "unknown")")
    print("Size: {fileResult.filesize) bytes")
    print("Tipo MIME: \(fileResult.mimeType ?? "unknown")")

    // Save in local documents
    saveToDocuments(fileResult)

    // Convert to base64 for sending to server
    let base64String = fileResult.base64
    sendToServer(base64String, fileName: fileResult.fileName)
}

private func saveToDocuments(_ fileResult: JAAKFileResult) {
    guard let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        return
    }

    let fileName = fileResult.fileName ?? "face_video_\(Date().timeIntervalSince1970).mp4"
    let fileURL = documentsPath.appendingPathComponent(fileName)

    do {
        try fileResult.data.write(to: fileURL)
        print("Video saved at:\ (filefURL)")
    } catch {
        print("Failed saving video:\ (error)")
    }
}

private func sendToServer(_ base64String: String, fileName: String?) {
    let payload: [String: Any] = [
        "videoData": base64String,
        "fileName": fileName ?? "face_video.mp4",
        "timestamp": Date().timeIntervalSince1970,
        "platform": "ios",
        "sdkVersion": "1.0.0"
    ]

    print("Enviando video al servidor: \(payload.keys)")
    // Implementar llamada HTTP
}

4.3 SDK

JAAKVisageStatus:

public enum JAAKVisageStatus: String, CaseIterable {
    case notLoaded = "not-loaded"
    case loading = "loading"
    case loaded = "loaded"
    case running = "running"
    case recording = "recording"
    case finished = "finished"
    case stopped = "stopped"
    case error = "error"
    case faceDetected = "face-detected"
    case countdown = "countdown"
    case captureComplete = "capture-complete"
    case processingVideo = "processing-video"
    case videoReady = "video-ready"
}

Track 5: Test Facial Detection

Objective

Check that all functionalities of SDK They work properly.

checklist

ElementStateDescription
Camera permits☐App requests and gets permission
Facial detection☐AI detects faces automatically
Automatic registration☐Reforms with face detection
Files generated☐Videos are saved correctly
Errors management☐Mistakes are handled correctly

Test process

Step A: Test Permissions

  1. Install Application as a physical device
  2. Open Application first time
  3. Check request automatic permits
  4. Grant permits for camera

Step B: Test Detection

  1. Press Button "Start"
  2. Position face facing the camera
  3. To expect automatic detection (green overlay)
  4. Check Start automatic recording
  5. Review login to confirm processing

Step C: Test Functionality

  1. Change Camera (front / back)
  2. Stop and Reboot detection
  3. Check Files saved as document
  4. Test at different light conditions
  5. Confirm handling of errors

Debugging and Troublehooting

Check Unit Compatibility

private func checkDeviceCompatibility() {
    print("=== VERIFICANDO COMPATIBILIDAD ===")

    let cameraStatus = PermissionsManager.checkCameraPermission()
    print("Camera status:\ (cameraStatus)")

    let systemVersion = UIDevice.current.systemVersion
    print("IOS version:\ (systemVersion)")

    let deviceModel = UIDevice.current.model
    print("Modelo dispositivo: \(deviceModel)")
}

private func enableDebugMode() {
    var config = configuration!
    config.enableInstructions = true

    // Apply configuration with activated debug
    detector = JAAKVisageSDK(configuration: config)
}

Common problems

ProblemResolution
"Models Do Not Load"Check online and memory available
"Camera doesn't start."Check permits and that are not busy
"No face detectors."Enhance light and face position
"Record Failed"Check available storage space

Full reference

Methods SDK

MethodDescriptionExample
JAAKVisageSDK (configuration:)Building SDKJAAKVisageSDK(configuration: config)
startDetection ()Begins facial detectiontry detector.startDetection()
stopDetection ()Stopped detectiondetector.stopDetection()
restartReboot detectortry detector.restartDetection()
createPreviewView ()Create preview viewdetector.createPreviewView()

Available

ConfigureDescriptionWhen to use
videoRecord duration in secondsFilling as required
FaceDetectionUnable facial detectionFor manual recording
enableInstructionsShow user instructionsFor new users
cameraPositionInitial camera positionas required

Response structure

FieldDescriptionWhen it's generated
dataBinary information about the videoAlways
base64Video encoded at base64To send to server
filesNameSuggested name of fileWhen specified
filesizeFile size in bytesAlways
mimeTypeMIME type of videoAlways (video / mp4)

Problem solving

Problem: "ML model error"

// Check before use
private func preloadModelsIfNeeded() {
    // The models are loaded automatically
    // Check status with delegate
}

private func handleModelLoadingError() {
    statusLabel.text = "Failed with models. Reboot the app."
}

Problem: "Detection doesn't work in simulator"

// It only works on a physical device
#if targetEnvironment(simulator)
    showAlert(title: "Simulador",
              message: "Facial detection requires a physical device")
    return
#endif

Problem: "Videos aren't saved"

// Check storage permits
private func checkStoragePermissions() {
    let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first

    if documentsPath == nil {
        print("Documents cannot be accessed")
        return
    }

    print("Directory available:\ (documentsPath!)")
}

Problem: "compilation error with User Sandboxing Script"

// Building Settings
// 1. Select target
// 2. Build Settings
// 3. Buscar "User Script Sandboxing"
// 4. Cambiar a "No"

Best Practices

Using SDK

  • Lighting: It works best with good front light
  • Distance: face should be about 30 cm from camera
  • Guidance: It works best with focused and vertical face
  • Stability: Avoid abrupt movements during recording

Integration

  • Threading: All callbacks run on the main thread
  • Memory: The SDK automatically manages memory but monitoring use on old devices
  • Cleaning: Implement automatic cleaning of temporary files
  • Lifecycle: Stop detection while pausing the app to preserve battery

Security

  • Permissions: Just require necessary permits (required camera)
  • Data: The videos are processed locally and aren't automatically sent to servers
  • Privacy: To clear the user about using the camera
  • Storage: Do not store videos permanently without explicit consent

Do you need some help?

Support information

  • Problem description: What are you trying to figure out?
  • Xcode's logs: Screenshots of console errors
  • Unit information: IOS model, version, memory
  • Configure SDK: Parameters used
  • Conditions of use: Lighting, distance, direction

Support Contact

Email: support Always include: IOS logo, configuration, version SDK


You have successfully implemented JAAKVisage SDK Your app can now detect faces and record videos automatically using artificial intelligence, generating optimized files for biometric monitoring processes.