Firebase 원격 구성을 사용하여 Firebase 앱 체크 점진적 출시

1. 소개

App Attest와 함께 Firebase 앱 체크를 사용하여 백엔드 서비스를 보호하고 Firebase 서비스에 대한 요청이 실제 앱에서 오는 것인지 확인할 수 있습니다.

할당량 한도에 도달하지 않도록 사용자를 App Attest 서비스에 점진적으로 온보딩하는 것이 좋습니다. 자세한 내용은 Apple의 'App Attest Service 사용 준비' 문서를 참조하세요.

'단계적 버전 업데이트 출시'에 설명된 대로 Apple의 App Store Connect 기능을 사용하여 점진적으로 앱 업데이트를 출시하는 기능을 사용하면 앱 체크 출시가 더 순조롭게 진행될 수 있습니다. 이 방법은 간단하고 간단합니다. 하지만 앱 버전 업데이트를 단계적으로 출시하면 새로운 앱 버전을 게시하지 않고 업데이트된 기존 앱의 출시를 제어하거나 동작을 변경할 수 없습니다.

App Attest로 앱 체크 출시를 더 효과적으로 제어하는 한 가지 방법은 Firebase 원격 구성을 사용하여 App Attest로 앱 체크를 사용하여 한 번에 일부 앱 사용자에 대해 앱 체크를 사용 설정하는 것입니다. 이렇게 하면 증명 서버에서 제한을 방지하는 데 도움이 될 수 있습니다. Google 애널리틱스를 사용하여 출시가 사용자에게 미치는 영향을 관찰할 수 있습니다.

학습 내용

이 여러 단계로 구성된 Codelab에서는 Firebase 원격 구성을 사용하여 앱에 앱 체크를 출시하는 방법을 알아봅니다.

이 Codelab에서는 Apple 플랫폼용 Firebase 앱 체크 Codelab에 설명된 대로 DatabaseExample 빠른 시작 앱을 기반으로 Firebase 앱 체크와 통합된 Firebase 프로젝트를 사용합니다. DatabaseExample 빠른 시작 앱을 통해 사용자는 Firebase 실시간 데이터베이스의 기능을 사용하여 로그인하고 게시물을 추가할 수 있습니다.

이 Codelab의 단계를 조정하여 자체 앱을 테스트할 수도 있습니다.

기본 요건

필요한 항목

  • Xcode 12.5 이상
  • App Attest 테스트의 경우:
    • 새 앱 식별자를 만들 수 있는 Apple 개발자 계정
    • App Attest 기능이 사용 설정된 명시적 앱 ID가 있는 애플리케이션 프로세스와 관련하여 도움이 필요한 경우 앱 ID 등록앱 기능 사용 설정 도움말을 참고하세요.
    • App Attest를 지원하는 iOS/iPadOS 기기
  • 다음을 포함하는 Firebase 프로젝트:
  • 원격 구성을 생성 및 관리하고 Google 애널리틱스를 볼 수 있는 권한이 있는 앱의 연결된 Firebase 프로젝트에 대한 액세스 권한입니다.

2. 커스텀 증명 제공업체 만들기

이 단계에서는 App Attest가 사용 설정된 경우에만 토큰을 제공하는 커스텀 제공자 클래스를 만듭니다. 원격 구성은 구성된 Firebase 앱 인스턴스를 활용하며, 이 단계에서 구현하는 커스텀 제공업체는 구성을 완료하기 위한 자리표시자 역할을 합니다.

다음 단계를 완료하려면 Xcode에서 앱의 프레임워크, 라이브러리 및 삽입된 콘텐츠 섹션Firebase, FirebaseRemoteConfig, FirebaseAnalytics를 추가해야 합니다. 실행 방법의 예시는 Apple 플랫폼용 Firebase 앱 체크 Codelab을 참고하세요.

  1. AppCheckProvider 프로토콜을 준수하는 NSObject의 서브클래스인 'MyAppCheckProvider' 파일을 만듭니다.
  2. 나중에 작성할 빈 getToken() 메서드를 포함합니다.

getToken() 메서드가 있는 맞춤 제공자 클래스에 관한 다음 코드 예를 참고하세요.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

AppAttestProvider를 인스턴스화하려면 상응하는 FirebaseApp의 인스턴스를 전달해야 합니다. 저장된 속성을 만들고 이니셜라이저 매개변수로 허용합니다.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {}
}

App Attest 제공업체에 토큰 요청 전달

이제 getToken() 메서드에서 토큰 요청을 App Attest 제공자로 전달할 준비가 되었습니다.

참고: FirebaseAppCheck 프레임워크 참조에서 getToken() 메서드에 대해 자세히 알아보세요.

getToken() 메서드에 다음 코드를 추가합니다.

// MyAppCheckProvider.swift

import Firebase
import FirebaseAnalytics
import FirebaseAppCheck
import FirebaseRemoteConfig

class MyAppCheckProvider: NSObject, AppCheckProvider {
  // Firebase app instance served by the provider.
  let firebaseApp: FirebaseApp

