Как добавить поддержку обновлений в приложении (Unreal Engine)

В этом руководстве рассказывается, как реализовать поддержку обновлений в приложении с помощью Unreal Engine. У нас есть отдельные руководства для случаев, когда вы используете язык программирования Kotlin или Java, нативный код (C/C++) или Unity.

Обзор Unreal Engine SDK

Play In-App Updates API входит в семейство Play Core SDK. API для Unreal Engine предлагает класс UInAppUpdatesManager, который обрабатывает обмен данными между вашим приложением и Play API. После отправки запроса приложение может проверить его статус с помощью EAppUpdateErrorCode.

Поддерживаемые версии Unreal Engine

Плагин поддерживает Unreal Engine 5.0 и все последующие версии.

Как настроить среду разработки

  1. Скачайте плагин Play Unreal Engine из хранилища GitHub.

  2. Скопируйте папку GooglePlay в папку Plugins в проекте Unreal Engine.

  3. Откройте проект Unreal Engine и нажмите Edit (Изменить) → Plugins (Плагины).

  4. Найдите Google Play и установите флажок Включено.

  5. Перезапустите проект игры и запустите сборку.

  6. Откройте файл Build.cs проекта и добавьте модуль PlayInAppUpdates в PublicDependencyModuleNames:

    using UnrealBuildTool;
    
    public class MyGame : ModuleRules
    {
      public MyGame(ReadOnlyTargetRules Target) : base(Target)
      {
        // ...
    
        PublicDependencyModuleNames.Add("PlayInAppUpdates");
    
        // ...
      }
    }
    

Проверьте наличие обновлений

Прежде чем запрашивать обновление, проверьте, доступно ли оно для вашего приложения. Для этого используйте UInAppUpdatesManager::RequestInfo.

MyClass.h

void MyClass::OnRequestInfoOperationCompleted(
  EAppUpdateErrorCode ErrorCode,
  UAppUpdateInfo* UpdateInfo)
{
  // Check the resulting error code.
  if (ErrorCode == EAppUpdateErrorCode::AppUpdate_NO_ERROR)
  {
    // Check AppUpdateInfo's UpdateAvailability, UpdatePriority,
    // IsUpdateTypeAllowed(), ... and decide whether to ask the user
    // to start an in-app update.
  }
}

MyClass.cpp

void MyClass::CheckForUpdateAvailability()
{
  // Create a delegate to bind the callback function.
  FRequestInfoOperationCompletedDelegate Delegate;

  // Bind the completion handler (OnRequestInfoOperationCompleted) to the delegate.
  Delegate.BindDynamic(this, &MyClass::OnRequestInfoOperationCompleted);

  // Initiate the request info operation, passing the delegate to handle the result.
  GetGameInstance()
    ->GetSubsystem<UInAppUpdatesManager>()
    ->RequestInfo(Delegate);
}

Возвращенный экземпляр UAppUpdateInfo содержит статус доступности обновления. Если обновление приложения уже выполняется, экземпляр также сообщает о его статусе.

Проверка актуальности обновления

Помимо проверки наличия обновления, вы также можете проверить, сколько времени прошло с момента последнего уведомления пользователя об обновлении через Google Play. Это поможет вам решить, какое обновление запустить: гибкое или немедленное. Например, вы можете подождать несколько дней, прежде чем уведомить пользователя о гибком обновлении, и ещё несколько дней, прежде чем потребовать немедленного обновления.

Используйте UAppUpdateInfo:GetClientVersionStalenessDays, чтобы узнать, сколько дней прошло с момента, когда обновление стало доступно в Google Play:

int32 ClientVersionStalenessDays = UpdateInfo->GetClientVersionStalenessDays();

Проверить приоритет обновления

Google Play Developer API позволяет задавать приоритет для каждого обновления. Это позволяет приложению решить, насколько настойчиво рекомендовать пользователю обновление. Например, можно использовать следующую стратегию:

  • Незначительные улучшения интерфейса. Низкий приоритет. Не запрашивайте ни гибкое, ни немедленное обновление.
  • Улучшение производительности. Средний приоритет. Запросите гибкое обновление.
  • Критическое обновление системы безопасности – высокий приоритет, требуется немедленное обновление.

Для определения приоритета Google Play использует целое число от 0 до 5, где 0 – значение по умолчанию, а 5 – наивысший приоритет. Чтобы задать приоритет обновления, используйте поле inAppUpdatePriority в разделе Edits.tracks.releases в Google Play Developer API. Все новые версии в выпуске имеют тот же приоритет, что и сам выпуск. Приоритет можно задать только при выпуске новой версии, и его нельзя изменить позже.

Задайте приоритет с помощью Google Play Developer API, как описано в документации по Play Developer API. Приоритет обновления приложения должен быть указан в ресурсе Edit.tracks, который передается в методе Edit.tracks: update. В примере ниже показано, как выпустить приложение с кодом версии 88 и inAppUpdatePriority 5:

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

В коде приложения можно проверить уровень приоритета для определенного обновления с помощью UAppUpdateInfo::UpdatePriority:

int32 Priority = UpdateInfo->GetPriority();

Как начать обновление

Если обновление доступно, вы можете запросить его с помощью UInAppUpdatesManager::StartUpdate. Прежде чем запрашивать обновление, убедитесь, что у вас есть актуальный объект UAppUpdateInfo. Вам также нужно создать объект UAppUpdateOptions, чтобы настроить процесс обновления.

