앱에 새로 출시할 기능이 상당히 실험적이고 도전적이라 '어떤 비즈니스 이펙트를 가져올지 예상할 수 없을 때' 어떤 선택을 할 수 있을까요? 여기서 전제는 '앱 배포'이기 때문에 되돌리거나 새로운 변경사항으로 바꾸고 싶으면 기존 방식으로는 길고 긴 심사를 다시 거쳐야한다는 것입니다.
- 점진 배포하기
- Server-Driven 방식으로 분기처리 하기
- 그냥 다시 배포하고 기도하기(?)

3가지 방식 모두 장단점이 있지만, 오늘은 그 중에서도 가장 적은 리소스로 가장 빠르게 프론트에서 적용할 수 있는 방식인 Firebase Remote Config 방식에 대해 정리해보겠습니다.
Firebase Remote Config?

이름에서도 알 수 있듯 원격 제어 설정을 도와주는 친구입니다.(Firebase,,, 대체 얼마나 해주는거야!!) 공식 개발자 문서에 따르면 아래와 같은 기능을 도입할 수 있다고 해요.
- 앱 사용자 층에 변경사항을 빠르게 출시: 파라미터 값을 원격으로 바꿔 앱 내 변화.
- 사용자층의 특정 세그먼트에 앱 맞춤설정: GA 세그먼트를 기준으로 다양한 사용자 환경 제공 가능.
- 타겟팅 및 점진 배포, 커스텀 이벤트 측정, A/B 테스트 설정 등등...
원격으로 값을 바꿔줄 수 있기 때문에 Server-Driven 방식처럼 분기 처리로 배포와 상관 없이 앱 내 변화를 줄 수 있게 됩니다. 이렇게 좋은 기능이 있었는데,,, 왜 작년엔 서버 없다고 3번 방식(기도 메타)만 사용했는지 모르겠네요.
일단 한번 해보기(빠른 시작 가이드)
기본적으로 프로젝트 내 Firebase 세팅이 되어있다는 걸 기준으로 정리해보겠습니다.(안했다면 요 공식 문서를!) 또 Remote Config 사용을 위해선 Google Analytics 사용 설정도 필수이기 때문에 이 친구 또한 되어 있어야 합니다.(안했다면 요 공식 문서를!)
자 우선 어떤 값을 원격으로 사용하고 제어하고 싶은지 명시해야겠죠? Firebase Console에서 쉽게 설정할 수 있습니다.

Remote Config를 처음 설정하게 되면 아래 화면으로 진입하게 됩니다. 첫 구성을 만들기 위해 '구성 만들기' 버튼을 클릭합니다.

이제 매개변수를 만들면 됩니다! 필드도 몇개 없고 직관적이라 어떤 값들이 들어가야 할지 쉽게 파악이 가능합니다. 저는 제 강아지 이름을 원격으로 제어하고자 `puppy_name`의 Key와 '민톨'이라는 Value를 문자열 타입으로 설정해주었습니다.
++ 중요! Remote Config 파라미터 Key 또는 Value에는 민감한 데이터를 저장하지 말 것을 권장합니다.


이렇게 첫 번째 매개변수를 만들고 나면 앞으로 계속 보게될 매개변수 리스트 화면을 볼 수 있게 됩니다. 여기서 중요한 점은, 값을 만들면 바로 반영되는 것이 아닌 '변경 사항 게시' 버튼을 눌러줘야 실제 값이 반영된다는 것입니다! 잊지말고 꼭 눌러주세요.

Firebase Console에서의 설정은 끝났습니다. 이제 프로젝트에도 Remote Config를 가져오기 위한 기본 세팅을 진행해줍니다. 먼저 제가 기존에 사용하던 `FirebaseManager`에 이를 위한 함수를 하나 생성해주었습니다.
++ `import FirebaseRemoteConfig` 부분에서 컴파일 에러가 난다면, 프로젝트 타겟에 `FirebaseRemoteConfig`가 추가되었는지 확인해보세요!(없다면 추가 고고)
import FirebaseCore
import FirebaseRemoteConfig // ⭐️ 추가
enum FirebaseManager {
/// Firebase를 초기화합니다.
static func initialize() {
FirebaseApp.configure()
}
/// ⭐️ Remote Config를 설정합니다.
static func setupRemoteConfig() {
let remoteConfig = RemoteConfig.remoteConfig() // ⭐️ 싱글톤
let settings = RemoteConfigSettings() // ⭐️ 설정 객체
settings.minimumFetchInterval = 0 // ⭐️ 얼마나 자주 값을 가져올지(0 == 최대한 자주)
remoteConfig.configSettings = settings // ⭐️ 싱글톤에 설정 객체 넘기기
}
}
이후 앱 초기화 시점에 Firebase 초기화와 함께 RemoteConfig 설정도 진행해주었습니다.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// ...
FirebaseManager.initialize()
FirebaseManager.setupRemoteConfig() // ⭐️ 앱 초기화 시 Remote Config 설정
// ...
}
}
자 이제 대망의 값을 가져와보겠습니다! Firebase Console에서 작성했던 Key와 타입을 이용해 아래와 같이 작성하면 우리가 설정했던 '민톨' 값을 정상적으로 가져오는 것을 확인할 수 있습니다.
// ⭐️ 당연한 이야기지만 비동기로 가져오지 않으면 기본값(타입 기본값 or 내가 지정한 기본값)으로 설정됨
Task {
let remoteConfig = RemoteConfig.remoteConfig()
try await remoteConfig.fetch()
try await remoteConfig.activate()
let puppyName = remoteConfig["puppy_name"].stringValue
print("제 강아지 이름은 \(puppyName)이에요.")
}

