Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

플레이 스토어 인앱 업데이트 구현 #257

Merged
merged 11 commits into from
Mar 6, 2024
Merged
12 changes: 7 additions & 5 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ dependencies {
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.activity:activity-ktx:1.8.2")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
implementation("androidx.navigation:navigation-ui-ktx:2.7.6")

// Retrofit, Serialization
implementation("com.squareup.retrofit2:retrofit:2.9.0")
Expand All @@ -92,7 +90,7 @@ dependencies {
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

// Navigation
val navVersion = "2.7.6"
val navVersion = "2.7.7"
implementation("androidx.navigation:navigation-fragment-ktx:$navVersion")
implementation("androidx.navigation:navigation-ui-ktx:$navVersion")

Expand All @@ -107,11 +105,15 @@ dependencies {

// Worker
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("androidx.hilt:hilt-work:1.1.0")
kapt("androidx.hilt:hilt-compiler:1.1.0")
implementation("androidx.hilt:hilt-work:1.2.0")
kapt("androidx.hilt:hilt-compiler:1.2.0")

// Material chart
implementation("app.priceguard:materialchart:0.2.2")

// In app update
implementation("com.google.android.play:app-update:2.1.0")
implementation("com.google.android.play:app-update-ktx:2.1.0")
}

kapt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
Expand All @@ -16,12 +20,22 @@ import androidx.work.WorkManager
import app.priceguard.R
import app.priceguard.databinding.ActivityHomeBinding
import app.priceguard.service.UpdateTokenWorker
import app.priceguard.ui.data.DialogConfirmAction
import app.priceguard.ui.util.SystemNavigationColorState
import app.priceguard.ui.util.applySystemNavigationBarColor
import app.priceguard.ui.util.openNotificationSettings
import app.priceguard.ui.util.showConfirmDialog
import app.priceguard.ui.util.showDialogWithAction
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.material.snackbar.Snackbar
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.InstallStateUpdatedListener
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus
import com.google.android.play.core.install.model.UpdateAvailability
import dagger.hilt.android.AndroidEntryPoint
import java.util.concurrent.TimeUnit

Expand All @@ -30,18 +44,33 @@ class HomeActivity : AppCompatActivity() {

private lateinit var binding: ActivityHomeBinding
private lateinit var snackbar: Snackbar
private lateinit var appUpdateManager: AppUpdateManager
private lateinit var flexibleAppUpdateResultLauncher: ActivityResultLauncher<IntentSenderRequest>
private lateinit var immediateAppUpdateResultLauncher: ActivityResultLauncher<IntentSenderRequest>
private val updateListener = InstallStateUpdatedListener { state ->
if (state.installStatus() == InstallStatus.DOWNLOADED) {
appUpdateManager.completeUpdate()
}

if (state.installStatus() == InstallStatus.FAILED) {
Toast.makeText(this, getString(R.string.update_failed), Toast.LENGTH_LONG)
.show()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.applySystemNavigationBarColor(SystemNavigationColorState.BOTTOM_NAVIGATION)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)

setupAppUpdate()
enqueueWorker()
initSnackBar()
checkForGooglePlayServices()
setBottomNavigationBar()
askNotificationPermission()
checkAppUpdates()
}

override fun onResume() {
Expand All @@ -59,6 +88,11 @@ class HomeActivity : AppCompatActivity() {
}
}

override fun onDestroy() {
super.onDestroy()
appUpdateManager.unregisterListener(updateListener)
}

private fun enqueueWorker() {
val saveRequest =
PeriodicWorkRequestBuilder<UpdateTokenWorker>(730, TimeUnit.HOURS)
Expand Down Expand Up @@ -128,6 +162,55 @@ class HomeActivity : AppCompatActivity() {
}
}

private fun setupAppUpdate() {
appUpdateManager = AppUpdateManagerFactory.create(this)
flexibleAppUpdateResultLauncher =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult ->
when (result.resultCode) {
RESULT_CANCELED -> {
showConfirmDialog(getString(R.string.warning), getString(R.string.update_cancel_warning))
}

com.google.android.play.core.install.model.ActivityResult.RESULT_IN_APP_UPDATE_FAILED -> {
Taewan-P marked this conversation as resolved.
Show resolved Hide resolved
Toast.makeText(this, getString(R.string.update_failed), Toast.LENGTH_LONG)
.show()
}
}
}
immediateAppUpdateResultLauncher =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult ->
when (result.resultCode) {
RESULT_CANCELED -> {
showDialogWithAction(getString(R.string.warning), getString(R.string.must_update), DialogConfirmAction.FINISH)
}

com.google.android.play.core.install.model.ActivityResult.RESULT_IN_APP_UPDATE_FAILED -> {
showDialogWithAction(getString(R.string.error), getString(R.string.update_failed), DialogConfirmAction.FINISH)
}
}
}
appUpdateManager.registerListener(updateListener)
}

private fun checkAppUpdates() {
val appUpdateInfoTask = appUpdateManager.appUpdateInfo
var appUpdateOptions = AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()
var activityResultLauncher = flexibleAppUpdateResultLauncher

appUpdateInfoTask.addOnSuccessListener { info ->
ootr47 marked this conversation as resolved.
Show resolved Hide resolved
when (info.updateAvailability()) {
UpdateAvailability.UPDATE_AVAILABLE, UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS -> {
if (info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) && info.updatePriority() >= 3) {
activityResultLauncher = immediateAppUpdateResultLauncher
appUpdateOptions = AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
}
appUpdateManager.startUpdateFlowForResult(info, activityResultLauncher, appUpdateOptions)
}
else -> {}
}
}
}

private fun showNotificationOffSnackbar() {
if (snackbar.isShown) return
snackbar.show()
Expand Down
17 changes: 17 additions & 0 deletions android/app/src/main/java/app/priceguard/ui/util/Dialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@ fun Fragment.showDialogWithAction(
dialogFragment.show(requireActivity().supportFragmentManager, tag)
}

fun AppCompatActivity.showDialogWithAction(
title: String,
message: String,
action: DialogConfirmAction = DialogConfirmAction.NOTHING
) {
val tag = "confirm_dialog_fragment_with_action_from_activity"
if (supportFragmentManager.findFragmentByTag(tag) != null) return

val dialogFragment = ConfirmDialogFragment()
val bundle = Bundle()
bundle.putString("title", title)
bundle.putString("message", message)
bundle.putString("actionString", action.name)
dialogFragment.arguments = bundle
dialogFragment.show(supportFragmentManager, tag)
}

fun AppCompatActivity.showDialogWithLogout() {
val tag = "error_dialog_fragment_from_activity"
if (supportFragmentManager.findFragmentByTag(tag) != null) return
Expand Down
4 changes: 4 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@
<string name="recommended_product_no_product">추천 상품이 준비중입니다.</string>
<string name="sold_out">품절</string>
<string name="error_maximum_count_exceeded">등록 가능한 상품 개수를 초과하였습니다.</string>
<string name="update_cancel_warning">업데이트 미적용 시 앱 사용에 지장이 생길 수 있습니다.</string>
<string name="update_failed">업데이트에 실패하였습니다. 다시 시도해 주세요.</string>
<string name="warning">경고</string>
<string name="must_update">필수 업데이트 미적용 시 앱 사용이 불가능 합니다.</string>
<string name="reset_password">비밀번호 재설정</string>
<string name="verify_email">이메일 인증</string>
<string name="verification_number">인증번호</string>
Expand Down
Loading