Petnow LogoPetnow
iOS SDK

Sample Code

Common iOS snippets for Petnow SDK usage.


Complete Pet Registration Example

Here's a complete example of implementing pet registration with the Petnow iOS SDK:

import SwiftUI
import PetnowAPI
import PetnowUI

// MARK: - Pet Registration View Model
class PetRegistrationViewModel: ObservableObject {
    @Published var isLoading = false
    @Published var errorMessage: String?
    @Published var registrationSuccess = false
    @Published var registeredPetId: String?

    private let apiClient: PetnowAPIClient

    init(apiClient: PetnowAPIClient) {
        self.apiClient = apiClient
    }

    func registerPet(
        species: PetnowAPIClient.PetSpecies,
        name: String,
        breed: String,
        fingerprintIds: [String],
        appearanceIds: [String]
    ) async {
        isLoading = true
        errorMessage = nil

        do {
            // Configure detection mode
            apiClient.configureDetectionMode(
                purpose: .PET_PROFILE_REGISTRATION,
                species: species
            )

            // Prepare metadata
            let metadata = """
            {
                "name": "\(name)",
                "breed": "\(breed)",
                "registration_date": "\(Date().ISO8601Format())"
            }
            """

            // Register pet
            let petId = try await apiClient.registerPetProfile(
                fingerPrints: fingerprintIds,
                appearances: appearanceIds,
                metadata: metadata,
                species: species
            )

            registeredPetId = petId
            registrationSuccess = true

        } catch {
            errorMessage = "Registration failed: \(error.localizedDescription)"
        }

        isLoading = false
    }
}

// MARK: - Pet Registration View
struct PetRegistrationView: View {
    @StateObject private var viewModel: PetRegistrationViewModel
    @State private var species: PetnowUI.Species = .dog
    @State private var petName = ""
    @State private var petBreed = ""
    @State private var showCamera = false
    @State private var capturedFingerprintUrls: [URL]?
    @State private var capturedAppearanceUrls: [URL]?

    init(apiClient: PetnowAPIClient) {
        _viewModel = StateObject(wrappedValue: PetRegistrationViewModel(apiClient: apiClient))
    }

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Pet Information")) {
                    TextField("Pet Name", text: $petName)
                    TextField("Breed", text: $petBreed)

                    Picker("Species", selection: $species) {
                        Text("Dog").tag(PetnowUI.Species.dog)
                        Text("Cat").tag(PetnowUI.Species.cat)
                    }
                }

                Section {
                    Button("Capture Biometric Data") {
                        showCamera = true
                    }
                    .disabled(petName.isEmpty || petBreed.isEmpty)
                }

                if let errorMessage = viewModel.errorMessage {
                    Section {
                        Text(errorMessage)
                            .foregroundColor(.red)
                    }
                }

                if viewModel.registrationSuccess {
                    Section {
                        Text("Pet registered successfully!")
                            .foregroundColor(.green)
                        if let petId = viewModel.registeredPetId {
                            Text("Pet ID: \(petId)")
                                .font(.caption)
                        }
                    }
                }
            }
            .navigationTitle("Register Pet")
            .sheet(isPresented: $showCamera) {
                CameraCaptureView(
                    species: species,
                    onCapture: { fingerprintUrls, appearanceUrls in
                        capturedFingerprintUrls = fingerprintUrls
                        capturedAppearanceUrls = appearanceUrls
                        uploadAndRegister()
                    }
                )
            }
        }
    }

    private func uploadAndRegister() {
        guard let fingerprintUrls = capturedFingerprintUrls,
              let appearanceUrls = capturedAppearanceUrls else { return }

        Task {
            // Upload fingerprints
            var fingerprintIds: [String] = []
            for url in fingerprintUrls {
                let imageData = try Data(contentsOf: url)
                let biometricId = try await viewModel.apiClient.uploadFingerPrints(
                    fileData: imageData,
                    fileName: url.lastPathComponent,
                    species: species == .dog ? .DOG : .CAT,
                    purpose: .PET_PROFILE_REGISTRATION
                )
                fingerprintIds.append(biometricId.id)
            }

            // Upload appearances
            var appearanceIds: [String] = []
            for url in appearanceUrls {
                let imageData = try Data(contentsOf: url)
                let biometricId = try await viewModel.apiClient.uploadAppearances(
                    fileData: imageData,
                    fileName: url.lastPathComponent,
                    species: species == .dog ? .DOG : .CAT,
                    purpose: .PET_PROFILE_REGISTRATION
                )
                appearanceIds.append(biometricId.id)
            }

            // Register pet
            await viewModel.registerPet(
                species: species == .dog ? .DOG : .CAT,
                name: petName,
                breed: petBreed,
                fingerprintIds: fingerprintIds,
                appearanceIds: appearanceIds
            )
        }
    }
}

// MARK: - Camera Capture View
struct CameraCaptureView: View {
    let species: PetnowUI.Species
    let onCapture: ([URL], [URL]) -> Void

    @StateObject private var cameraViewModel: CameraViewModel
    @Environment(\.dismiss) var dismiss

