Petnow LogoPetnow
마이그레이션

SDK v1.3 → v1.4 마이그레이션

기존 v1.3.x 앱을 v1.4.0으로 업그레이드하는 변경점별 가이드.

기존 v1.3.x 통합을 v1.4.0으로 올릴 때 필요한 코드 변경을 플랫폼별로 정리합니다.

v1.2.x에서 올라오시나요? 이 페이지 대신 직행 SDK v1.2 → v1.4 마이그레이션을 쓰세요 — 중간 v1.3 시절 코드 없이 모든 변경을 한 번에 다룹니다.

iOS: 대부분의 기존 공개 심볼은 deprecated 별칭으로 유지되어 일반적인 앱은 경고와 함께 빌드됩니다. 다만 별칭 없이 제거·숨김된 심볼이 소수 있으며(아래 별칭 없이 제거된 항목 참고), 해당 심볼을 쓰던 앱은 표의 대체 경로가 필요합니다.
Android: 전역 진입점 PetnowApiClient(apiClient 모듈)가 더 이상 배포되지 않아 코드 변경이 필요합니다.

v1.4의 변경은 크게 두 가지를 위한 것입니다 — ① iOS/Android 공개 API 통일(CameraController·DetectionConfiguration/DetectionPurpose·DetectionStatus/CameraResult 등을 양 플랫폼에서 같은 모양으로), ② 세션 수명주기를 명료한 API로 제어(start/pause/resume/finalize를 분리된 동사로). 아래 각 항목의 가 이 둘 중 어디에 해당하는지 보여줍니다.


iOS

1. CameraViewModelCameraController

// v1.3.x (deprecated)
@StateObject private var viewModel: CameraViewModel
CameraView(viewModel: viewModel)

// v1.4.0
@StateObject private var controller: CameraController 
CameraView(controller: controller)                    

CameraViewModelCameraController의 deprecated typealias입니다. CameraView(viewModel:)CameraView(controller:)로 변경하세요.

왜: 이 타입은 단순 뷰모델이 아니라 라이선스·검출 명령을 소유하는 컨트롤러입니다. 개명으로 역할이 분명해지고 Android CameraController와 네이밍이 정렬됩니다. → 기본 사용법

2. 라이선스를 생성자로 이동

라이선스를 initializeCamera(licenseInfo:)로 전달하던 방식은 deprecated입니다. 생성자에 licenseInfo를 주입하고, initializeCamera는 license 인자 없이 호출하세요.

// v1.3.x (deprecated)
let controller = CameraController(species: .dog, cameraPurpose: .forRegisterFromProfile)
try await controller.initializeCamera(
    licenseInfo: LicenseInfo(apiKey: "YOUR_API_KEY"),
    initialPosition: .back,
    captureSessionId: sessionId
)

// v1.4.0
let controller = CameraController( 
    configuration: DetectionConfiguration(species: .dog, purpose: .petProfileRegistration), 
    licenseInfo: LicenseInfo(apiKey: "YOUR_API_KEY") 
)
try await controller.initializeCamera(initialPosition: .back, captureSessionId: sessionId) 
controller.startDetection() 

initializeCamera는 탐지를 시작하지 않습니다 — 반환된 뒤 startDetection()을 명시적으로 호출하세요(Android와 동일).

왜: 라이선스를 컨트롤러 수명 동안 한 번만 주입하면 initializeCamera는 카메라·세션 연결에만 집중하고, 매 호출마다 키를 다시 넘길 필요가 없습니다. 라이선스 검증도 1회로 단순해집니다(Android도 동일 구조). → 시작하기

3. teardown: stopDetection()finalizeCamera()

// v1.3.x (deprecated)
controller.stopDetection()

// v1.4.0
controller.finalizeCamera() 

왜: 캡처/검출 세션의 수명주기를 더 명료한 API로 제어하도록 바뀌었습니다. 기존 stopDetection()검출 중지카메라 종료를 한 메서드에 뒤섞었지만, v1.4는 동사를 분리합니다 — 시작 startDetection(), 일시정지/재개 pauseDetection(), 완전 종료 finalizeCamera(). 각 단계가 분명해 의도치 않은 전체 teardown을 막습니다. → 기본 사용법

4. 별칭 없이 제거된 항목

대부분은 deprecated 별칭으로 이전되지만, 아래 v1.3 멤버는 제거·숨김되어 표의 대체 경로가 필요합니다:

v1.4에서 제거됨대체
captureSession (원시 AVCaptureSession getter)getter 없음 — 프리뷰는 CameraView가 담당. 완전 커스텀 프리뷰는 CameraController(configuration:licenseInfo:captureSession:)으로 자체 세션 주입 → 커스터마이징
cameraPermissionStatus권한 처리는 호스트 앱 소유 — AVCaptureDevice.authorizationStatus(for: .video)로 직접 확인/요청
currentCameraPosition내부 전환 상태 — 앱의 switchCamera() 호출 기준으로 UI 관리
LicenseInfo(apiKey:isDebugMode:)isDebugMode 제거 — SDK는 무조건 프로덕션을 바라봅니다. LicenseInfo(apiKey:)를 쓰세요. isDebugMode:를 넘기던 호출부는 인자를 제거해야 합니다.

iOS 변경 요약

v1.3.xv1.4.0
CameraViewModelCameraController
CameraView(viewModel:)CameraView(controller:)
initializeCamera(licenseInfo:…)생성자 CameraController(configuration:licenseInfo:) + initializeCamera(initialPosition:captureSessionId:)
stopDetection()finalizeCamera() (탐지 시작은 명시적 startDetection())
captureSession / cameraPermissionStatus / currentCameraPosition제거/숨김 — 별칭 없이 제거된 항목 참고

자세한 사용법은 기본 사용법을 참고하세요.


Android

v1.4에서 전역 진입점 PetnowApiClient(apiClient 모듈)가 SDK에서 빠졌습니다. 라이선스·탐지 설정이 세션 단위 전달로 바뀌고, 모듈의 서버 API 헬퍼도 사라지므로 코드 변경이 필요합니다.

1. 전역 PetnowApiClient init/설정 → 세션 단위 전달

// v1.3.x (apiClient 모듈이 더 이상 배포되지 않음 — 컴파일 에러)
PetnowApiClient.init(key = "YOUR_API_KEY", isDebugMode = false)
PetnowApiClient.configureDetectionMode(
    purpose = DetectionPurpose.PET_PROFILE_REGISTRATION,
    species = PetSpecies.DOG,
    enableFakeDetection = true
)
  • 권장(CameraView + CameraController): LicenseInfo(apiKey)CameraController(context, license, scope) 생성자에, DetectionConfigurationinitializeCamera(config, captureSessionId)에 전달합니다. → 기본 사용법
  • 기존 PetnowCameraFragment 유지: 라이선스를 Fragment args(ARG_API_KEY) 또는 provideLicense()로, 설정을 ARG_DETECTION_CONFIGURATION으로 전달합니다. → Fragment 방식(레거시)
  • 설정 타입의 패키지가 이동합니다: io.petnow.api.client.{DetectionConfiguration, DetectionPurpose, PetSpecies}io.petnow.ui.config.* (형태 동일).
  • PetnowApiClient.isSuccessInitialize의 대체물은 없습니다 — 초기화 실패는 이제 initializeCamera()의 구조화된 PetnowUIError로 드러납니다(4번 항목).
  • Android의 isDebugMode는 사라졌습니다: SDK는 무조건 프로덕션을 바라봅니다.

PetnowApiClient로 Petnow Server API를 호출했다면(캡처 세션 생성, 비문 업로드, 등록): 해당 헬퍼는 이동한 게 아니라 모듈과 함께 은퇴했습니다. 대신 앱 서버에서 Server API를 호출하세요 — v1.4 클라이언트 SDK는 촬영만 담당합니다.

왜: 전역 싱글톤은 앱 전체가 하나의 가변 설정을 공유해, 세션마다 다른 설정·독립 생명주기·테스트가 어려웠습니다. 세션 단위 전달은 전역 상태를 없애고, 서버 호출을 클라이언트 밖으로 옮겨 API 키를 제자리(앱 서버)에 둡니다.

2. 리스너 import 패키지 변경

// v1.3.x
import io.petnow.ui.PetnowCameraDetectionListener

// v1.4.0
import io.petnow.callback.PetnowCameraDetectionListener      
// V2: import io.petnow.callback.PetnowCameraDetectionListenerV2

왜: 콜백 공개 API를 전용 io.petnow.callback 패키지로 분리한 것뿐입니다. 동작 변화는 없고 import 경로만 바뀝니다. → 기본 사용법

