-
[iOS/Swift] Firebase A/B Test야매 iOS 2022. 11. 19. 19:05
https://www.google.com/url?sa=i&url=https%3A%2F%2Fproductcoalition.com%2Fare-you-segmenting-your-a-b-test-results-c5512c6def65&psig=AOvVaw2p149FDuNn7dv85-Sq3XtU&ust=1668937149332000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCNjqrMH5ufsCFQAAAAAdAAAAABAM AB 테스트를 하기 위해선 먼저 가설이 필요하다
어떤 변화가 일어났을 때 해당 변화가 실제로 유효한지 그리고 가설에 맞는지 검증해야 될 필요가 있다
그래서 그룹을 나누고 그 그룹들에게 다른 화면을 보여줘서 그에 대한 결과를 얻어낼 수 있다
그룹에 많은 사용자가 있다면 더욱 더 유효한 데이터를 얻을 수 있다
- 외부 요인으로 발생된 이벤트인지 아니면 변경사항으로 발생된 이벤트인지
AB Test
Firebase Analytics는 이벤트 베이스 모델을 사용한다
- 유저가 어떤 동작을 하면 firebase Analytics가 이벤트를 서버에게 보낸다
- 서버는 가공한 이벤트를 바탕으로 콘솔에 그래프로 보여준다
여기서 Remote Config를 사용해 AB 테스트를 진행할 것이기 때문에 원격 구성을 체크한다
기본사항
기본사항에는 이름과 설명을 적어주면 된다
타겟팅
타겟팅은 앱 별로 따로 진행 한다
- 플랫폼마다 유저의 행동이 다를 수 있기 때문
- 그 아래 여러 추가적인 조건을 정할 수 있다 (ex/ 언어)
이 실험에 참가 시킬 유저들의 비율을 정해야 한다. 많은 사람들이 참여한다면 더욱 신뢰적인 데이터를 얻게 된다. 하지만 시도하려는게 지나치게 도전적이면 작은 그룹으로 테스트를 하는 것이 나을 수도 있다
목표
이 실험을 하는 목적 또는 어떤 것을 극대화 하고 싶은지 (ex/ 구독)
변행
각각의 그룹에 맞는 Remote Config 값을 설정해준다
각각의 그룹에서 가끔 빈문자열을 넣기도 하는데 그것은 사용자가 실험에 참여하지 않을 때의 값을 보여달라는 뜻
현재 위에서 작성된 AB 테스트가 제대로 동작하는지 확인하기 위해서 해당 테스트에 테스트 기기를 등록할 수 있다
테스트 기기를 등록하기 위해선 Firebase 설치 인증 토큰이 필요한데 아래의 코드를 통해 얻을 수 있다.
그리고 해당 테스트 기기를 어떤 그룹에 배정할 것인지도 설정할 수 있다.
Installations.installations().authToken { result, _ in print("Fiebase instance ID token is \(result?.authToken ?? "n/a")") }
A/B 테스트 코드
아래의 코드에서 2가지 테스트를 진행하고 있다
1. 버턴의 모양
2. 버튼을 눌렀을 때 어떤 화면으로 넘어갈 것인지
AppDelegate
@main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. FirebaseApp.configure() Installations.installations().authToken { result, _ in print("Fiebase instance ID token is \(result?.authToken ?? "n/a")") } return true } }
RCValue
import UIKit import Firebase enum ValueKey: String { case buttonTitle case buttonCornerRadius case buttonBackgroundColor case buttonTriggeredViewController } final class RCValues { static let sharedInstance = RCValues() var loadingDoneCallback: (() -> Void)? var fetchComplete: Bool? private init() { loadDefaultValue() fetchCloudValues() } private func loadDefaultValue() { let appDefaults: [String: Any?] = [ ValueKey.buttonTitle.rawValue: "Go To Submit", ValueKey.buttonCornerRadius.rawValue: "0.0", ValueKey.buttonBackgroundColor.rawValue: "#126424", ValueKey.buttonTriggeredViewController.rawValue: "ASubmitViewController" ] RemoteConfig.remoteConfig().setDefaults(appDefaults as? [String: NSObject]) } private func fetchCloudValues() { #if DEBUG activateDebugMode() #endif RemoteConfig.remoteConfig().fetch { [weak self] _, error in if let error = error { print("error fetching remote values \(error)") return } RemoteConfig.remoteConfig().activate { [weak self] _, _ in print("remote value fetched") self?.fetchComplete = true self?.loadingDoneCallback?() } } } private func activateDebugMode() { let settings = RemoteConfigSettings() settings.minimumFetchInterval = 0 RemoteConfig.remoteConfig().configSettings = settings } func string(forKey key: ValueKey) -> String { RemoteConfig.remoteConfig()[key.rawValue].stringValue ?? "" } func double(forKey key: ValueKey) -> Double { RemoteConfig.remoteConfig()[key.rawValue].numberValue.doubleValue } func color(forKey key: ValueKey) -> UIColor { let colorAsHexString = RemoteConfig.remoteConfig()[key.rawValue].stringValue ?? "#FFFFFFFF" let convertedColor = UIColor(colorAsHexString) return convertedColor } }
// ViewController
import UIKit import Firebase import SnapKit import Then class ViewController: UIViewController { private lazy var button = UIButton().then { $0.setTitle("Go To Submit", for: .normal) $0.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside) $0.setTitleColor(.black, for: .normal) $0.clipsToBounds = true } override func viewDidLoad() { super.viewDidLoad() render() // Do any additional setup after loading the view. } private func render() { button.layer.cornerRadius = RCValues.sharedInstance.double(forKey: .buttonCornerRadius) button.setTitle(RCValues.sharedInstance.string(forKey: .buttonTitle), for: .normal) button.backgroundColor = RCValues.sharedInstance.color(forKey: .buttonBackgroundColor) view.addSubview(button) view.backgroundColor = .white button.snp.makeConstraints { $0.center.equalToSuperview() } } @objc func buttonPressed() { Analytics.logEvent( "GoToSubmitButtonPressedexch", parameters: nil ) switch RCValues.sharedInstance.string(forKey: .buttonTriggeredViewController) { case "ASubmitViewController": let vc = ASubmitViewController() vc.delegate = self self.present(vc, animated: true) default: self.navigationController?.pushViewController(BSubmitViewController(), animated: true) } } } extension ViewController: ASubmitViewControllerButtonProtocol { func touchedSubmitButton() { self.dismiss(animated: true) self.navigationController?.pushViewController(SubmitResultViewController(), animated: true) } }
'야매 iOS' 카테고리의 다른 글
[iOS/Swift] How to use iOS WidgetKit / 위젯 만들기 (0) 2023.02.19 Inversion of Control (IOC) (1) 2022.12.05 [iOS/Swift] Firebase Event (0) 2022.11.19 [iOS/Swift] Firebase Remote Config (0) 2022.11.19 present한 뷰컨트롤러 dismiss 후 바로 뷰컨트롤러 present (0) 2021.12.25