В примере ниже создается объект UAppUpdateOptions для немедленного обновления.

// Creates an UAppUpdateOptions defining an immediate in-app
// update flow and its parameters.
UAppUpdateOptions* Options = NewObject<UAppUpdateOptions>();
Options->CreateOptions(EAppUpdateType::AppUpdate_TYPE_IMMEDIATE);

В следующем примере создается объект UAppUpdateOptions для гибкого обновления:

// Creates an UAppUpdateOptions defining a flexible in-app
// update flow and its parameters.
UAppUpdateOptions* Options = NewObject<UAppUpdateOptions>();
Options->CreateOptions(EAppUpdateType::AppUpdate_TYPE_FLEXIBLE);

Объект UAppUpdateOptions также содержит функцию IsAssetPackDeletionAllowed, которая возвращает информацию о том, разрешено ли обновлению удалять наборы объектов, если на устройстве недостаточно места. По умолчанию в этом поле задано значение false, но вы можете изменить его на true, используя UAppUpdateOptions::SetAssetPackDeletionAllowed:

// Sets the AssetPackDeletionAllowed field to true.
Options->SetAssetPackDeletionAllowed(true);

Дальнейшие действия зависят от того, какое обновление вы запрашиваете: гибкое или немедленное.

Как обработать гибкое обновление

После того как вы получите актуальный объект UAppUpdateInfo и правильно настроенный объект UAppUpdateOptions, вызовите метод UInAppUpdatesManager::StartUpdate, чтобы запросить процесс обновления.

MyClass.h

void MyClass::OnStartUpdateOperationCompleted(EAppUpdateErrorCode ErrorCode)
{
  // ...
}

MyClass.cpp

// .cpp
void MyClass::StartUpdate()
{
  // Create a delegate to bind the callback function.
  FUpdateOperationCompletedDelegate Delegate;

  // Bind the completion handler (OnStartUpdateOperationCompleted) to the delegate.
  Delegate.BindDynamic(this, &MyClass::OnStartUpdateOperationCompleted);

  // Initiate the start update operation, passing the delegate to handle the result.
  GetGameInstance()
    ->GetSubsystem<UInAppUpdatesManager>()
    ->StartUpdate(UpdateInfo, UpdateOptions, Delegate);
}

При гибком обновлении вы должны запустить установку обновления приложения после успешного завершения скачивания. Для этого вызовите InAppUpdatesManager::CompleteUpdate, как показано в примере ниже.

MyClass.h

void MyClass::OnCompleteUpdateOperationCompleted(EAppUpdateErrorCode ErrorCode)
{
  // ...
}

MyClass.cpp

void MyClass::CompleteFlexibleUpdate()
{
  // Create a delegate to bind the callback function.
  FUpdateOperationCompletedDelegate Delegate;

  // Bind the completion handler (OnCompleteUpdateOperationCompleted) to the delegate.
  Delegate.BindDynamic(this, &MyClass::OnCompleteUpdateOperationCompleted);

  // Initiate the complete update operation, passing the delegate to handle the result.
  GetGameInstance()
    ->GetSubsystem<UInAppUpdatesManager>()
    ->CompleteUpdate(UpdateInfo, UpdateOptions, Delegate);
}

Как обработать немедленное обновление

После того как вы получите актуальный объект UAppUpdateInfo и правильно настроенный объект UAppUpdateOptions, вызовите метод InAppUpdatesManager::StartUpdate, чтобы запросить процесс обновления.

MyClass.h

void MyClass::OnStartUpdateOperationCompleted(EAppUpdateErrorCode ErrorCode)
{
  // ...
}

MyClass.cpp

void MyClass::StartUpdate()
{
  // Create a delegate to bind the callback function.
  FUpdateOperationCompletedDelegate Delegate;

  // Bind the completion handler (OnStartUpdateOperationCompleted) to the delegate.
  Delegate.BindDynamic(this, &MyClass::OnStartUpdateOperationCompleted);

  // Initiate the start update operation, passing the delegate to handle the result.
  GetGameInstance()
    ->GetSubsystem<UInAppUpdatesManager>()
    ->StartUpdate(UpdateInfo, UpdateOptions, Delegate);
}

При немедленном обновлении Google Play показывает диалоговое окно с запросом подтверждения. Если пользователь соглашается, Google Play автоматически скачивает и устанавливает обновление, а затем перезапускает приложение.

Обработка ошибок

В этом разделе описаны решения распространенных проблем.

  • Если UInAppUpdatesManager::StartUpdate возвращает ошибку AppUpdate_INVALID_REQUEST, это означает, что UAppUpdateInfo недействителен. Прежде чем запускать процесс обновления, убедитесь, что объект UAppUpdateInfo, возвращенный из UInAppUpdatesManager::RequestInfo, не равен null.
  • Если метод UInAppUpdatesManager::StartUpdate возвращает ошибку AppUpdate_NOT_ALLOWED, это означает, что объект UAppUpdateOptions указывает на тип обновления, который не разрешен для доступного обновления. Перед запуском процесса обновления проверьте, указывает ли объект UAppUpdateInfo, что выбранный тип обновления разрешен.

Дальнейшие действия

Протестируйте обновления в приложении, чтобы убедиться, что интеграция работает правильно.