Remote Config
Firebase 의 Remote Config 는 사용자가 앱 업데이트를 다운로드하지 않고도 앱의 동작과 모양을 변경할 수 있는
클라우드 서비스입니다.
https://firebase.google.com/docs/remote-config
https://firebase.google.com/docs/remote-config/get-started?platform=android
🚨 Firebase Remote Config 생성
1. Remote Config 구성 매개변수 만들기
Firebase console 창에서 왼쪽 Remote Config 를 클릭합니다.
그리고 구성 만들기 를 클릭해 주세요~
첫번째 매개변수 만들기 화면이 표시됩니다.
매개변수 이름(키) 에 원하는 변수의 키를 입력하고 데이터 유형 도 선택해주세요.
(데이터 유형은 문자열, 숫자, 부울, JSON 유형 중 선택할 수 있습니다.)
설명도 선택사항으로 추가해줍니다.
Default value 에 기본 값을 입력해주세요.
새로 추가 버튼을 누르면 조건부 값, 맞춤설정 항목이 나옵니다.
이 부분을 이용하면 사용자의 개별적인 니즈와 요구사항에 맞는 커스텀 환경을 만들 수 있습니다.
마지막으로 저장 버튼을 눌러 첫 번째 매개변수 만들기를 완료합니다.
2. Remote Config 변경사항 게시하기
그리고 필요한 매개변수들을 여러개 추가해주고, 변경사항 게시 버튼 클릭
변경사항 게시 버튼 클릭하면 즉시 적용됩니다.
🚨 소스코드 구성하기
1. build.gradle(:app)
◾ 앱에 Remote Config SDK 추가
- dependencies 안에 Firebase Remote Config 에 대한 의존성을 추가해줍니다.
implementation 'com.google.firebase:firebase-config-ktx' //Firebase Remote Config 추가
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'com.google.gms.google-services'
id 'com.google.firebase.crashlytics'
}
android {
...
}
dependencies {
...
implementation platform('com.google.firebase:firebase-bom:30.0.1')
implementation 'com.google.firebase:firebase-config-ktx' //Firebase Remote Config
...
}
2. RemoteMainActivity.kt
Remote Config 객체 사용하기
Firebase 의 Remote Config 싱글톤 객체 가져와서 사용합니다.
싱글톤 객체는 인앱 기본 매개변수 값을 저장하고, 백엔드에서 업데이트된 매개변수 값을 가져오고, 가져온 값을 앱에서 사용할 수 있게 되는 시기를 제어하는 데 사용됩니다.
setDefaultAsync 는 Firebase Remote Config 에 변수가 정의되어 있지 않을 때, 디폴트로 값을 얻고자 할 때 사용합니다.. setDefaultAsync 의 파라미터는 Map 객체로 넘겨주어도 되며, xml 형태로도 제공이 가능합니다.
◾ Remote Config 객체 가져오기
val remoteConfig = Firebase.remoteConfig
◾ 객체 default 값 설정 - map 형태
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
mapOf(
"app_version" to "0.0.0",
"welcome_msg" to "Welcome to my awesome app!"
)
}
remoteConfig.setConfigSettingsAsync(configSettings)
◾ 객체 default 값 설정 - xml 형태
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
◾ remote_config_defaults.xml
<?xml version="1.0" encoding="utf-8"?>
<defaultsMap>
<entry>
<key>welcome_msg</key>
<value>Welcome to my awesome app!</value>
</entry>
<entry>
<key>app_version</key>
<value>0.0.0</value>
</entry>
</defaultsMap>
◾ 매개변수 KEY 값 설정
var appVersion = remoteConfig.getString("app_version")
var welcomeMsg = remoteConfig.getString("welcome_msg")
var testShowEnable = remoteConfig.getBoolean("test_show_enable")
var testTitle = remoteConfig.getString("test_title")
var testMsg = remoteConfig.getString("test_msg")
var dialogInfo = remoteConfig.getString("dialog_info")
◾ 값 가져오기 및 활성화
remoteConfig.fetchAndActivate()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val updated = task.result
LogUtil.d(TAG, "Config params updated: $updated")
Toast.makeText(this, "Fetch and activate succeeded",
Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Fetch failed",
Toast.LENGTH_SHORT).show()
}
}
RemoteMainActivity.kt 소스
Remote Config 초기화 및 활성화 후 매개변수의 Key 로 값을 가져와서 사용하였습니다.
첫번째 버튼 Button Show Test 클릭 시, String 또는 Boolean 형태로 된 welcome_msg, app_version,
test_show_enable, test_title, test_msg 매개변수를 사용해서 화면에 표시해주었습니다.
welcome_msg 매개변수는 Firebase 에서 추가한 매개변수가 아니기 때문에 setDefaultAsync 의 디폴트 값으로 표시되는 걸 확인할 수 있습니다.
두번째 버튼 Button Show Dialog 클릭 시, dialog_info 를 JSON 형태로 변환 후
dialog_info 의 show_enable, dialog_title, dialog_msg 를 사용해서 alertDialog 를 띄워주었습니다.
class RemoteMainActivity: AppCompatActivity() {
companion object {
const val TAG = "RemoteMainActivity"
const val REMOTE_KEY_APP_VERSION = "app_version"
const val REMOTE_KEY_WELCOME_MSG = "welcome_msg"
const val REMOTE_KEY_TEST_SHOW_ENABLE= "test_show_enable"
const val REMOTE_KEY_TEST_TITLE = "test_title"
const val REMOTE_KEY_TEST_MSG = "test_msg"
const val REMOTE_KEY_DIALOG_INFO = "dialog_info"
}
lateinit var binding: ActivityRemoteMainBinding
private var appVersion: String? = null
private var welcomeMsg: String? = null
private var testShowEnable: Boolean = false
private var testTitle: String? = null
private var testMsg: String? = null
private var dialogInfo: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRemoteMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initRemoteConfig()
initView()
}
/**
* initRemoteConfig()
* - Firebase Remote Config 설정
*/
private fun initRemoteConfig() {
val remoteConfig = Firebase.remoteConfig //Remote Config 객체 가져오기
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
mapOf(
REMOTE_KEY_APP_VERSION to "0.0.0",
REMOTE_KEY_WELCOME_MSG to "Welcome to my awesome app!"
)
}
remoteConfig.setConfigSettingsAsync(configSettings) //객체 default 값 설정 - map 형태
// remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) //객체 default 값 설정 - xml 형태
//매개변수 KEY 값 설정
appVersion = remoteConfig.getString(REMOTE_KEY_APP_VERSION)
welcomeMsg = remoteConfig.getString(REMOTE_KEY_WELCOME_MSG)
testShowEnable = remoteConfig.getBoolean(REMOTE_KEY_TEST_SHOW_ENABLE)
testTitle = remoteConfig.getString(REMOTE_KEY_TEST_TITLE)
testMsg = remoteConfig.getString(REMOTE_KEY_TEST_MSG)
dialogInfo = remoteConfig.getString(REMOTE_KEY_DIALOG_INFO)
//값 가져오기 및 활성화
remoteConfig.fetchAndActivate()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val updated = task.result
LogUtil.d(TAG, "Config params updated: $updated")
Toast.makeText(this, "Fetch and activate succeeded",
Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Fetch failed",
Toast.LENGTH_SHORT).show()
}
}
}
/**
* initView()
* - View 설정
*/
private fun initView() {
// button show test 클릭 시
binding.btnShowTest.setOnClickListener {
binding.tvTest.text =
if(testShowEnable) {
"$REMOTE_KEY_WELCOME_MSG : ${welcomeMsg.toString()}" +
"\n\n" +
"$REMOTE_KEY_APP_VERSION : ${appVersion.toString()}" +
"\n\n" +
"$REMOTE_KEY_TEST_SHOW_ENABLE : ${testShowEnable.toString()}" +
"\n\n" +
"$REMOTE_KEY_TEST_TITLE : $testTitle" +
"\n\n" +
"$REMOTE_KEY_TEST_MSG : $testMsg"
} else {
"$REMOTE_KEY_TEST_SHOW_ENABLE : ${testShowEnable.toString()}"
}
}
// button show dialog 클릭 시
binding.btnShowDialog.setOnClickListener {
val dialogInfoJson = JSONObject(dialogInfo) //dialogInfo 를 JSONObject 로 변환
if(dialogInfoJson.getBoolean("show_enable")) {
val builder = AlertDialog.Builder(this)
val dialog = builder.setTitle("[${this.getString(R.string.app_name)}] ${dialogInfoJson.get("dialog_title")}")
.setMessage("${dialogInfoJson.get("dialog_msg")}")
.setNegativeButton("닫기", null)
.setCancelable(false)
.create()
dialog.show()
} else {
Toast.makeText(this, "Dialog Info - show_enable :: false", Toast.LENGTH_SHORT).show()
}
}
}
}
activity_remote_main.xml 소스
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".remote.RemoteMainActivity">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="100dp"
android:text="RemoteMainActivity"
android:textSize="20dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_show_test"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_show_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:paddingHorizontal="10dp"
android:text="Button Show Test"
android:background="@drawable/bg_custom_button_purple"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/btn_show_dialog"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_show_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:paddingHorizontal="10dp"
android:text="Button Show Dialog"
android:background="@drawable/bg_custom_button_purple"
app:layout_constraintTop_toBottomOf="@id/tv_title"
app:layout_constraintStart_toEndOf="@id/btn_show_test"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tv_test"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="30dp"
android:padding="30dp"
android:text="0.0.0"
android:textColor="@color/black"
android:textSize="15dp"
android:background="@color/blue_100"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_show_test"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
결과 화면
감사합니다 ✌️ ̆̈
'📱 안드로이드 Android ~ Kotlin' 카테고리의 다른 글
[Android/Kotlin] ViewPager2 를 이용한 스크롤 시 애니메이션 적용(smoothScroll, PageTransformer) (0) | 2022.11.03 |
---|---|
[Android/Kotlin] ViewPager2 를 이용한 무한 스크롤(Infinite Scroll)/자동 스크롤(Auto Scroll) (0) | 2022.10.31 |
[Android/kotlin] 구글 Firebase In-App Messaging 사용하기 (0) | 2022.07.28 |
[Android/kotlin] 구글 Firebase Realtime Database 사용한 채팅 앱 만들기 (0) | 2022.06.24 |
[Android/kotlin] 구글 Firebase Realtime Database 사용하기 (0) | 2022.06.10 |