reCAPTCHA를 iOS 앱과 통합

이 페이지에서는 iOS 앱에 reCAPTCHA를 통합하는 방법을 설명합니다.

휴대기기의 화면 크기, 성능, 앱의 UI 면에서 차이가 있으므로 iOS 모바일 앱에서는 시각적 체크박스 reCAPTCHA 테스트(로봇이 아닙니다)를 사용할 수 없습니다. 대신 MFA 흐름과 같은 자체 계층별 시행 전략을 구현하여 의심스러운 트래픽에 대한 대체 사용 경로를 제공할 수 있습니다.

SDK는 리플렉션 및 동적 코드를 사용하여 이미 배포된 애플리케이션나 SDK에 있는 감지 시스템을 업데이트하고 조정할 수 있습니다. 애플리케이션에 대한 간섭이 방지되도록 시스템에서 사용 가능한 클래스 세트는 신중하게 제어된 목록으로 제한됩니다.

시작하기 전에

  1. 앱의 최소 SDK를 iOS 12로 설정하거나 새 모바일 앱을 만듭니다.

  2. reCAPTCHA 환경을 준비합니다.

  3. iOS 앱 플랫폼의 reCAPTCHA 키를 만듭니다.

    또는 다음 단계 중 하나를 수행하여 iOS용 기존 reCAPTCHA 키의 ID를 복사할 수 있습니다.

    • Google Cloud 콘솔에서 기존 키의 ID를 복사하려면 다음을 수행합니다.

      1. reCAPTCHA 페이지로 이동합니다.

        reCAPTCHA로 이동

      2. reCAPTCHA 키 목록에서 복사할 키 위에 마우스 포인터를 올려놓고 를 클릭합니다.
    • REST API를 사용하여 기존 키의 ID를 복사하려면 projects.keys.list 메서드를 사용합니다.
    • gcloud CLI를 사용하여 기존 키의 ID를 복사하려면 gcloud recaptcha keys list 명령어를 사용합니다.

  4. GitHub 계정이 있습니다.

  5. Apple 개인 정보 보호 세부정보를 읽어보세요.

iOS 환경 준비

개발 환경을 준비하려면 다음 안내를 따르세요.

  1. Xcode 최신 버전을 다운로드하여 설치하고 빈 iOS 단일 뷰 애플리케이션을 새로 만듭니다.

  2. 다음 중 하나를 사용하여 SDK를 다운로드합니다.

    CocoaPods

    1. CocoaPods를 다운로드하여 설치합니다.
    2. Podfile을 만들고 다음 줄을 Podfile에 추가합니다.

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'AppTarget' do
      
        # Podfiles must include use_frameworks! or
        # use_frameworks! :linkage => :static
        use_frameworks!
      
        pod "RecaptchaEnterprise", "18.6.0"
        ...
      
      end
      
    3. pod update를 실행하여 필수 종속 항목을 설치합니다.

    Swift 패키지 관리자

    1. Xcode에서 파일 > 패키지 추가를 선택하고 검색 또는 패키지 URL 입력 필드에 https://github.com/GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk URL을 입력합니다.
    2. Xcode 대화상자에 다음 세부정보를 입력합니다.

      • GitHub 사용자 이름
      • GitHub의 안내를 사용하여 만든 개인 액세스 토큰. 개인 액세스 토큰에는 XCode 로그인 대화상자에 나열된 범위가 있어야 합니다.

      Xcode는 SDK 및 필요한 종속 항목을 설치합니다.

    Flutter

    Flutter를 통해 reCAPTCHA를 사용하는 방법에 대한 자세한 내용은 Flutter 문서를 참조하세요.

    ReactNative

    React Native를 통해 reCAPTCHA를 사용하는 방법에 대한 자세한 내용은 React Native 문서를 참조하세요.

    직접 다운로드

    1. SDK 및 해당 종속 항목을 xcframework로 다운로드하려면 클라이언트를 다운로드합니다.

앱 구성

Swift 또는 Objective-C로 앱을 작성할 수 있습니다.

앱을 구성하려면 앱에 다음 파일을 추가합니다.

Swift

  1. 앱이 Swift로 작성된 경우 다음 가져오기를 포함합니다.

     import RecaptchaEnterprise
    

