인앱 업데이트 지원

사용자 기기에서 앱을 최신 상태로 유지하면 사용자가 새로운 기능을 사용해 보고 성능 향상과 버그 수정을 통한 이점을 얻을 수 있습니다. 사용자 중에는 기기가 무제한 데이터에 연결되어 있을 때 백그라운드 업데이트를 진행하도록 설정하는 경우도 있지만 업데이트 알림이 필요한 사용자도 있을 수 있습니다. 인앱 업데이트는 활성 사용자에게 앱 업데이트 메시지를 표시하는 새로운 요청 흐름을 도입한 Play Core 라이브러리 기능입니다.

인앱 업데이트는 Android 5.0(API 수준 21) 이상을 실행하는 기기에서만 작동하며 Play Core 라이브러리 1.5.0 이상 사용이 필수입니다. 이러한 필수사항을 충족하면 앱은 인앱 업데이트의 다음 UX를 지원할 수 있습니다.

  • 유연: 원활한 상태 모니터링 기능과 함께 백그라운드 다운로드 및 설치를 제공하는 사용자 환경입니다. 이 UX는 사용자가 업데이트를 다운로드하는 동안 앱을 사용할 수 있는 경우에 적합합니다. 예를 들어 사용자에게 앱의 핵심 기능과는 크게 상관없는 새 기능을 사용해 보도록 유도하고자 할 때 사용할 수 있습니다.

    그림 1. 유연한 업데이트 흐름의 예

  • 즉시: 앱을 계속 사용하려면 사용자가 앱을 업데이트하고 다시 시작해야 하는 전체 화면 사용자 환경입니다. 이 UX는 업데이트가 앱을 계속 사용하는 데 중요한 경우에 가장 적합합니다. 사용자가 즉시 업데이트를 수락하면 Google Play가 업데이트 설치 및 앱 다시 시작을 처리합니다.

    그림 2. 즉시 업데이트 흐름의 예

이 페이지에서는 Play Core 라이브러리를 사용하여 유연한 인앱 업데이트 또는 즉시 인앱 업데이트를 요청하고 수행하는 방법을 보여줍니다.

업데이트 사용 가능 여부 확인

업데이트를 요청하기 전에 먼저 앱에 사용 가능한 업데이트가 있는지 확인해야 합니다. 업데이트를 확인하려면 아래에 표시된 것처럼 AppUpdateManager를 사용합니다.

Kotlin

    // Creates instance of the manager.
    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
            // For a flexible update, use AppUpdateType.FLEXIBLE
            && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
        ) {
            // Request the update.
        }
    }
    

자바

    // Creates instance of the manager.
    AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);

    // Returns an intent object that you use to check for an update.
    Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

    // Checks that the platform will allow the specified type of update.
    appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
        if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
              // For a flexible update, use AppUpdateType.FLEXIBLE
              && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
                  // Request the update.
        }
    });
    

결과에 업데이트 사용 가능 상태가 들어 있습니다. 사용 가능한 업데이트가 있고 업데이트가 허용되는 경우 반환되는 AppUpdateInfo에는 업데이트를 시작하기 위한 인텐트도 들어 있습니다. 업데이트를 시작하는 방법은 다음 섹션을 참조하세요.

인앱 업데이트가 이미 진행 중이면 진행 중인 업데이트의 상태도 결과에 보고됩니다.

업데이트 시작

앱을 업데이트할 수 있는지 확인한 후에는 아래에 표시된 것처럼 AppUpdateManager.startUpdateFlowForResult()를 사용하여 업데이트를 요청할 수 있습니다. 그러나 업데이트 요청을 너무 자주 보낼 경우 사용자가 귀찮아할 수도 있으므로 업데이트 요청 횟수를 염두에 두어야 합니다. 즉, 앱의 기능에 중요한 변경인 경우에만 인앱 업데이트를 요청하도록 제한해야 합니다.

