[Android] 인앱 업데이트

박주호·2022년 2월 11일
1

Hi, Android

목록 보기
6/7
post-thumbnail
post-custom-banner

🧑‍💻 IN-APP Update란?

안드로이드 앱을 실행할 때 해당 앱에 대한 업데이트 정보를 플레이스토어에서 가져와 업데이트 가능 여부를 판단하고 앱 내부에서 즉시 혹은 유연한 업데이트를 통해 사용자가 플레이스토어를 접속하지 않더라도 Play Core라이브러리를 사용해 UX흐름을 지원할 수 있는 기능입니다.

사용하는 이유

  1. 별다른 서버가 필요하지 않다.
  2. 플레이스토어 정보(버전 우선순위, 출시 기간 등)에 따라 업데이트를 강제 혹은 보류 할 수 있다.
  3. 사용자가 플레이스토어에 접속하여 업데이트를 진행하지 않아도 된다.

구현방법

dependencies {
. . .
	implementation 'com.google.android.play:core:1.10.2'
}

[즉시업데이트 기준 설명]

val appUpdateManager = AppUpdateManagerFactory.create(context)

// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo

// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
        // This example applies an immediate update. To apply a flexible update
        // instead, pass in AppUpdateType.FLEXIBLE
        && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
    ) {
        // Request the update.
    }
}

appUpdateManager 인스턴스의 업데이트 정보를 불러오고 리스너로 업데이트 가능여부를 체크합니다. 이때 업데이트 조건을 설정할 수 있습니다. IMMEDIATE , FLEXIBLE 혹은 (appUpdateInfo.clientVersionStalenessDays() ?: -1) >= DAYS_FOR_FLEXIBLE_UPDATE 스토어에 업데이트가 제공된 이후의 일 수도 가능합니다.

플레이스토어에 출시되면 출시 트랙마다 아래와 같이 릴리즈 정보가 생성이 됩니다.

{
  "releases": [{
      "versionCodes": ["88"],
      "inAppUpdatePriority": 5,
      "status": "completed"
  }]
}

inAppUpdatePriority 의 경우 0부터 5까지 존재하며 높을수록 높은 우선순위를 의미합니다. 디폴트 값은 0으로 지정되어 있습니다.

Google Developer API 를 통해 값을 변경할 수 있다고 공식문서에 설명되어 있습니다.(아직 적용 x)

appUpdateManager.startUpdateFlowForResult(
    appUpdateInfo,
		IMMEDIATE,
    this,
    REQUEST_CODE_UPDATE
)

Request the update 부분에 업데이트 정보를 넣어주고 업데이트를 요청합니다.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_UPDATE) {
            if (resultCode != Activity.RESULT_OK) {
                Toast.makeText(this, "업데이트가 취소 되었습니다.", Toast.LENGTH_SHORT).show()

                val appUpdateInfoTask: Task<AppUpdateInfo> = appUpdateManager.appUpdateInfo

                appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
                    if (appUpdateInfo.updateAvailability() === UpdateAvailability.UPDATE_AVAILABLE) {
                        if(appUpdateInfo.isUpdateTypeAllowed(IMMEDIATE)){
                            val dialog = ContentDialog(
                                this,
                                "업데이트 알림",
                                "필수 업데이트가 있습니다.\n최적의 사용 환경을 위해 최신 버전으로 업데이트 해주세요."
                            )
                            dialog.apply {
                                addFirstButton("확인") {
                                    dialog.dismiss()
                                    // 업데이트를 다시 요청한다.
                                    requestUpdate(appUpdateInfo)
                                }
                                addSecondButton("나가기"){
                                    dialog.dismiss()
                                    finish()
                                }
                            }.show()
                        }
                    }
                }
            }
        }
}

onActivityResult 메소드에서 해당하는 리퀘스트 코드를 전달받고 결과에 따른 분기처리를 해줍니다.

유의사항으로 즉시 업데이트의 경우 사용자가 앱을 닫거나 종료하더라도 추가 사용자 확인 없이 업데이트가 백그라운드에서 계속 다운로드되고 설치되어야 합니다. 그 과정에서 앱이 포그라운드로 돌아왔을 때 업데이트가 중단되었는지(DEVELOPER_TRIGGERED_UPDATE_IN_PROGRES상태인지) 확인해야하며 중단되었다면 다시 시작하는 로직을 아래와 같이 추가해주어야 합니다.

override fun onResume() {
    super.onResume()

    // 업데이트 진행 중 확인
    appUpdateManager
        .appUpdateInfo
.addOnSuccessListener{appUpdateInfo: AppUpdateInfo->
if (appUpdateInfo.updateAvailability()
                == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
) {
                // If an in-app update is already running, resume the update.
                requestUpdate(appUpdateInfo)
            }
}
}

테스트는 개발자 콘솔의 내부앱 공유를 이용하면 편합니다.

결과 예시

참고

인앱 업데이트
인앱 업데이트 지원 - 코틀린

profile
항상 배우려는 자세로
post-custom-banner

0개의 댓글