Objective-C

  1. 앱이 Objective-C로 작성된 경우 더미 Swift 파일을 만들고 Xcode가 Swift 라이브러리를 찾아서 연결할 수 있도록 다음의 가져오기를 포함합니다.

    import Foundation
    
  2. 그러기 위해서는Swift 코드가 올바르게 연결되었습니다. 목표> 빌드 설정> 항상 Swift 표준 라이브러리 삽입 및 옵션이 다음과 같이 Yes 로 설정되어 있는지 확인합니다.

iOS 앱과 reCAPTCHA 통합

iOS 앱에 reCAPTCHA를 통합하려면 Xcode에서 다음 단계를 따르세요.

  1. 생성된 reCAPTCHA 키(KEY_ID)로 SDK를 인스턴스화하려면 다음 코드를 사용하여 앱을 업데이트합니다.

    스토리보드를 사용한 Swift

    1. ViewController.swift을 업데이트합니다.

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Task {
            do {
              self.recaptchaClient = try await Recaptcha.fetchClient(withSiteKey: "KEY_ID")
            } catch let error as RecaptchaError {
               print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
            }
          }
        }
      }
      

      애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Recaptcha.fetchClient(withSiteKey: "KEY_ID") { client, error in
            guard let client = client else {
                print("RecaptchaClient creation error: \(error).")
              return
            }
            self.recaptchaClient = client
          }
        }
      }
      

    SwiftUI를 사용한 Swift

    1. ViewModel 클래스를 만듭니다.

      import RecaptchaEnterprise
      
      @MainActor class ViewModel: ObservableObject {
        private var recaptchaClient: RecaptchaClient?
      
        init() {
           Task {
            do {
              self.recaptchaClient = try await Recaptcha.fetchClient(withSiteKey: "KEY_ID")
            } catch let error as RecaptchaError {
               print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
            }
          }
        }
      }
      

      애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

      import RecaptchaEnterprise
      
      class ViewController: UIViewController {
        var recaptchaClient: RecaptchaClient?
      
        override func viewDidLoad() {
          super.viewDidLoad()
          Recaptcha.fetchClient(withSiteKey: "KEY_ID") { client, error in
            guard let client = client else {
                print("RecaptchaClient creation error: \(error).")
              return
            }
            self.recaptchaClient = client
          }
        }
      }
      
    2. ContentView.swift에서 ViewModel을 인스턴스화합니다.

      import SwiftUI
      import RecaptchaEnterprise
      
      struct ContentView: View {
        @StateObject private var viewModel = ViewModel()
      
        var body: some View {
        }
      }
      
      struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
          ContentView()
        }
      }
      

    Objective-C

    1. ViewController.h를 업데이트합니다.

      #import <RecaptchaEnterprise/RecaptchaEnterprise.h>
      
      @interface ViewController : UIViewController
      @property (strong, atomic) RecaptchaClient *recaptchaClient;
      @end
      
    2. ViewController.m를 업데이트합니다.

      @implementation ViewController
      [Recaptcha fetchClientWithSiteKey:@"KEY_ID"
            completion:^void(RecaptchaClient* recaptchaClient, NSError* error) {
              if (!recaptchaClient) {
                NSLog(@"%@", (RecaptchaError *)error.errorMessage);
                return;
              }
              self->_recaptchaClient = recaptchaClient;
            }
      ];
      @end
      

    SDK 초기화는 완료되는 데 몇 초 정도 걸릴 수 있습니다. 이 지연 시간을 완화하려면 커스텀 Application 클래스의 onCreate() 호출 중에 클라이언트를 최대한 일찍 초기화합니다. reCAPTCHA SDK에서 UI 요소를 차단해서는 안 됩니다.

  2. reCAPTCHA를 호출하고 execute()를 트리거하는 버튼을 만듭니다.

    스토리보드를 사용한 Swift

    1. 스토리보드에서 버튼을 만듭니다.
    2. 만든 버튼에 연결된 ViewController에서 작업을 만듭니다.
    3. 다음의 코드 스니펫을 사용하여 Login 작업을 전달하는 execute() 메서드를 호출하여 reCAPTCHA 토큰을 반환합니다.

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      Task {
        do {
          let token = try await recaptchaClient.execute(withAction: RecaptchaAction.login)
          print(token)
        } catch let error as RecaptchaError {
          print(error.errorMessage)
        }
      }
      

      애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      recaptchaClient.execute(withAction: RecaptchaAction.login) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
      

    SwiftUI를 사용한 Swift

    1. 다음 실행 코드를 사용하여 ViewModel.swift를 업데이트합니다.

      import RecaptchaEnterprise
      
      @MainActor class ViewModel: ObservableObject {
      
        func execute() {
          guard let recaptchaClient = self.recaptchaClient else {
            print("Client not initialized correctly.")
            return
          }
      
          Task {
            do {
              let token = try await recaptchaClient.execute(withAction: RecaptchaAction.login)
              print(token)
            } catch let error as RecaptchaError {
              print(error.errorMessage)
            }
          }
        }
      }
      

      애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

      guard let recaptchaClient = recaptchaClient else {
        print("RecaptchaClient creation failed.")
        return
      }
      recaptchaClient.execute(withAction: RecaptchaAction.login) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
      
    2. ContentView.swift를 업데이트합니다.

      import SwiftUI
      import RecaptchaEnterprise
      
      struct ContentView: View {
        @StateObject private var viewModel = ViewModel()
      
        var body: some View {
      
          Button {
            viewModel.execute()
          } label: {
            Text("Execute")
          }.padding()
      
          Spacer()
        }
      }
      
      struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
          ContentView()
        }
      }
      

    Objective-C

    1. 스토리보드에서 버튼을 만듭니다.
    2. 만든 버튼에 연결된 ViewController에서 작업을 만듭니다.
    3. Login 작업을 전달하는 execute() 메서드를 호출하여 reCAPTCHA 토큰을 반환합니다.

      if (!self->_recaptchaClient) {
        return;
      }
      
      [recaptchaClient execute:RecaptchaAction.login
          completion:^void(NSString* _Nullable  token, NSError* _Nullable error) {
        if (!token) {
          NSLog (@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        NSLog (@"%@", token);
      }];
      

    느린 네트워킹 환경 또는 백그라운드 초기화가 완료될 때까지 기다리는 경우와 같이 클라이언트의 execute API가 완료되는 데 몇 초가 걸릴 수 있습니다. execute() 호출이 버튼 누르기와 같은 UI 이벤트를 차단하지 않는지 확인합니다.

  3. 애플리케이션을 테스트합니다.

    1. reCAPTCHA는 감지 엔진의 일부로 Apple의 AppAttest를 사용합니다. 로컬 개발 점수가 고정되어 있는 테스트 키를 사용하지 않으려면 다음을 수행합니다.

      1. Xcode에서 App Attest 기능을 앱에 추가합니다.

      2. 프로젝트의 .entitlements 파일에서 App Attest 환경을 production으로 설정합니다.

    2. Xcode 빌드 환경을 삭제하려면 제품 메뉴에서 빌드 폴더 정리를 클릭합니다.

    3. 애플리케이션을 실행하려면 제품 메뉴에서 실행을 클릭합니다.

    4. 로드된 애플리케이션에서 앞에서 만든 버튼을 클릭합니다.

    5. 통합에 성공하면 반환되는 reCAPTCHA 토큰(알파벳-숫자 문자열)의 디버그 출력 창을 관찰합니다.

method API에서 fetchClient 메서드로 마이그레이션

fetchClient 메서드는 네트워크 오류가 발생하면 초기화를 재시도하는 RecaptchaClient를 반환합니다. 클라이언트가 생성될 때 앱에서 네트워크에 액세스할 수 없으면 클라이언트는 계속해서 재시도하고 네트워크에 액세스하면 성공적으로 초기화합니다.

execute(timeout)를 호출했지만 클라이언트가 아직 준비되지 않은 경우 토큰이나 RecaptchaErrorCode를 반환하기 전에 초기화하려고 시도합니다.

다음 예시에서는 getClient에서 fetchClient로 마이그레이션하는 방법을 보여줍니다.

스토리보드를 사용한 Swift

// Migrate from getClient
func initializeWithGetClient() {
  Task {
    do {
      self.recaptchaClient = try await Recaptcha.getClient(withSiteKey: "KEY_ID")
    } catch let error as RecaptchaError {
        print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
    }
  }
}

// Migrate to fetchClient
func initializeWithFetchClient() {
  Task {
    do {
      self.recaptchaClient = try await Recaptcha.fetchClient(withSiteKey: "KEY_ID")
    } catch let error as RecaptchaError {
        print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
    }
  }
}

애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

// Migrate from getClient
override func initializeWithGetClient() {
  Recaptcha.getClient(withSiteKey: "KEY_ID") { client, error in
    guard let client = client else {
        print("RecaptchaClient creation error: \(error).")
      return
    }
    self.recaptchaClient = client
  }
}

// Migrate to fetchClient
override func initializeWithFetchClient() {
  Recaptcha.fetchClient(withSiteKey: "KEY_ID") { client, error in
    guard let client = client else {
        print("RecaptchaClient creation error: \(error).")
      return
    }
    self.recaptchaClient = client
  }
}

SwiftUI를 사용한 Swift

// Migrate from getClient
initializeWithGetClient() {
    Task {
    do {
      self.recaptchaClient = try await Recaptcha.getClient(withSiteKey: "KEY_ID")
    } catch let error as RecaptchaError {
        print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
    }
  }
}

// Migrate to fetchClient
initializeWithFetchClient() {
    Task {
    do {
      self.recaptchaClient = try await Recaptcha.fetchClient(withSiteKey: "KEY_ID")
    } catch let error as RecaptchaError {
        print("RecaptchaClient creation error: \(String(describing: error.errorMessage)).")
    }
  }
}

애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

// Migrate from getClient
func initializeWithGetClient() {
  super.viewDidLoad()
  Recaptcha.getClient(withSiteKey: "KEY_ID") { client, error in
    guard let client = client else {
        print("RecaptchaClient creation error: \(error).")
      return
    }
    self.recaptchaClient = client
  }
}

// Migrate to fetchClient
func initializeWithFetchClient() {
  super.viewDidLoad()
  Recaptcha.fetchClient(withSiteKey: "KEY_ID") { client, error in
    guard let client = client else {
        print("RecaptchaClient creation error: \(error).")
      return
    }
    self.recaptchaClient = client
  }
}

Objective-C

// Migrate from getClient
@implementation ViewController
[Recaptcha getClientWithSiteKey:@"KEY_ID"
      completion:^void(RecaptchaClient* recaptchaClient, NSError* error) {
        if (!recaptchaClient) {
          NSLog(@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        self->_recaptchaClient = recaptchaClient;
      }
];
@end

// Migrate to fetchClient
@implementation ViewController
[Recaptcha fetchClientWithSiteKey:@"KEY_ID"
      completion:^void(RecaptchaClient* recaptchaClient, NSError* error) {
        if (!recaptchaClient) {
          NSLog(@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        self->_recaptchaClient = recaptchaClient;
      }
];
@end

API 호출 제한 시간 설정

withTimeout 속성을 사용하여 execute API의 제한 시간 값을 지정할 수 있습니다.

Swift

  1. execute 호출 시 제한 시간을 설정합니다.

      Task {
        do {
          let token = try await recaptchaClient.execute(
            withAction: RecaptchaAction.login,
            withTimeout: 10000)
          print(token)
        } catch let error as RecaptchaError {
          print(error.errorMessage)
        }
      }
    

    애플리케이션의 최소 OS 버전이 13 미만이면 후행 클로저를 대신 사용합니다.

      recaptchaClient.execute(
        withAction: RecaptchaAction.login,
        withTimeout: 10000
      ) { token, error in
        if let token = token {
          print(token)
        } else {
          print(error)
        }
      }
    

Objective-C

  1. execute 호출 시 제한 시간을 설정합니다.

      [recaptchaClient execute:RecaptchaAction.login
          witTimeout:10000.0
          completion:^void(NSString* _Nullable  token, NSError* _Nullable error) {
        if (!token) {
          NSLog (@"%@", (RecaptchaError *)error.errorMessage);
          return;
        }
        NSLog (@"%@", token);
      }];
    

오류 처리

앱이 reCAPTCHA 서비스와 통신할 수 없으면 API에 오류가 발생한 것일 수 있습니다. 이러한 오류를 정상적으로 처리하는 로직을 앱에 추가해야 합니다.

일반적인 API 오류의 완화에 대한 자세한 내용은 RecaptchaErrorCode를 참조하세요.

API 참조

iOS용 reCAPTCHA API의 전체 참조는 RecaptchaEnterprise를 참조하세요.

다음 단계

  • reCAPTCHA 응답 토큰을 평가하려면 평가를 만듭니다.