Kotlin

    appUpdateManager.startUpdateFlowForResult(
        // Pass the intent that is returned by 'getAppUpdateInfo()'.
        appUpdateInfo,
        // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
        AppUpdateType.IMMEDIATE,
        // The current activity making the update request.
        this,
        // Include a request code to later monitor this update request.
        MY_REQUEST_CODE)
    

자바

    appUpdateManager.startUpdateFlowForResult(
        // Pass the intent that is returned by 'getAppUpdateInfo()'.
        appUpdateInfo,
        // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
        AppUpdateType.IMMEDIATE,
        // The current activity making the update request.
        this,
        // Include a request code to later monitor this update request.
        MY_REQUEST_CODE);
    

업데이트는 각 AppUpdateInfo 인스턴스를 사용하여 한 번만 시작할 수 있습니다. 실패한 경우 업데이트를 다시 시도하려면 새 AppUpdateInfo를 요청하고 업데이트가 사용 가능하고 허용되는지 다시 확인해야 합니다.

요청하는 업데이트 유형에 따라 필요한 그다음 단계가 결정됩니다. 자세한 내용은 즉시 업데이트 처리 방법 또는 유연한 업데이트 처리 방법에 관한 섹션을 참조하세요.

업데이트 상태에 관한 콜백 가져오기

업데이트를 시작한 후에는 아래에 나와 있는 것처럼 onActivityResult() 콜백을 사용하여 업데이트 실패 또는 취소를 처리할 수 있습니다.

Kotlin

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
        if (requestCode == MY_REQUEST_CODE) {
            if (resultCode != RESULT_OK) {
                log("Update flow failed! Result code: $resultCode")
                // If the update is cancelled or fails,
                // you can request to start the update again.
            }
        }
    }
    

자바

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (requestCode == MY_REQUEST_CODE) {
        if (resultCode != RESULT_OK) {
          log("Update flow failed! Result code: " + resultCode);
          // If the update is cancelled or fails,
          // you can request to start the update again.
        }
      }
    }
    

다음은 onActivityResult() 콜백에서 수신할 수 있는 서로 다른 값에 관한 설명입니다.

  • RESULT_OK: 사용자가 업데이트를 수락했습니다. 즉시 업데이트인 경우 앱에 업데이트 제어 권한이 주어졌을 때는 이미 Google Play가 업데이트를 완료한 상태여야 하기 때문에 개발자는 이 콜백을 수신하지 못할 수 있습니다.
  • RESULT_CANCELED: 사용자가 업데이트를 거부하거나 취소했습니다.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: 기타 오류로 인해 사용자가 동의하지 못했거나 업데이트가 진행되지 못했습니다.

유연한 업데이트 처리

유연한 업데이트를 시작하면 사용자에게 동의를 요청하는 대화상자가 먼저 표시됩니다. 사용자가 동의하면 백그라운드에서 다운로드가 시작되고 사용자는 앱과 상호작용을 계속할 수 있습니다. 이 섹션에서는 유연한 인앱 업데이트를 모니터링하고 완료하는 방법을 설명합니다.

유연한 업데이트 상태 모니터링

사용자가 유연한 업데이트를 수락하면 Google Play는 백그라운드에서 업데이트를 다운로드하기 시작합니다. 다운로드가 시작되면 앱은 업데이트 설치 가능 시점을 확인하고 앱의 UI에 진행 상황을 표시하기 위해 업데이트 상태를 모니터링해야 합니다.

설치 상태 업데이트 리스너를 등록하여 진행 중인 업데이트 상태를 모니터링할 수 있습니다.

Kotlin

    // Create a listener to track request state updates.
    val listener = { state ->
        // Show module progress, log state, or install the update.
    }

    // Before starting an update, register a listener for updates.
    appUpdateManager.registerListener(listener)

    // Start an update.

    // When status updates are no longer needed, unregister the listener.
    appUpdateManager.unregisterListener(listener)
    

자바

    // Create a listener to track request state updates.
    InstallStateUpdatedListener listener = state -> {
        // Show module progress, log state, or install the update.
      };

    // Before starting an update, register a listener for updates.
    appUpdateManager.registerListener(listener);

    // Start an update.

    // When status updates are no longer needed, unregister the listener.
    appUpdateManager.unregisterListener(listener);
    