3. (권장) V2 리스너로 이전

CameraController 경로에서는 setDetectionListenerV2(V2)를 사용합니다. V2는 DetectionStatus(sealed: NoObject/Processing/Detected/Finished/Failed(reason))와 CameraResult(Success(fingerprintImageFiles, appearanceImageFiles)/Fail)를 전달합니다.

왜: V1은 플랫폼별 레거시 모델을 주지만, V2는 iOS와 동일한 결과 모델을 줍니다 — 타입 안전 sealed DetectionStatus와 이미지 파일 목록을 담은 CameraResult. 크로스플랫폼 일관성과 더 풍부한 결과를 얻습니다. → 기본 사용법

4. 초기화 실패가 구조화된 PetnowUIError

v1.3.x에서는 initializeCamera() 실패가 플랫폼 예외 그대로 새어나왔습니다(권한 누락 시 SecurityException, 카메라 오류 시 camera2 예외 등). v1.4.0은 모든 초기화 실패를 sealed class io.petnow.ui.PetnowUIError로 던집니다. 또한 v1.4.0부터 initializeCamera()가 API 키를 서버에서 검증하므로(프로세스당 키별 1회), 거부된 키는 PetnowUIError.InvalidLicense로 실패합니다.

// v1.3.x — 플랫폼 예외를 개별 catch
try {
    controller.initializeCamera(configuration, captureSessionId)
} catch (e: SecurityException) { /* 권한 누락 */ }
  catch (e: Exception) { /* 기타 초기화 오류 */ }

// v1.4.0 — 단일 catch + sealed when
try {
    controller.initializeCamera(configuration, captureSessionId)
} catch (e: PetnowUIError) {                                
    when (e) {
        is PetnowUIError.InvalidLicense -> { /* API 키 거부 */ }
        is PetnowUIError.PermissionDenied -> { /* 권한 누락 */ }
        is PetnowUIError.CameraOpenFailed -> { /* 카메라 오류 — 원인은 e.cause */ }
    }
}

CancellationException은 그대로 전파됩니다(정상 생명주기 — 재던지세요).

왜: catch (e: PetnowUIError) 하나로 모든 초기화 실패를 받고, sealed when이 케이스 누락을 컴파일 타임에 막아줍니다. 케이스 이름이 iOS PetnowUIError(invalidLicense/permissionDenied)와 같아 두 플랫폼의 에러 처리 코드가 나란히 정렬됩니다. 원본 플랫폼 예외는 cause로 보존됩니다. → 기본 사용법 — 에러 처리

Android 변경 요약

v1.3.xv1.4.0
PetnowApiClient.init()LicenseInfo + CameraController(context, license, scope) 또는 Fragment args/provideLicense()
PetnowApiClient.configureDetectionMode()initializeCamera(config, captureSessionId) 또는 ARG_DETECTION_CONFIGURATION
PetnowApiClient.isSuccessInitialize제거 — 실패는 PetnowUIError로 드러남
PetnowApiClient의 서버 API 헬퍼은퇴 — Server API는 앱 서버에서 호출
import io.petnow.ui.PetnowCameraDetectionListenerimport io.petnow.callback.PetnowCameraDetectionListener
initializeCamera() 실패 시 SecurityException 등 플랫폼 예외sealed PetnowUIError(InvalidLicense/PermissionDenied/CameraOpenFailed)

자세한 내용은 기본 사용법Fragment 방식(레거시)을 참고하세요.


마이그레이션 체크리스트

iOS

  • CameraViewModelCameraController, CameraView(viewModel:)(controller:)
  • 라이선스를 생성자(CameraController(configuration:licenseInfo:))로 이동, initializeCamera에서 license 인자 제거
  • stopDetection()finalizeCamera(); initializeCamerastartDetection() 호출
  • captureSession/cameraPermissionStatus/currentCameraPosition 사용처 교체 (별칭 없이 제거된 항목 참고)

Android

  • PetnowApiClient 호출 제거 → 세션 단위 라이선스/설정 전달; 서버 API 호출은 앱 서버로 이관
  • 리스너 import를 io.petnow.callback으로 변경
  • (권장) CameraView + CameraController + V2 리스너로 이전
  • initializeCamera()SecurityException/일반 예외 catch를 PetnowUIError catch(+when)로 교체

On this page