    init(species: PetnowUI.Species, onCapture: @escaping ([URL], [URL]) -> Void) {
        self.species = species
        self.onCapture = onCapture
        _cameraViewModel = StateObject(wrappedValue: CameraViewModel(
            species: species,
            cameraPurpose: .forRegisterFromProfile
        ))
    }

    var body: some View {
        NavigationView {
            ZStack {
                CameraView(viewModel: cameraViewModel)
                    .edgesIgnoringSafeArea(.all)

                VStack {
                    Text("Position your pet in the frame")
                        .foregroundColor(.white)
                        .padding()
                        .background(Color.black.opacity(0.7))

                    Spacer()

                    Text("Progress: \(cameraViewModel.currentDetectionProgress)%")
                        .foregroundColor(.white)
                        .padding()
                        .background(Color.black.opacity(0.7))
                }
            }
            .navigationTitle("Capture")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
            .task {
                do {
                    try await cameraViewModel.initializeCamera(
                        licenseInfo: LicenseInfo(
                            apiKey: "YOUR_API_KEY",
                            isDebugMode: true
                        ),
                        initialPosition: .back
                    ) { result in
                        handleCameraResult(result)
                    }
                } catch {
                    print("Camera initialization failed: \(error)")
                    dismiss()
                }
            }
        }
    }

    private func handleCameraResult(_ result: CameraResult) {
        switch result {
        case .success(let fingerprintImages, let appearanceImages):
            onCapture(fingerprintImages, appearanceImages)
        case .fail:
            print("Capture failed")
        }
        dismiss()
    }
}

// MARK: - App Entry Point
@main
struct PetRegistrationApp: App {
    let apiClient = PetnowAPIClient(
        apiKey: "YOUR_API_KEY",
        isDebugMode: true
    )

    var body: some Scene {
        WindowGroup {
            PetRegistrationView(apiClient: apiClient)
        }
    }
}

Error Handling Example

// Comprehensive error handling
func performPetOperation(apiClient: PetnowAPIClient) async {
    do {
        // Check server status first
        let status = try await apiClient.checkServerStatus()
        print("Server status: \(status.status)")

        // Configure detection mode
        apiClient.configureDetectionMode(
            purpose: .PET_PROFILE_REGISTRATION,
            species: .DOG
        )

        // Your pet operation here
        let pets = try await apiClient.getPetnowPets()
        print("Found \(pets.count) pets")

    } catch PetnowSDKError.notInitialized {
        print("❌ SDK not initialized")
    } catch PetnowSDKError.invalidApiKey {
        print("❌ Invalid API key")
    } catch PetnowSDKError.clientError(let statusCode, let errorResponse) {
        print("❌ Client error: \(statusCode)")
        if let errors = errorResponse?.errors {
            for error in errors {
                print("  - \(error.code)")
            }
        }
    } catch PetnowSDKError.serverError(let statusCode, _) {
        print("❌ Server error: \(statusCode)")
    } catch {
        print("❌ Unexpected error: \(error.localizedDescription)")
    }
}

Camera Integration with UIKit

import UIKit
import SwiftUI
import PetnowUI

class CameraViewController: UIViewController {
    private var hostingController: UIHostingController<CameraView>?
    private let species: PetnowUI.Species
    private let cameraPurpose: PetnowUI.CameraPurpose

    init(species: PetnowUI.Species, cameraPurpose: PetnowUI.CameraPurpose) {
        self.species = species
        self.cameraPurpose = cameraPurpose
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupCamera()
    }

    private func setupCamera() {
        let cameraViewModel = CameraViewModel(
            species: species,
            cameraPurpose: cameraPurpose
        )

        let cameraView = CameraView(viewModel: cameraViewModel)
        hostingController = UIHostingController(rootView: cameraView)

        guard let hostingController = hostingController else { return }

        addChild(hostingController)
        view.addSubview(hostingController.view)
        hostingController.view.frame = view.bounds
        hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        hostingController.didMove(toParent: self)

        // Initialize camera
        Task {
            do {
                try await cameraViewModel.initializeCamera(
                    licenseInfo: LicenseInfo(
                        apiKey: "YOUR_API_KEY",
                        isDebugMode: true
                    ),
                    initialPosition: .back
                ) { [weak self] result in
                    DispatchQueue.main.async {
                        self?.handleCameraResult(result)
                    }
                }
            } catch {
                print("Camera initialization failed: \(error)")
            }
        }
    }

    private func handleCameraResult(_ result: CameraResult) {
        switch result {
        case .success(let fingerprintImages, let appearanceImages):
            print("Captured \(fingerprintImages.count) fingerprints and \(appearanceImages.count) appearances")
            // Process captured images
        case .fail:
            print("Camera capture failed")
        }

        // Dismiss or navigate to next screen
        dismiss(animated: true)
    }
}

Best Practices

  1. Initialize SDK Early: Initialize the API client in your AppDelegate or main app structure
  2. Handle Permissions: Request camera permissions before using camera features
  3. Error Handling: Always wrap API calls in do-catch blocks
  4. Memory Management: Clean up camera resources when not needed
  5. User Feedback: Provide clear feedback during biometric capture process
  6. Testing: Test with both debug and production environments