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