將 reCAPTCHA 整合至 iOS 應用程式

本頁說明如何在 iOS 應用程式中整合 reCAPTCHA。

由於行動裝置的螢幕大小、效能和應用程式 UI 各有不同,因此 iOS 行動應用程式不支援視覺化核取方塊 reCAPTCHA 驗證問題 (「我不是機器人」)。您可以改為實作自己的分層強制執行策略,例如多重驗證流程,為可疑流量提供替代兌換路徑。

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.8.0-beta01"
        ...
      
      end
      
    3. 執行 pod update 安裝必要的依附元件。

    Swift Package Manager

    1. 在 Xcode 中,依序選取「File」>「Add Packages」,然後在「Search」或「Enter Package URL」欄位中輸入下列網址: https://github.com/GoogleCloudPlatform/recaptcha-enterprise-mobile-sdk
    2. 在「Xcode」對話方塊中,輸入下列詳細資料:

      • GitHub 使用者名稱。
      • 使用 GitHub 的操作說明建立的個人存取權杖。「個人存取權杖」必須具有「XCode Sign In」對話方塊中列出的範圍。

      Xcode 會安裝 SDK 和必要的依附元件。

    Flutter

    如需透過 Flutter 使用 reCAPTCHA 的詳細操作說明,請參閱 Flutter 說明文件

    ReactNative

    如需透過 React Native 使用 reCAPTCHA 的詳細操作說明,請參閱 React Native 說明文件

    直接下載

    1. 如要以 xcframework 形式下載 SDK 和其依附元件,請下載用戶端

設定應用程式

您可以使用 Swift 或 Objective-C 編寫應用程式。

如要設定應用程式,請在應用程式中新增下列檔案:

Swift

  1. 如果應用程式是以 Swift 編寫,請加入下列匯入項目:

     import RecaptchaEnterprise
    

Objective-C

  1. 如果應用程式是以 Objective-C 編寫,請建立虛擬 Swift 檔案,並加入下列匯入項目,確保 Xcode 可以找到並連結 Swift 程式庫。

    import Foundation
    
  2. 如要確保 Swift 程式碼已正確連結,請依序前往「Target」>「Build Settings」>「Always Embed Swift Standard Libraries」,並確認該選項已設為 Yes

將 reCAPTCHA 整合至 iOS 應用程式

如要將 reCAPTCHA 整合至 iOS 應用程式,請在 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
          }
        }
      }
      

    Swift 和 SwiftUI

    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() 呼叫期間。您不應讓 UI 元素封鎖 reCAPTCHA SDK。

  2. 建立按鈕來呼叫 reCAPTCHA 並觸發 execute()

    使用分鏡腳本的 Swift

    1. 在腳本中建立按鈕。
    2. ViewController 中建立與您建立的按鈕相關聯的動作。
    3. 呼叫 execute() 方法並傳遞 Login 動作,即可使用下列程式碼片段傳回 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)
        }
      }
      

    Swift 和 SwiftUI

    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. 呼叫 execute() 方法並傳遞 Login 動作,以回傳 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 的 App Attest 做為偵測引擎的一部分。如果您不打算在本地開發時使用測試金鑰和固定分數,請按照下列步驟操作:

      1. 在 Xcode 中,將 App Attest 功能新增至應用程式。

      2. 在專案的 .entitlements 檔案中,將 App Attest 環境設為 production

    2. 如要清除 Xcode 建構環境,請依序點選「Product」選單中的「Clean Build Folder」

    3. 如要執行應用程式,請在「Product」選單中點選「Run」

    4. 在載入的應用程式中,按一下您先前建立的按鈕。

    5. 觀察偵錯輸出視窗中的 reCAPTCHA 權杖 (英數字串),如果整合成功,系統就會傳回這個權杖。

從方法 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
  }
}

Swift 和 SwiftUI

// 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 參考資料

如需 reCAPTCHA API for iOS 的完整參考資料,請參閱 RecaptchaEnterprise

後續步驟

  • 如要評估 reCAPTCHA 回應權杖,請建立評估