--- title: iOS / macOS SDK --- # iOS / macOS SDK Apple 플랫폼 SDK. **iOS 15+** 및 Mac Catalyst 기반 **macOS 11+ (Big Sur)** 를 지원하며, `.xcframework` 와 로컬라이즈된 리소스 `.bundle` 로 배포됩니다. SwiftUI / UIKit / AppKit 프로젝트에 바로 통합할 수 있습니다. ## GitHub 데모 ::: tip 📦 [Captcha-La/iosmacos-demo](https://github.com/Captcha-La/iosmacos-demo) — 모든 통합 단계가 포함된 실행 가능한 예제. ::: ## 설치 `Podfile`에 CaptchaLa를 추가하세요 (CocoaPods 1.10+): ```ruby # Podfile platform :ios, '13.0' target 'YourApp' do use_frameworks! pod 'Captchala', '~> 1.0.2' end ``` ```bash pod install ``` 수동 통합을 선호한다면: Download the latest iOS release from the [CaptchaLa dashboard](https://dash.captcha.la). The archive contains: - `Captchala.xcframework` — the compiled SDK - `Captchala.bundle` — localized resources Drop both next to your `.xcodeproj`. The demo project references them by file name; no manual linking is needed beyond keeping their location stable. 수동 통합 시 xcframework를 직접 다운로드하세요: [dash.captcha.la/downloads](https://dash.captcha.la/downloads) ```text YourApp/ ├── YourApp.xcodeproj ├── YourApp/ ├── Captchala.xcframework └── Captchala.bundle ``` Open the project and run on the simulator, a device, or **My Mac (Mac Catalyst)**: ```bash open YourApp.xcodeproj # Cmd-R in Xcode ``` ## 빠른 시작 ```swift import SwiftUI import Captchala final class CaptchaDelegateBridge: NSObject, CaptchalaDelegate { var onSuccess: ((CaptchalaResult) -> Void)? var onFailure: ((CaptchalaError) -> Void)? var onClose: (() -> Void)? func captcha(didSucceedWith result: CaptchalaResult) { onSuccess?(result) } func captcha(didFailWithError error: CaptchalaError) { onFailure?(error) } func captchaDidClose() { onClose?() } } struct LoginView: View { @State private var bridge = CaptchaDelegateBridge() @State private var status = "Tap to verify" var body: some View { Button("Verify with CAPTCHA", action: startVerify) Text(status).font(.caption) } private func startVerify() { bridge.onSuccess = { r in // Send r.passToken to your backend for validation. status = "OK: \(r.passToken)" } bridge.onFailure = { e in status = "ERROR [\(e.code)] \(e.message)" } Task { @MainActor in // 1. Fetch a one-shot server_token from YOUR backend. let token = await fetchServerTokenFromYourBackend() // 2. Build config and present. let config = CaptchalaConfigBuilder() .appKey("YOUR_APP_KEY") .action("login") .lang("en") // en, zh-CN, zh-TW, ja, ko, ms, vi, id .theme("light") // "light" | "dark" .enableVoice(true) .enableOfflineMode(true) .serverToken(token) .onServerTokenExpired { await fetchServerTokenFromYourBackend() } .build() guard let presenter = topViewController() else { return } CaptchalaClient.shared .initialize(config: config) .setDelegate(bridge) .verify(from: presenter) } } } ``` ::: tip Mac Catalyst & native macOS The exact same Swift code runs on iOS, Mac Catalyst, and native macOS. On Catalyst pass any `UIViewController`. On native macOS use `NSViewController` and call `.verify()` without an argument — the SDK presents in its own `NSWindow`. ::: ## 주요 API | 심볼 | 용도 | | --- | --- | | `CaptchalaClient.shared` | 공유 싱글턴. 모든 진입점이 여기서 시작합니다. | | `CaptchalaConfigBuilder()` | `appKey`, `action`, `lang`, `theme`, `enableVoice`, `enableOfflineMode`, `serverToken` 을 설정하는 빌더. | | `initialize(config:)` | 빌드된 설정을 적용합니다. `self` 를 반환해 `setDelegate` 를 체이닝할 수 있습니다. | | `setDelegate(_:)` | `CaptchalaDelegate` 를 채택한 `NSObject` 를 전달합니다. SDK 는 약한 참조로 보관합니다. | | `verify(from: presenter)` | 지정한 UIViewController(iOS / Catalyst) 위에 CAPTCHA 를 모달 시트로 표시합니다. | | `CaptchalaResult` | `captcha(didSucceedWith:)` 콜백으로 반환됩니다. 필드: `passToken`, `challengeId`, `ttl`, `isOffline`, `isClientOnly`. | | `onServerTokenExpired { … }` | 챌린지 중 기존 `server_token` 이 만료되면 새 토큰을 가져오는 비동기 클로저. | ## 서버 측 검증 `result.passToken`(또는 `result.token`)을 백엔드로 전달하고 CaptchaLa API로 검증합니다. **`X-App-Secret`을 클라이언트 코드에 노출하지 마세요**. ```bash POST https://apiv1.captcha.la/v1/validate X-App-Key: YOUR_APP_KEY X-App-Secret: YOUR_APP_SECRET Content-Type: application/json { "pass_token": "" } ``` 전체 검증 엔드포인트와 `X-App-Key` / `X-App-Secret` 흐름은 [API 레퍼런스](../api-reference)를 참고하세요. ## 문제 해결 - **`Captchala.xcframework` 를 찾을 수 없음** `.xcframework` 와 `.bundle` 은 `Example.xcodeproj` 와 같은 위치에 두세요. 데모는 파일명으로 참조하므로 SDK 업데이트 시 경로를 바꾸지 마세요. - **Mac Catalyst destination 이 보이지 않음** Xcode 에서 타깃의 *Supported Destinations* 에 *Mac (Mac Catalyst)* 을 활성화하세요. 데모는 `SUPPORTS_MACCATALYST = YES` 입니다. - **모달이 나타나지 않음** `verify(from:)` 에 실제 `UIViewController` 를 전달하세요. 데모는 `UIApplication.connectedScenes` 를 순회해 최상단 key-window 컨트롤러를 얻습니다 — SwiftUI `View` 만 있다면 이 헬퍼를 복사하세요. - **macOS 에서 `Info.plist` 개인정보 문구 필요** Catalyst / 네이티브 macOS 타깃에서는 **Outgoing Connections (Client)** 샌드박스 권한을 활성화하세요. SDK 는 HTTPS 호출만 하며 마이크/카메라에 접근하지 않습니다. ## 요구 사항 - iOS 15+ (device or simulator) - macOS 11+ (Big Sur) via Mac Catalyst, macOS 13+ for native targets - Xcode 15+ - Swift 5.7+ (async/await)