유연한 업데이트 설치

유연한 업데이트 상태를 모니터링할 때 InstallStatus.DOWNLOADED 상태를 감지하는 경우 앱을 다시 시작해야 업데이트를 설치할 수 있습니다.

즉시 업데이트와 달리 Google Play는 자동으로 앱이 다시 시작하도록 하지 않습니다. 이는 유연한 업데이트에서는 사용자가 업데이트 설치 여부를 결정할 때까지 앱을 계속 사용하기를 바라기 때문입니다.

따라서 사용자에게 설치가 준비되었음을 알리고 앱 다시 시작을 위한 사용자 확인을 요청하는 알림(또는 기타 UI 표시)을 제공하는 것이 좋습니다.

예를 들어 그림 1에 나와 있는 것처럼 머티리얼 디자인을 사용한 스낵바 요청 확인을 구현하여 사용자로부터 앱을 다시 시작할지 확인받을 수 있습니다.

다음 코드 샘플은 유연한 업데이트가 다운로드된 후 사용자에게 표시되는 스낵바 알림을 나타낸 것입니다.

Kotlin

    override fun onStateUpdate(state: InstallState) {
        if (state.installStatus() == InstallStatus.DOWNLOADED) {
            // After the update is downloaded, show a notification
            // and request user confirmation to restart the app.
            popupSnackbarForCompleteUpdate()
        }
        ...
    }

    /* Displays the snackbar notification and call to action. */
    fun popupSnackbarForCompleteUpdate() {
        Snackbar.make(
            findViewById(R.id.activity_main_layout),
            "An update has just been downloaded.",
            Snackbar.LENGTH_INDEFINITE
        ).apply {
            setAction("RESTART") { appUpdateManager.completeUpdate() }
            setActionTextColor(resources.getColor(R.color.snackbar_action_text_color))
            show()
        }
    }
    

자바

    @Override
    public void onStateUpdate(InstallState state) {
      if (state.installStatus() == InstallStatus.DOWNLOADED) {
        // After the update is downloaded, show a notification
        // and request user confirmation to restart the app.
        popupSnackbarForCompleteUpdate();
      }
      ...
    }

    /* Displays the snackbar notification and call to action. */
    private void popupSnackbarForCompleteUpdate() {
      Snackbar snackbar =
          Snackbar.make(
              findViewById(R.id.activity_main_layout),
              "An update has just been downloaded.",
              Snackbar.LENGTH_INDEFINITE);
      snackbar.setAction("RESTART", view -> appUpdateManager.completeUpdate());
      snackbar.setActionTextColor(
          getResources().getColor(R.color.snackbar_action_text_color));
      snackbar.show();
    }
    

포그라운드에서 appUpdateManager.completeUpdate()를 호출하면 백그라운드에서 앱을 다시 시작하는 전체 화면 UI가 플랫폼에 표시됩니다. 플랫폼이 업데이트 설치를 끝내면 앱은 기본 작업으로 다시 시작됩니다.

대신 백그라운드에서 appUpdateManager.completeUpdate()를 호출하면 기기 UI를 가리지 않는 상태로 업데이트가 자동으로 설치됩니다.

사용자가 앱을 포그라운드로 가져오는 경우 개발자는 설치 대기 중인 업데이트가 없는지 확인하는 것이 좋습니다. 앱의 업데이트가 DOWNLOADED 상태이면 아래에 나와 있는 것처럼 사용자에게 업데이트 설치를 요청하는 알림을 표시하세요. 그러지 않으면 업데이트 데이터가 사용자의 기기 저장용량을 계속 차지합니다.

Kotlin

    // Checks that the update is not stalled during 'onResume()'.
    // However, you should execute this check at all app entry points.
    override fun onResume() {
        super.onResume()

        appUpdateManager
            .appUpdateInfo
            .addOnSuccessListener { appUpdateInfo ->
                ...
                // If the update is downloaded but not installed,
                // notify the user to complete the update.
                if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                    popupSnackbarForCompleteUpdate()
                }
            }
    }
    

