강업 공지때문에 주말 출근하기 싫어서
원격 구성. 앱을 업데이트를 하지 않아도 하루 활성 사용자 수 제한 없이 앱의 동작과 모양을 변경할 수 있음
enum class RemoteConfigData(val key: String, val defaultValue: Any) {
// 테스트
HELLO_BOOLEAN(
key = "hello_boolean",
defaultValue = false),
HELLO_STRING(
key = "hello_string",
defaultValue = "test string 123"),
HELLO_LONG(
key = "hello_long",
defaultValue = 0L),
HELLO_DOUBLE(
key = "hello_double",
defaultValue = 0.0),
// 강제 업데이트
FORCE_UPDATE(
key = "force_update",
defaultValue = JSONObject().apply{
put("real", JSONObject().apply{
put("isForceUpdate", false)
put("forceUpdateVersion", "0.0.0")
put("noticeMsg", "")
put("marketUrl", "market://details?id=앱패키지")
})
put("dev", JSONObject().apply{
put("isForceUpdate", false)
put("forceUpdateVersion", "0.0.0")
put("noticeMsg", "")
put("marketUrl", "market://details?id=앱패키지")
})
}.toString());
companion object {
private fun getJsonStr(config: RemoteConfigData) = RemoteConfigManager.getValue(config)
private fun getServer() = if (isReal()) "real" else "dev"
// 강제 업데이트
private fun getForceUpdate() = JSONObject(getJsonStr(FORCE_UPDATE)).optJSONObject(getServer())
fun isForceUpdate() = getForceUpdate()?.optBoolean("isForceUpdate")
fun getForceUpdateVersion() = getForceUpdate()?.optString("forceUpdateVersion")
fun getNoticeMsg() = getForceUpdate()?.optString("noticeMsg")
fun getMarketUrl() = getForceUpdate()?.optString("marketUrl")
}
}
object RemoteConfigManager {
private val TAG = this::class.simpleName
private const val FETCH_INTERVAL = 60*60L
private var mIsCompletedRemoteConfig = false // remote config 잘 받아왔는지
private var mOnReadyListener: (() -> Unit)? = null // remote config 준비 완료 리스너
fun init() {
// 셋팅
// 앱에서 단기간에 가져오기를 너무 많이 수행하면 가져오기 호출이 제한되고 SDK는 FirebaseRemoteConfigFetchThrottledException을 반환합니다.
// SDK 버전 17.0.0 이전에는 60분 동안 가져오기 요청 수가 5회로 제한되었지만 최신 버전에서는 좀 더 많이 허용됩니다.
Firebase.remoteConfig.setConfigSettingsAsync(
remoteConfigSettings{
// 개발할 땐 바로 fetch하기 위해 1로 셋팅
minimumFetchIntervalInSeconds = if(BuildConfig.DEBUG) 1 else FETCH_INTERVAL
}
)
// 인앱 매개변수 기본값 설정
Firebase.remoteConfig.setDefaultsAsync(mutableMapOf<String, Any>().apply {
RemoteConfigData.values().forEach{ remoteConfigConst ->
put(remoteConfigConst.key, remoteConfigConst.defaultValue)
}
}).addOnCompleteListener {
}
// 값 가져오기 및 활성화
Firebase.remoteConfig.fetchAndActivate()
.addOnCompleteListener { task->
if (task.isSuccessful) {
val updated = task.result
Timber.tag(TAG).d("Config params updated: $updated")
Timber.tag(TAG).d("Fetch and activate succeeded")
} else {
Timber.tag(TAG).d("Fetch failed")
}
mIsCompletedRemoteConfig = true
mOnReadyListener?.invoke()
}
}
/**
* remote config 잘 받아온 상태이면 바로 block 실행
* 아직 remote config 받아오기 전이라면 onReadyListener 셋팅만 하고, 실제 remote config 받기 완료했을 때 onReadyListener 실행
*/
fun onReady(block: () -> Unit) {
if(!mIsCompletedRemoteConfig) {
mOnReadyListener = block
return
}
block.invoke()
}
fun getValue(config: RemoteConfigData): Any {
// remote config 다 받아오기도 전이라면 기본값 넘기기
if(!mIsCompletedRemoteConfig) {
return config.defaultValue
}
return when(config.defaultValue) {
is Boolean -> Firebase.remoteConfig.getBoolean(config.key)
is String -> Firebase.remoteConfig.getString(config.key)
is Long -> Firebase.remoteConfig.getLong(config.key)
is Double -> Firebase.remoteConfig.getDouble(config.key)
else -> throw IllegalArgumentException("unused type")
}
}
}
@Test
fun testRemoteConfig() = runBlocking {
RemoteConfigManager.onReady {
val booleanValue = RemoteConfigManager.getValue(RemoteConfigData.HELLO_BOOLEAN)
val stringValue = RemoteConfigManager.getValue(RemoteConfigData.HELLO_STRING)
val longValue = RemoteConfigManager.getValue(RemoteConfigData.HELLO_LONG)
val doubleValue = RemoteConfigManager.getValue(RemoteConfigData.HELLO_DOUBLE)
println("booleanValue : $booleanValue")
println("stringValue : $stringValue")
println("longValue : $longValue")
println("doubleValue : $doubleValue")
assertThat(booleanValue).isNotNull()
assertThat(stringValue).isNotNull()
assertThat(longValue).isNotNull()
assertThat(doubleValue).isNotNull()
val forceUpdate = RemoteConfigData.isForceUpdate()
val forceUpdateVersion = RemoteConfigData.getForceUpdateVersion()
val noticeMsg = RemoteConfigData.getNoticeMsg()
val marketUrl = RemoteConfigData.getMarketUrl()
println("forceUpdate : $forceUpdate")
println("forceUpdateVersion : $forceUpdateVersion")
println("noticeMsg : $noticeMsg")
println("marketUrl : $marketUrl")
assertThat(forceUpdate).isNotNull()
assertThat(forceUpdateVersion).isNotNull()
assertThat(noticeMsg).isNotNull()
assertThat(marketUrl).isNotNull()
}
delay(1000L)
}
// init remote config
RemoteConfigManager.init()
asis
when(공지) {
is 강업 -> {
강업체크 { 일반공지체크() }
}
else -> 일반공지체크()
}
tobe
when(공지) {
is 강업 -> {
강업체크 { 일반공지체크() }
}
else -> {
// remote config 강제 업데이트 체크
RemoteConfigManager.onReady {
if (!isRemoteConfig강업()) {
일반공지체크()
return@onReady
}
remoteConfig강업데이터셋팅()
강업체크 { 일반공지체크() }
}
}
}