  // The App Check provider factory should pass the FirebaseApp instance.
  init(app: FirebaseApp) {
    self.firebaseApp = app
    super.init()
  }

  private lazy var appAttestProvider = AppAttestProvider(app: firebaseApp)

  func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
    // Fetch App Attest flag from Remote Config
    let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
    remoteConfig.fetchAndActivate { remoteConfigStatus, error in
      // Get App Attest flag value
      let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

      guard appAttestEnabled else {
        // Skip attestation if App Attest is disabled. Another attestation
        // method like DeviceCheck may be used instead of just skipping.
        handler(nil, MyProviderError.appAttestIsDisabled)
        return
      }

      // Try to obtain an App Attest provider instance and fail if cannot
      guard let appAttestProvider = self.appAttestProvider else {
        handler(nil, MyProviderError.appAttestIsUnavailable)
        return
      }

      // If App Attest is enabled for the app instance, then forward the
      // Firebase App Check token request to the App Attest provider
      appAttestProvider.getToken(completion: handler)
    }
  }
}

enum MyProviderError: Error {
  case appAttestIsDisabled
  case appAttestIsUnavailable
  case unexpected(code: Int)
}

이전 코드는 원격 구성 AppAttestEnabled 불리언 매개변수를 확인합니다 (이 원격 구성 매개변수는 Codelab 후반부에서 생성됨). 값이 false이면 코드가 실패하여 앱 체크가 현재 기기에 출시되지 않았음을 나타냅니다. 값이 true이면 코드가 App Attest 제공자를 가져오려고 하지만 가져올 수 없으면 실패합니다. 이러한 오류 검사를 통과하면 코드는 토큰 요청을 App Attest 제공업체에 전달합니다.

애널리틱스 이벤트 추가

애널리틱스 이벤트를 추가하면 앱 체크 출시가 얼마나 성공적인지 더 잘 파악할 수 있습니다. 애널리틱스는 더 많은 잠재고객을 대상으로 App Attest를 사용 설정해야 하는지 결정하는 데 도움이 됩니다.

두 가지 애널리틱스 이벤트(성공 시 AppAttestSuccess, 실패 시 AppAttestFailure)를 로깅합니다. 이 두 가지 애널리틱스 이벤트는 앱 체크 출시의 성공을 추적하고 더 큰 출시를 진행해야 하는지 결정하는 데 도움이 됩니다.

func getToken(completion handler: @escaping (AppCheckToken?, Error?) -> Void) {
  // Fetch Remote Config.
  let remoteConfig = RemoteConfig.remoteConfig(app: firebaseApp)
  remoteConfig.fetchAndActivate { remoteConfigStatus, error in
    // Get App Attest flag value from Remote Config.
    let appAttestEnabled = remoteConfig.configValue(forKey: "AppAttestEnabled").boolValue

    guard appAttestEnabled else {
      // Skip attestation if App Attest is disabled. Another attestation
      // method like DeviceCheck may be used instead of just skipping.
      handler(nil, MyProviderError.appAttestIsDisabled)
      return
    }

    // Try to obtain an App Attest provider instance and fail otherwise.
    guard let appAttestProvider = self.appAttestProvider else {
      handler(nil, MyProviderError.appAttestIsUnavailable)
      return
    }

    // If App Attest is enabled for the app instance, then forward the
    // Firebase App Check token request to the App Attest provider.
    appAttestProvider.getToken { token, error in
      // Log an Analytics event to track attestation success rate.
      let appAttestEvent: String
      if (token != nil && error == nil) {
        appAttestEvent = "AppAttestSuccess"
      } else {
        appAttestEvent = "AppAttestFailure"
      }
      Analytics.logEvent(appAttestEvent, parameters: nil)

      // Pass the result to the handler
      handler(token, error)
    }
  }
}

3. 제공자 팩토리 클래스 업데이트

토큰 요청을 App Attest 제공자로 전달하는 로직을 구현하고 애널리틱스 이벤트를 몇 개 추가한 후에는 Apple 플랫폼용 앱 체크 Codelab에서 만든 MyAppCheckProviderFactory.class를 업데이트해야 합니다. 이 클래스는 시뮬레이터를 위한 앱 체크 디버그 제공자를 타겟팅하며, 그 외의 경우에는 커스텀 제공자를 타겟팅합니다.

Apple 플랫폼용 Firebase 앱 체크 Codelab에서 만든 MyAppCheckProviderFactory 클래스에서 다음 코드를 수정합니다.

// MyAppCheckProviderFactory.swift

import Firebase

class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
  func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
      #if targetEnvironment(simulator)
      // App Attest is not available on simulators.
      // Use a debug provider.
      let provider = AppCheckDebugProvider(app: app)

      // Print only locally generated token to avoid a valid token leak on CI.
      print("Firebase App Check debug token: \(provider?.localDebugToken() ?? "" )")

      return provider
      #else
      if #available(iOS 14.0, *) {
        // Use your custom App Attest provider on real devices.
        return MyAppCheckProvider(app: app)
      } else {
        return DeviceCheckProvider(app: app)
      }
      #endif
  }
}

