Petnow LogoPetnow
마이그레이션

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

v1.2.x 통합을 v1.3을 거치지 않고 곧바로 v1.4로 올리는 가이드.

의존성은 곧바로 v1.4로 올리세요 — 중간에 v1.3을 설치할 이유가 없습니다. 이 가이드는 v1.2.x와 v1.4 사이의 모든 코드 변경을 한 곳에 모아 v1.4 API 기준으로만 서술합니다. v1.4가 다시 갈아엎는 v1.3 시절 코드를 잠깐 쓰는 일이 없도록 하기 위해서입니다.

v1.3.x에서 올라오시나요? 더 짧은 SDK v1.3 → v1.4 마이그레이션을 쓰세요. 아직 v1 Server API를 호출한다면 API v1 → v2도 함께 진행하세요.


iOS

1. CameraViewModelCameraController · 라이선스는 생성자로 · captureSessionId 필수

v1.2 시절 패턴 세 가지가 한 번에 바뀝니다: 타입 이름이 바뀌고, 라이선스가 생성자로 이동하며, initializeCamera에 서버가 발급한 captureSessionId (POST /api/capture-sessions)가 필수입니다.

// ❌ v1.2.x
@StateObject private var viewModel: CameraViewModel
try await viewModel.initializeCamera(
    licenseInfo: LicenseInfo(apiKey: "YOUR_API_KEY"),
    initialPosition: .back
) { result in /* ... */ }
CameraView(viewModel: viewModel)

// ✅ v1.4
@StateObject private var controller = CameraController( 
    configuration: DetectionConfiguration(species: .dog, purpose: .petProfileRegistration), 
    licenseInfo: LicenseInfo(apiKey: "YOUR_API_KEY") 
)
let sessionId = try await createCaptureSessionFromServer() // POST /api/capture-sessions
try await controller.initializeCamera(initialPosition: .back, captureSessionId: sessionId) 
CameraView(controller: controller) 

Breaking: captureSessionId 없이는 컴파일되지 않습니다. 카메라 초기화 전에 서버에서 세션 ID를 발급하세요. → Server API

왜: 컨트롤러가 수명 동안 라이선스를 보유하고(검증 1회), initializeCamera는 카메라 연결에만 집중하며, 타입 이름이 Android의 CameraController와 일치합니다. → 시작하기

2. previewLayer 제거 — 프리뷰는 CameraView가 담당

CameraViewModel.previewLayer(v1.2)는 제거됐고, v1.4에서 캡처 세션은 공개 getter가 없지만 — 이니셜라이저로 자체 AVCaptureSession을 주입하면 완전 커스텀 프리뷰는 여전히 가능합니다(커스터마이징 참고). 기본 경로에서는 CameraView가 프리뷰를 담당하며, 준비 상태 확인은 published 프로퍼티 isInitialized를 쓰세요.

// ❌ v1.2.x
if viewModel.previewLayer != nil { showCameraView() }
view.layer.addSublayer(viewModel.previewLayer)

// ✅ v1.4 — 프리뷰는 CameraView가 그리고, 준비 상태는 명시적으로 확인
if controller.isInitialized { showCameraView() } 
CameraView(controller: controller)               

프리뷰 위에 커스텀 UI를 올리려면 CameraView 위에 뷰를 얹으세요 — 커스터마이징 참고.

3. 탐지가 저절로 시작되지 않습니다 — startDetection() 호출

initializeCamera()는 카메라만 연결하고 탐지를 시작하지 않습니다. 반환된 뒤 명시적으로 시작하세요(재촬영도 같은 호출):

try await controller.initializeCamera(initialPosition: .back, captureSessionId: sessionId)
controller.startDetection() 

4. 종료: stopDetection()finalizeCamera()

// ❌ v1.2.x
controller.stopDetection()

// ✅ v1.4
controller.finalizeCamera() 

일시정지/재개는 별도 동사(pauseDetection())를 가져 완전 종료가 항상 명시적입니다.

iOS 변경 요약

v1.2.xv1.4
CameraViewModel / CameraView(viewModel:)CameraController / CameraView(controller:)
initializeCamera(licenseInfo:initialPosition:)생성자 CameraController(configuration:licenseInfo:) + initializeCamera(initialPosition:captureSessionId:)
previewLayer제거 — 프리뷰는 CameraView, 준비 상태는 isInitialized
stopDetection()finalizeCamera(); 탐지 시작은 명시적 startDetection()

