Firebase 추가
Crashlytics 추가 RemoteConfig 이용한 강제 업데이트 로직 추가
This commit is contained in:
parent
edbaceba0b
commit
fd8c4e726d
|
@ -20,7 +20,8 @@ bin/
|
|||
gen/
|
||||
out/
|
||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||
release/
|
||||
/release/
|
||||
/debug/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
|
@ -302,7 +303,7 @@ fabric.properties
|
|||
### AndroidStudio Patch ###
|
||||
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
app/debug/*
|
||||
app/release/*
|
||||
app/debug/
|
||||
app/release/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio,visualstudiocode,git,kotlin,java
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'com.google.gms.google-services'
|
||||
id 'com.google.android.gms.oss-licenses-plugin'
|
||||
|
||||
id 'kotlin-kapt'
|
||||
|
@ -8,6 +9,7 @@ plugins {
|
|||
id 'org.jlleitschuh.gradle.ktlint'
|
||||
|
||||
id 'io.objectbox'
|
||||
id("com.google.firebase.crashlytics")
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -115,4 +117,12 @@ dependencies {
|
|||
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
||||
|
||||
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1'
|
||||
|
||||
// Firebase
|
||||
implementation platform('com.google.firebase:firebase-bom:32.2.0')
|
||||
implementation 'com.google.firebase:firebase-dynamic-links-ktx'
|
||||
implementation 'com.google.firebase:firebase-crashlytics-ktx'
|
||||
implementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
implementation 'com.google.firebase:firebase-messaging-ktx'
|
||||
implementation 'com.google.firebase:firebase-config-ktx'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "758414412471",
|
||||
"project_id": "sodalive-test",
|
||||
"storage_bucket": "sodalive-test.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:758414412471:android:dcea9dff87fa125c7a5b32",
|
||||
"android_client_info": {
|
||||
"package_name": "kr.co.vividnext.sodalive.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "758414412471-g35socquiplhaamhfl4e6bsta5blabi7.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAeNDVDY_r5afz97L1NPvQC6oFy5lPXHNI"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "758414412471-g35socquiplhaamhfl4e6bsta5blabi7.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package kr.co.vividnext.sodalive.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import kr.co.vividnext.sodalive.databinding.DialogSodaBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
|
||||
open class SodaDialog(
|
||||
activity: Activity,
|
||||
layoutInflater: LayoutInflater,
|
||||
title: String,
|
||||
desc: String,
|
||||
confirmButtonTitle: String,
|
||||
confirmButtonClick: () -> Unit,
|
||||
cancelButtonTitle: String = "",
|
||||
cancelButtonClick: (() -> Unit)? = null,
|
||||
) {
|
||||
|
||||
private val alertDialog: AlertDialog
|
||||
|
||||
val dialogView = DialogSodaBinding.inflate(layoutInflater)
|
||||
|
||||
init {
|
||||
val dialogBuilder = AlertDialog.Builder(activity)
|
||||
dialogBuilder.setView(dialogView.root)
|
||||
|
||||
alertDialog = dialogBuilder.create()
|
||||
alertDialog.setCancelable(false)
|
||||
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
|
||||
dialogView.tvTitle.text = title
|
||||
dialogView.tvDesc.text = desc
|
||||
|
||||
dialogView.tvCancel.text = cancelButtonTitle
|
||||
dialogView.tvCancel.setOnClickListener {
|
||||
alertDialog.dismiss()
|
||||
cancelButtonClick?.let { it() }
|
||||
}
|
||||
|
||||
dialogView.tvConfirm.text = confirmButtonTitle
|
||||
dialogView.tvConfirm.setOnClickListener {
|
||||
alertDialog.dismiss()
|
||||
confirmButtonClick()
|
||||
}
|
||||
|
||||
dialogView.tvCancel.visibility = if (cancelButtonTitle.isNotBlank()) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
|
||||
dialogView.tvConfirm.visibility = if (confirmButtonTitle.isNotBlank()) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun show(width: Int) {
|
||||
alertDialog.show()
|
||||
|
||||
val lp = WindowManager.LayoutParams()
|
||||
lp.copyFrom(alertDialog.window?.attributes)
|
||||
lp.width = width - (26.7f.dpToPx()).toInt()
|
||||
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||
|
||||
alertDialog.window?.attributes = lp
|
||||
}
|
||||
}
|
|
@ -12,4 +12,8 @@ object Constants {
|
|||
|
||||
const val EXTRA_DATA = "extra_data"
|
||||
const val EXTRA_TERMS = "extra_terms"
|
||||
const val EXTRA_USER_ID = "extra_user_id"
|
||||
const val EXTRA_ROOM_ID = "extra_room_id"
|
||||
|
||||
const val EXTRA_AUDIO_CONTENT_ID = "extra_audio_content_id"
|
||||
}
|
||||
|
|
|
@ -2,10 +2,21 @@ package kr.co.vividnext.sodalive.splash
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.firebase.dynamiclinks.PendingDynamicLinkData
|
||||
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.google.firebase.remoteconfig.ktx.get
|
||||
import com.google.firebase.remoteconfig.ktx.remoteConfig
|
||||
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
|
||||
import kr.co.vividnext.sodalive.BuildConfig
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ActivitySplashBinding
|
||||
import kr.co.vividnext.sodalive.main.MainActivity
|
||||
|
@ -15,21 +26,163 @@ import kr.co.vividnext.sodalive.user.login.LoginActivity
|
|||
class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding::inflate) {
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val remoteConfig = Firebase.remoteConfig
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (SharedPreferenceManager.token.isBlank()) {
|
||||
showLoginActivity()
|
||||
setupRemoteConfig()
|
||||
fetchAndroidLatestVersion()
|
||||
}
|
||||
|
||||
private fun setupRemoteConfig() {
|
||||
val configSettings = remoteConfigSettings {
|
||||
minimumFetchIntervalInSeconds = 300
|
||||
}
|
||||
remoteConfig.setConfigSettingsAsync(configSettings)
|
||||
}
|
||||
|
||||
private fun fetchAndroidLatestVersion() {
|
||||
remoteConfig.fetchAndActivate()
|
||||
.addOnCompleteListener(this) { task ->
|
||||
if (task.isSuccessful) {
|
||||
handler.post {
|
||||
checkAppVersion(remoteConfig["android_latest_version"].asString())
|
||||
}
|
||||
} else {
|
||||
checkFirebaseDynamicLink()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAppVersion(latestVersion: String) {
|
||||
val versions = BuildConfig.VERSION_NAME.split(".")
|
||||
val latestVersions = latestVersion.split(".")
|
||||
|
||||
if (latestVersions.isNotEmpty() && latestVersions.size == versions.size) {
|
||||
val latestMajor = latestVersions[0].toInt()
|
||||
val latestMinor = latestVersions[1].toInt()
|
||||
val latestPatch = latestVersions[2].toInt()
|
||||
|
||||
val major = versions[0].toInt()
|
||||
val minor = versions[1].toInt()
|
||||
val patch = versions[2].toInt()
|
||||
|
||||
if (latestMajor > major || (latestMajor == major && latestMinor > minor)) {
|
||||
showUpdateDialog(isEssential = true)
|
||||
} else if (latestMajor == major && latestMinor == minor && latestPatch > patch) {
|
||||
showUpdateDialog(isEssential = false)
|
||||
} else {
|
||||
checkFirebaseDynamicLink()
|
||||
}
|
||||
} else {
|
||||
showMainActivity()
|
||||
checkFirebaseDynamicLink()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMainActivity() {
|
||||
private fun showUpdateDialog(isEssential: Boolean = false) {
|
||||
val desc = if (isEssential) {
|
||||
"필수 업데이트가 있습니다.\n업데이트 후 사용가능합니다."
|
||||
} else {
|
||||
"최신 업데이트가 있습니다.\n업데이트 하시겠습니까?"
|
||||
}
|
||||
|
||||
val cancelButtonClick = if (!isEssential) {
|
||||
{ checkFirebaseDynamicLink() }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
SodaDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "업데이트",
|
||||
desc = desc,
|
||||
confirmButtonTitle = "업데이트",
|
||||
confirmButtonClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse("market://details?id=${BuildConfig.APPLICATION_ID}")
|
||||
)
|
||||
)
|
||||
finish()
|
||||
},
|
||||
cancelButtonTitle = if (isEssential) {
|
||||
""
|
||||
} else {
|
||||
"다음에"
|
||||
},
|
||||
cancelButtonClick = cancelButtonClick
|
||||
).show(screenWidth)
|
||||
}
|
||||
|
||||
private fun checkFirebaseDynamicLink() {
|
||||
Firebase.dynamicLinks
|
||||
.getDynamicLink(intent)
|
||||
.addOnSuccessListener(this) { getDynamicLinkSuccess(it) }
|
||||
.addOnFailureListener(this) { getDynamicLinkFailure() }
|
||||
}
|
||||
|
||||
private fun getDynamicLinkSuccess(pendingDynamicLinkData: PendingDynamicLinkData?) {
|
||||
var deepLink: Uri? = null
|
||||
if (pendingDynamicLinkData != null) {
|
||||
deepLink = pendingDynamicLinkData.link
|
||||
}
|
||||
|
||||
val extras = if (deepLink != null) {
|
||||
val roomIdString = deepLink.getQueryParameter("room_id")
|
||||
val channelIdString = deepLink.getQueryParameter("channel_id")
|
||||
val audioContentIdString = deepLink.getQueryParameter("audio_content_id")
|
||||
|
||||
if (roomIdString != null) {
|
||||
bundleOf(
|
||||
Constants.EXTRA_ROOM_ID to roomIdString.toLong()
|
||||
)
|
||||
} else if (channelIdString != null) {
|
||||
bundleOf(
|
||||
Constants.EXTRA_USER_ID to channelIdString.toLong()
|
||||
)
|
||||
} else if (audioContentIdString != null) {
|
||||
bundleOf(
|
||||
Constants.EXTRA_AUDIO_CONTENT_ID to audioContentIdString.toLong()
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else if (intent.extras != null) {
|
||||
intent.extras
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
startNextActivity(extras = extras)
|
||||
}
|
||||
|
||||
private fun getDynamicLinkFailure() {
|
||||
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||
?: if (intent.extras != null) {
|
||||
intent.extras
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
startNextActivity(extras = extras)
|
||||
}
|
||||
|
||||
private fun startNextActivity(extras: Bundle? = null) {
|
||||
if (SharedPreferenceManager.token.isBlank()) {
|
||||
showLoginActivity(extras)
|
||||
} else {
|
||||
showMainActivity(extras)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMainActivity(extras: Bundle?) {
|
||||
handler.postDelayed({
|
||||
startActivity(
|
||||
Intent(applicationContext, MainActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_DATA, extras)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
}
|
||||
|
@ -38,10 +191,11 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
|||
}, 500)
|
||||
}
|
||||
|
||||
private fun showLoginActivity() {
|
||||
private fun showLoginActivity(extras: Bundle?) {
|
||||
handler.postDelayed({
|
||||
startActivity(
|
||||
Intent(applicationContext, LoginActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_DATA, extras)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_339970ff" />
|
||||
<corners android:radius="10dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -0,0 +1,79 @@
|
|||
<?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="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/bg_round_corner_10_222222">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/color_bbbbbb"
|
||||
android:textSize="18.3sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="작성글 등록" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/color_bbbbbb"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_title"
|
||||
tools:text="작성한 글을 등록하시겠습니까?" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16.7dp"
|
||||
android:layout_marginTop="45dp"
|
||||
android:layout_marginBottom="16.7dp"
|
||||
android:gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_desc">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_cancel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="13.3dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_10_339970ff_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="18.3sp"
|
||||
tools:text="취소" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_confirm"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_10_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp"
|
||||
tools:text="확인" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -16,4 +16,5 @@
|
|||
|
||||
<color name="color_b3909090">#B3909090</color>
|
||||
<color name="color_88909090">#88909090</color>
|
||||
<color name="color_339970ff">#339970FF</color>
|
||||
</resources>
|
||||
|
|
|
@ -22,6 +22,8 @@ plugins {
|
|||
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
|
||||
|
||||
id "org.jlleitschuh.gradle.ktlint" version "11.2.0"
|
||||
id 'com.google.gms.google-services' version '4.3.15' apply false
|
||||
id("com.google.firebase.crashlytics") version "2.9.7" apply false
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
|
Loading…
Reference in New Issue