안녕하세요.
Google Play Core 라이브러리의 인앱 업데이트 기능을 사용하여 앱을 기기에서 최신상태로 유지할 수 있는 방법을 알아보겠습니다.
Android 5.0(API 레벨 21) 이상을 실행하는 기기는 인앱 업데이트 기능과 호환됩니다.
다음은 앱 내에서 업데이트를 표시하는 두 가지 방법입니다.\
업데이트 종류
Flexible(유연한)
사용자가 앱을 업데이트하려는 경우 팝업 창이 표시됩니다.
수락과 거부는 모두 선택 사항입니다.
동의하면 업데이트가 백그라운드에서 다운로드되기 시작합니다.
업데이트가 약간의 UI 조정 또는 성능 업그레이드 를 제공하는 경우 이를 활용하는 것을 권장합니다.
Immediate(즉각적인)
앱을 사용하려면 무조건 업데이트해야 합니다.
보안 패치와 같은 중요한 업데이트 가 있는 경우 이를 활용할 수 있습니다 .
업데이트를 해야한다고 알릴 수 있는 두가지 신호가 있습니다.
1. Priority(우선순위) : 0에서 5 사이의 정수를 제공하여 각 릴리스에서 업데이트의 중요도를 지정합니다(5가 가장 높은 우선 순위). 앱을 업데이트하기 위해 적절한 업데이트 흐름(Immediate 또는 Flexible)이 시작됩니다.
Google Play Console 을 통해 업데이트의 우선순위 를 설정할 수 있는 방법은 없고 Google Play 개발자 API 를 사용해야 합니다 .
- 5: 즉시 표시(중요 업데이트에 권장)
- 4: 5일 후 즉시 표시 및 3일 후 유연성 표시.
- 3: 30일 후 즉시 표시, 15일 후 유연 표시(성능 업데이트 권장)
- 2: 90일 후 즉시 표시 및 30일 후 유연성 표시(마이너 업데이트 권장)
- 1: 항상 유연성 표시
- 0: 업데이트에 영향 없음 흐름.
2. Staleness : 장치가 업데이트를 사용할 수 있음을 인식한 시간을 지정합니다. 이는 적절한 흐름을 설정하는 데 도움이 됩니다. 예를 들어, 사용자가 업데이트 릴리스 후 이전 30일 동안 앱을 업데이트하지 않은 경우 Flexible이 트리거되고, 90일보다 긴 경우 Immediate이 트리거됩니다.
Android에서 인앱 업데이트를 구현하는 방법
모듈 수준 build.gradle 파일에 다음 종속성을 추가합니다.
dependencies {
implementation 'com.google.android.play:core:1.7.0'
}
InAppUpdate.kt 라는 새 파일을 만듭니다.
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.InstallState
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
class InAppUpdate(activity: Activity) : InstallStateUpdatedListener {
private var appUpdateManager: AppUpdateManager
private val MY_REQUEST_CODE = 500
private var parentActivity: Activity = activity
private var currentType = AppUpdateType.FLEXIBLE
init {
appUpdateManager = AppUpdateManagerFactory.create(parentActivity)
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
// 업데이트를 해야하는 지 확인
if (info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) { // 업데이트 해야함
if (info.updatePriority() == 5) { // Priority: 5 (Immediate update flow)- 즉각적으로 진행
if (info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
startUpdate(info, AppUpdateType.IMMEDIATE)
}
} else if (info.updatePriority() == 4) { // Priority: 4
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 5 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow - 즉각적으로 진행
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 3 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow - 유연하게 진행
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 3) { // Priority: 3
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 30 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow - 즉각적으로 진행
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 15 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow - 유연하게 진행
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 2) { // Priority: 2
val clientVersionStalenessDays = info.clientVersionStalenessDays()
if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 90 && info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
// Trigger IMMEDIATE flow - 즉각적으로 진행
startUpdate(info, AppUpdateType.IMMEDIATE)
} else if (clientVersionStalenessDays != null && clientVersionStalenessDays >= 30 && info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
// Trigger FLEXIBLE flow - 유연하게 진행
startUpdate(info, AppUpdateType.FLEXIBLE)
}
} else if (info.updatePriority() == 1) { // Priority: 1
// Trigger FLEXIBLE flow - 유연하게 진행
startUpdate(info, AppUpdateType.FLEXIBLE)
} else { // Priority: 0
// 인앱 업데이트 안 보여줌
}
} else {
// 업데이트 필요 없음
}
}
appUpdateManager.registerListener(this)
}
private fun startUpdate(info: AppUpdateInfo, type: Int) {
appUpdateManager.startUpdateFlowForResult(info, type, parentActivity, MY_REQUEST_CODE)
currentType = type
}
fun onResume() {
appUpdateManager.appUpdateInfo.addOnSuccessListener { info ->
if (currentType == AppUpdateType.FLEXIBLE) {
// 업데이트가 다운로드되었지만 설치되지 않은 경우 사용자에게 업데이트를 완료하도록 알립니다.
if (info.installStatus() == InstallStatus.DOWNLOADED)
flexibleUpdateDownloadCompleted()
} else if (currentType == AppUpdateType.IMMEDIATE) {
// IMMEDIATE(즉각적인)일때만 , 이미 업데이트 진행중인 상태입니다.
if (info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
startUpdate(info, AppUpdateType.IMMEDIATE)
}
}
}
}
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == MY_REQUEST_CODE) {
if (resultCode != AppCompatActivity.RESULT_OK) {
// 업데이트가 취소되거나 실패한 경우 업데이트를 다시 시작하도록 요청할 수 있습니다.
Log.e("ERROR", "Update flow failed! Result code: $resultCode")
}
}
}
private fun flexibleUpdateDownloadCompleted() {
Snackbar.make(
parentActivity.findViewById(R.id.activity_main_layout),
"An update has just been downloaded.",
Snackbar.LENGTH_INDEFINITE
).apply {
setAction("RESTART") { appUpdateManager.completeUpdate() }
setActionTextColor(Color.WHITE)
show()
}
}
fun onDestroy() {
appUpdateManager.unregisterListener(this)
}
override fun onStateUpdate(state: InstallState) {
if (state.installStatus() == InstallStatus.DOWNLOADED) {
flexibleUpdateDownloadCompleted()
}
}
}
InAppUpdate.kt 클래스를 초기화하고 onResume 및 onActivityResults 메서드를 액티비티(예.MainActivity)에 추가합니다.
class MainActivity : AppCompatActivity() {
private lateinit var inAppUpdate: InAppUpdate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
inAppUpdate = InAppUpdate(this)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
inAppUpdate.onActivityResult(requestCode,resultCode, data)
}
override fun onResume() {
super.onResume()
inAppUpdate.onResume()
}
override fun onDestroy() {
super.onDestroy()
inAppUpdate.onDestroy()
}
}
테스트
인앱 업데이트 솔루션을 테스트하려면 앱 을 내부테스트 트랙에 업로드하거나 내부 공유하기에 업로드하여 테스트할 수 있습니다.
'안드로이드 코틀린' 카테고리의 다른 글
[Kotlin][Android] DataBinding + RecyclerView 함께 사용해보기 (0) | 2022.11.18 |
---|---|
[Kotlin][Android] Jetpack Compose에서 폰트 추가해서 사용하기 (0) | 2022.11.03 |
[Kotlin] 알림 구현 - Action Button & Broadcast Receiver (0) | 2022.10.09 |
[Kotlin][Android] Jetpack Compose로 system bar 색 변경하기 (0) | 2022.09.27 |
[Kotlin][Android] PhotoView 라이브러리 사용법(사진 줌인&줌아웃&드래그 이동) (0) | 2022.09.12 |