Android

1. 전역 PetnowApiClient 소멸 — 라이선스·설정은 세션 단위로 전달

// ❌ v1.2.x (apiClient 모듈이 더 이상 배포되지 않음 — 컴파일 에러)
PetnowApiClient.init(key = "YOUR_API_KEY", isDebugMode = false)
PetnowApiClient.configureDetectionMode(
    purpose = DetectionPurpose.PET_PROFILE_REGISTRATION,
    species = PetSpecies.DOG,
    enableFakeDetection = true
)
  • 권장 (CameraView + CameraController): LicenseInfoCameraController(context, license, scope) 생성자에, DetectionConfigurationinitializeCamera(config, captureSessionId)에 전달합니다. → 기본 사용법
  • 기존 PetnowCameraFragment 유지: 라이선스는 Fragment args(ARG_API_KEY)나 provideLicense()로, 설정은 ARG_DETECTION_CONFIGURATION으로 전달합니다. → Fragment (레거시)

PetnowApiClient.isSuccessInitialize의 대체물은 없습니다 — 초기화 실패는 PetnowUIError로 드러납니다(4번). 설정 타입 패키지가 이동하고(io.petnow.api.client.*io.petnow.ui.config.*, 형태 동일), Android의 isDebugMode는 사라졌습니다.

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

2. captureSessionId 필수

어느 경로든 서버 발급 captureSessionId(POST /api/capture-sessions)가 필수입니다.

// ✅ v1.4 — CameraController 경로
val sessionId = createCaptureSessionFromServer()
controller.initializeCamera(configuration, captureSessionId = sessionId) 

// ✅ v1.4 — Fragment 경로
val fragment = MyCameraFragment().apply {
    arguments = Bundle().apply {
        putString(ARG_CAPTURE_SESSION_ID, sessionId.toString()) 
    }
}

Breaking: captureSessionId 없이는 Fragment가 즉시 종료되고, 컨트롤러 경로는 초기화에 실패합니다.

3. 리스너 import 패키지 변경 — 그리고 V2로

// ❌ v1.2.x
import io.petnow.ui.PetnowCameraDetectionListener

// ✅ v1.4
import io.petnow.callback.PetnowCameraDetectionListenerV2 

CameraController 경로에서는 setDetectionListenerV2를 쓰세요. V2는 iOS와 동일한 결과 모델 — sealed DetectionStatus (NoObject/Processing/Detected/Finished/Failed(reason))와 CameraResult(Success(fingerprintImageFiles, appearanceImageFiles)/Fail) — 를 전달합니다.

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

initializeCamera()가 더 이상 플랫폼 예외를 그대로 던지지 않으며, API 키를 서버에 검증합니다(프로세스당 키별 1회).

// ✅ v1.4 — 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은 여전히 그대로 전파됩니다(정상 수명주기 — 다시 던지세요).

Android 변경 요약

v1.2.xv1.4
PetnowApiClient.init() / configureDetectionMode()세션 단위: CameraController(context, license, scope) + initializeCamera(config, captureSessionId) 또는 Fragment args
PetnowApiClient의 서버 API 헬퍼은퇴 — Server API는 앱 서버에서 호출
세션 ID 없는 FragmentARG_CAPTURE_SESSION_ID 필수
import io.petnow.ui.PetnowCameraDetectionListenerio.petnow.callback.…ListenerV2 (권장)
원시 SecurityException 등 플랫폼 예외sealed PetnowUIError

마이그레이션 체크리스트

공통

  • 서버에서 POST /api/capture-sessionscaptureSessionId 발급

iOS

  • CameraViewModelCameraController; 라이선스를 생성자로
  • 서버 세션 ID로 initializeCamera(initialPosition:captureSessionId:)
  • previewLayer 사용 코드를 CameraView로 교체 (준비 상태는 isInitialized)
  • initializeCamerastartDetection() 호출 · stopDetection()finalizeCamera()

Android

  • PetnowApiClient 호출 제거; 라이선스/설정을 세션 단위로 전달; 서버 API 호출은 앱 서버로 이관
  • captureSessionId 전달 (컨트롤러 인자 또는 ARG_CAPTURE_SESSION_ID)
  • 리스너 import를 io.petnow.callback으로, V2로 이전
  • initializeCamera() 주변을 PetnowUIError catch로 교체

On this page