자바

    // Checks that the update is not stalled during 'onResume()'.
    // However, you should execute this check at all app entry points.
    @Override
    protected void onResume() {
      super.onResume();

      appUpdateManager
          .getAppUpdateInfo()
          .addOnSuccessListener(appUpdateInfo -> {
                  ...
                  // If the update is downloaded but not installed,
                  // notify the user to complete the update.
                  if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                      popupSnackbarForCompleteUpdate();
                  }
              });
    }
    

즉시 업데이트 처리

즉시 업데이트를 수행 중이고 사용자가 업데이트 설치에 동의하는 경우 Google Play는 업데이트가 진행되는 내내 업데이트 진행 상황을 앱의 UI 상단에 표시합니다. 업데이트하는 동안 사용자가 앱을 닫거나 종료하더라도 추가 사용자 확인 없이 업데이트가 백그라운드에서 계속 다운로드되고 설치되어야 합니다.

하지만 앱이 포그라운드로 돌아오면 업데이트가 UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS 상태로 중단되지 않았는지 확인해야 합니다. 업데이트가 이 상태로 중단된 경우 아래와 같이 업데이트를 계속하세요.

Kotlin

    // Checks that the update is not stalled during 'onResume()'.
    // However, you should execute this check at all entry points into the app.
    override fun onResume() {
        super.onResume()

        appUpdateManager
            .appUpdateInfo
            .addOnSuccessListener { appUpdateInfo ->
                ...
                if (appUpdateInfo.updateAvailability()
                    == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
                ) {
                    // If an in-app update is already running, resume the update.
                    appUpdateManager.startUpdateFlowForResult(
                        appUpdateInfo,
                        IMMEDIATE,
                        this,
                        MY_REQUEST_CODE
                    );
                }
            }
    }
    

자바

    // Checks that the update is not stalled during 'onResume()'.
    // However, you should execute this check at all entry points into the app.
    @Override
    protected void onResume() {
      super.onResume();

      appUpdateManager
          .getAppUpdateInfo()
          .addOnSuccessListener(
              appUpdateInfo -> {
                ...
                if (appUpdateInfo.updateAvailability()
                    == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                    // If an in-app update is already running, resume the update.
                    appUpdateManager.startUpdateFlowForResult(
                        appUpdateInfo,
                        IMMEDIATE,
                        this,
                        MY_REQUEST_CODE);
                }
              });
    }
    

문제해결

이 섹션에서는 인앱 업데이트가 테스트 중에 예상대로 작동하지 않을 수 있는 상황에서 사용할 수 있는 몇 가지 해결 방법을 설명합니다.

  • 인앱 업데이트는 앱을 소유한 사용자 계정만 이용할 수 있습니다. 따라서 사용 중인 계정으로 인앱 업데이트를 테스트하기 전에 그 계정이 Google Play에서 앱을 한 번 이상 다운로드했는지 확인합니다.
  • 인앱 업데이트를 테스트할 때 사용 중인 앱이 Google Play에서 제공되는 것과 동일한 애플리케이션 ID를 가지고 있고 동일한 서명 키로 서명되었는지 확인합니다.
  • Google Play는 앱을 상위 버전 코드로만 업데이트할 수 있으므로 테스트 중인 앱이 업데이트 버전 코드보다 낮은 버전 코드인지 확인합니다.
  • 계정이 유효하고 Google Play 캐시가 최신 상태인지 확인합니다. 이를 확인하려면 테스트 기기에서 Google Play 스토어 계정에 로그인하고 그 상태에서 다음 단계를 따르세요.
    1. Google Play 스토어 앱을 완전히 종료해야 합니다.
    2. Google Play 스토어 앱을 열고 내 앱/게임 탭으로 이동합니다.
    3. 테스트 중인 앱과 함께 사용 가능한 업데이트가 표시되지 않으면 올바로 테스트 트랙을 설정했는지 확인합니다.