다양한 타입 설정도 가능해요
Remote Config는 총 4개의 데이터 타입을 지원합니다. 위에서 예시로 포함한 문자열(`String`)과 숫자(`Int`), 부울(`Bool`), `JSON`을 이용해 다양한 데이터를 표현할 수 있죠. 각각 사용은 아래와 같이 가능합니다. JSON을 지원하기 때문에 사실상 대부분의 데이터는 모두 표현이 가능하다 봐도 무방합니다 ㅎㅎ

Task {
let remoteConfig = RemoteConfig.remoteConfig()
try await remoteConfig.fetch()
try await remoteConfig.activate()
let puppyName = remoteConfig["puppy_name"].stringValue
let puppyAge = remoteConfig["puppy_age"].numberValue
let isCute = remoteConfig["isCute"].boolValue
let character = try remoteConfig["character"].decoded(asType: Character.self)
print("제 강아지 이름은 \(puppyName)이고 \(puppyAge)살이고 \(isCute ? "귀여워요" : "별로에요").")
dump(character)
}

인앱 기본값 설정도 가능해요
지금가지는 Firebase Console에서 기본값을 설정해주었지만 각각의 앱 별로 별도의 기본값을 사용해줘야 할 일이 생기기도 합니다.(ex: iOS, Android에 따른 기본값 분기 처리 등)
인앱 기본값을 설정하기 위해 Firebase Console에서 기본값 파일을 다운로드 받은 후, 앱 내 적용해 이를 구현할 수 있습니다.


원격 구성 기본값을 다운로드 받으면 `remote_config_defaults.plist` 파일이 다운로드 됩니다. 해당 파일을 프로젝트에 적용 후, 설정하고 싶은 기본값을 구성합니다.

static func setupRemoteConfig() {
let remoteConfig = RemoteConfig.remoteConfig()
let settings = RemoteConfigSettings()
settings.minimumFetchInterval = 0
remoteConfig.configSettings = settings
remoteConfig.setDefaults(fromPlist: "remote_config_defaults") // ⭐️ 기본값 설정
}
그럼 이렇게 안귀여운(?) 한톨을 출력할 수 있게 됩니다.

실시간 업데이트도 가능해요
지금까지 RemoteConfig를 받아오는 방식은 매번 명시적으로 불러오는 것이었습니다.(ex: viewDidLoad, onAppear 시점에 RemoteConfig 값 호출)
하지만 Rx나 Combine, AsyncStream처럼 비동기 스트림 형태, 즉 실시간으로 값을 받을 수 있는 방법도 있습니다!
// ⭐️ Remote Config 리스너 추가
remoteConfig.addOnConfigUpdateListener { configUpdate, error in
// ⭐️ 에러 처리
if let error {
print("에러 발생: \(error.localizedDescription)")
return
}
// ⭐️ 업데이트가 있을 시 로직 호출
if let _ = configUpdate {
Task {
let remoteConfig = RemoteConfig.remoteConfig()
try await remoteConfig.fetch()
try await remoteConfig.activate()
let puppyName = remoteConfig["puppy_name"].stringValue
print("실시간 민톨 이름 업데이트: \(puppyName)")
}
}
}

SwiftUI용 프로퍼티 래퍼도 있어요
일반 함수 안에서는 위와 같이 리스너를 추가해 실시간 값을 받아올 수 있지만, SwiftUI View 용으로만 사용한다면 전용 프로퍼티 래퍼 `@RemoteConfigProperty` 사용을 고려해봐도 좋습니다. 아래와 같이 추가하면 정말 쉽게 실시간 View 업데이트를 사용할 수 있게 됩니다!
struct ContentView: View {
@RemoteConfigProperty(key: "puppy_name", fallback: "기본 민톨") var puppyName
var body: some View {
VStack {
Text(puppyName)
}
.onAppear {
RemoteConfig.remoteConfig().fetchAndActivate()
}
}
}
역시 좋은 기능은 잘 찾아오면 이미 있다,,, ㅎㅎ
최근 회사 프로젝트에서 광고 SDK 관련 민감한 로직의 분기 처리를 빠르게 적용하기 위해 Sever-Driven 대신 Firebase Remote Config를 사용했었습니다. 이미 여기저기 사용 중이었기 때문에 이미 있던 값들을 가져다 쓰기만 했었는데, 역시 이렇게 직접 구현해보니 더 제 것이 되는 것 같습니다.
예전 캐플 프로젝트 때도 Remote Config를 적극적으로 활용했으면 서버 분들께 부담 드리지 않고 다양한 이벤트를 진행해 볼 수 있었을 것 같다는 아쉬움도 남네요 ㅜ 🥲
'실무 내용 내껄로 만들기' 카테고리의 다른 글
| Firebase App Distribution + Fastlane으로 초간단 QA 빌드 뽑아보기 (0) | 2025.10.19 |
|---|---|
| Git Worktree로 브랜치 사이를 효율적으로 거닐기 (0) | 2025.09.13 |
| 무지성 Commit은 그만! Git Rebase로 깔끔하게 코드 리뷰 반영하기 (5) | 2025.09.07 |