FirebaseApp를 구성하기 전에 AppCheckProviderFactory를 설정했는지 확인합니다.

// DatabaseExampleApp.swift

import SwiftUI
import Firebase
import FirebaseAppCheck

@main
struct DatabaseExampleApp: App {
  init() {
    AppCheck.setAppCheckProviderFactory(MyAppCheckProviderFactory())
    FirebaseApp.configure()
  }

  // ...
}

4. Firebase Console에서 원격 구성 매개변수 추가

이제 Firebase Console에 원격 구성 매개변수 AppAttestEnabled를 추가합니다 . getToken 메서드에 이 매개변수가 필요합니다.

Firebase Console에서 원격 구성 매개변수를 만드는 방법은 다음과 같습니다.

  1. 프로젝트의 원격 구성을 열고 매개변수 추가를 클릭합니다. 원격 구성을 처음 사용하는 경우 구성 만들기를 클릭합니다.
  2. 매개변수 이름 (키) 필드에 AppAttestEnabled를 입력합니다.
  3. 데이터 유형 드롭다운에서 부울을 선택합니다.
  4. 기본값 드롭다운에서 false를 선택합니다.

Firebase Console에서 원격 구성 매개변수 만들기

'저장'을 클릭하기 전에 10% 의 사용자를 위한 조건부 값을 만듭니다.

  1. 새로 추가 > 조건부 값 > 새 조건 만들기를 클릭합니다.
  2. 이름 필드에 조건 이름을 입력합니다.
  3. 적용 조건...에서 임의 백분위수의 사용자, <=를 선택한 후 % 필드에 10을 입력합니다.
  4. 조건 만들기를 클릭합니다.

Firebase Console에서 원격 구성 조건 정의

App Attest가 사용자의 10% 에게 배포되도록 조건부 값을 true로 설정합니다.

  1. 방금 만든 조건의 값을 true로 설정합니다.
  2. 저장을 클릭합니다.

Firebase Console에서 원격 구성 매개변수 검토

완료되면 원격 구성 변경사항을 게시합니다.

기기에서 출시 테스트

앱 코드를 수정하지 않고 기기에서 다양한 원격 구성 플래그 값을 테스트하려면 A/B 테스팅으로 Firebase 원격 구성 실험 만들기 튜토리얼에 따라 AppAttestEnabled 매개변수에 대한 실험을 구성합니다. 튜토리얼 섹션 '테스트 기기에서 실험 유효성 검사'에서는 테스트 기기에 다른 값을 할당하는 방법을 설명합니다.

마지막 단계는 Google 애널리틱스를 사용하여 App Attest 출시의 성공을 모니터링하는 것입니다.

5. AppCheck 출시 성공 검토

애널리틱스 이벤트 대시보드에서 출시 성공을 측정할 수 있습니다. AppAttestSuccessAppAttestFailure 이벤트를 확인합니다. 대시보드에 이벤트가 표시되는 데 최대 24시간이 걸릴 수 있습니다. 또는 디버깅을 사용 설정하고 DebugView를 사용하여 디버그 이벤트를 더 빠르게 확인할 수도 있습니다.

원하는 경우 Crashlytics 대시보드에서 비정상 종료 발생률의 증가를 모니터링할 수 있습니다. 앱에 Crashlytics를 추가하는 방법에 대한 자세한 내용은 Firebase Crashlytics 시작하기를 참조하세요.

대부분 AppAttestSuccess 이벤트와 AppAttestFailure 이벤트가 거의 표시되지 않으면 원격 구성 매개변수 AppAttestEnabled에서 조건을 수정하여 App Attest를 사용 설정한 사용자의 비율을 높일 수 있다는 좋은 신호입니다.

Firebase Console에서 애널리틱스 이벤트 검토

선택사항: Google 애널리틱스 잠재고객 활용

AppAttestEnabled 애널리틱스 이벤트를 더 활용하려면 애널리틱스 잠재고객을 만들어 AppAttestEnabled를 true로 설정한 사용자를 추적할 수 있습니다.

App Attest는 iOS 14.0과 함께 출시되었습니다. 일부 사용자는 이 버전을 사용하지 않을 수 있으므로 App Attest를 사용할 수 없습니다. 다른 애널리틱스 이벤트를 기록하여 이러한 사용자를 추적한 다음 DeviceCheck와 같은 다른 증명 방법으로 해당 잠재고객을 타겟팅할 수 있습니다.

선택사항: Crashlytics를 사용하여 비정상 종료 모니터링

출시 중 앱의 안정성을 더 잘 이해하려면 Firebase Crashlytics를 사용하여 비정상 종료 및 심각하지 않은 오류를 모니터링하세요.

6. 수고하셨습니다

원격 구성으로 앱 체크가 출시되었습니다. 🎉

추가 리소스: