📱 안드로이드 Android ~ Kotlin

[Android/kotlin] 구글 Firebase Remote Config 사용하기

핑크빛연어 2022. 9. 7. 18:30

 

Remote Config

 

Firebase 의 Remote Config 는 사용자가 앱 업데이트를 다운로드하지 않고도 앱의 동작과 모양을 변경할 수 있는

클라우드 서비스입니다.

 

https://firebase.google.com/docs/remote-config

 

Firebase 원격 구성하기

앱 업데이트를 게시하지 않고도 일일 활성 사용자 수 제한 없이 무료로 앱의 동작과 디자인을 변경할 수 있습니다.

firebase.google.com

 

https://firebase.google.com/docs/remote-config/get-started?platform=android 

 

Firebase 원격 구성 시작하기

의견 보내기 Firebase 원격 구성 시작하기 iOS+ Android 웹 Flutter Unity C++ Firebase 원격 구성으로 클라우드에서 앱의 매개변수를 정의하고 값을 업데이트하면 앱 업데이트를 배포하지 않고도 앱의 모양

firebase.google.com

 

 

 

🚨 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>

 

 

 

결과 화면

초기 화면 / Button show test 클릭 시 화면 / Button show dialog 클릭 시 화면

 

 

 

감사합니다 ✌️ ̆̈

 

728x90
반응형