# Usage

Essential Kit wraps native iOS iTunes Store API and Android Google Play In-App Update API into a single Unity interface. Check for updates, show customizable prompts, and guide users through the update process seamlessly.

## Table of Contents

* [Update Flow at a Glance](#update-flow-at-a-glance)
* [Understanding Update Flow](#understanding-update-flow)
* [Import Namespaces](#import-namespaces)
* [Check Availability](#check-availability)
* [Check for Updates](#check-for-updates)
* [Show Update Prompt](#show-update-prompt)
* [Force Updates vs Optional Updates](#force-updates-vs-optional-updates)
* [Platform-Specific Behavior](#platform-specific-behavior)
* [Core APIs Reference](#core-apis-reference)
* [Error Handling](#error-handling)
* [Advanced: Manual Initialization](#advanced-manual-initialization)
* [Related Guides](#related-guides)

## Update Flow at a Glance

```
[Game session starts or player opens Settings]
                ↓
[AppUpdater.RequestUpdateInfo]
                ↓
[Store response → AppUpdaterUpdateInfo]
                ↓
[Decide prompt type (optional vs force)]
                ↓
[AppUpdater.PromptUpdate]
                ↓
[Platform-specific UI → restart or resume]
```

## Understanding Update Flow

App Updater follows a two-step process:

**1. Request Update Info** Query the app store to check if a newer version exists.

**2. Prompt Update** If an update is available, show a prompt and handle the update flow.

**Platform Differences:**

* **iOS**: Shows an alert that redirects users to the App Store
* **Android**: Supports in-app updates with progress tracking, or redirects to Play Store

## Import Namespaces

```csharp
using VoxelBusters.EssentialKit;
using VoxelBusters.CoreLibrary;
```

## Check Availability

Call `IsAvailable()` before making requests so you can gracefully fall back if the feature is stripped from the build:

```csharp
if (!AppUpdater.IsAvailable())
{
    Debug.LogWarning("App Updater is not available on this platform or build.");
    return;
}
```

## Check for Updates

Request update information from the app store:

```csharp
void CheckForUpdates()
{
    if (!AppUpdater.IsAvailable())
    {
        Debug.LogWarning("App Updater is not available on this platform or build.");
        return;
    }

    AppUpdater.RequestUpdateInfo((result, error) =>
    {
        if (error != null)
        {
            Debug.LogError($"Failed to check for updates: {error.Description}");
            return;
        }

        Debug.Log($"Update status: {result.Status}");

        switch (result.Status)
        {
            case AppUpdaterUpdateStatus.Available:
                Debug.Log("Update available!");
                ShowUpdatePrompt(isForceUpdate: false);
                break;

            case AppUpdaterUpdateStatus.Downloaded:
                Debug.Log("Update already downloaded, ready to install");
                InstallDownloadedUpdate();
                break;

            case AppUpdaterUpdateStatus.NotAvailable:
                Debug.Log("App is up to date");
                break;

            case AppUpdaterUpdateStatus.InProgress:
                Debug.Log("Update is already in progress");
                break;

            case AppUpdaterUpdateStatus.Unknown:
                Debug.LogWarning("Could not determine update status");
                break;
        }
    });
}
```

### Update Status Values

| Status         | Meaning                                            | Next Action                                                       |
| -------------- | -------------------------------------------------- | ----------------------------------------------------------------- |
| `Available`    | New version exists on the store                    | Call `PromptUpdate()` to show update dialog                       |
| `Downloaded`   | Update downloaded but not installed (Android only) | Call `PromptUpdate()` with `AllowInstallationIfDownloaded = true` |
| `NotAvailable` | App is up to date                                  | No action needed                                                  |
| `InProgress`   | Update is currently downloading                    | Wait for completion                                               |
| `Unknown`      | Unable to determine status                         | Check error for details                                           |

{% hint style="info" %}
`Downloaded` status appears only on Android when using In-App Update flexible flow. The update is ready to install without additional downloads.
{% endhint %}

## Show Update Prompt

After confirming an update is available, show a prompt:

```csharp
void ShowUpdatePrompt(bool isForceUpdate)
{
    var options = new PromptUpdateOptions.Builder()
        .SetPromptTitle("Update Available")
        .SetPromptMessage("A new version with bug fixes and improvements is ready!")
        .SetIsForceUpdate(isForceUpdate)
        .Build();

    AppUpdater.PromptUpdate(options, (progress, error) =>
    {
        if (error != null)
        {
            Debug.LogError($"Update failed: {error.Description}");
            return;
        }

        Debug.Log($"Update progress: {progress * 100}%");

        if (progress >= 1.0f)
        {
            Debug.Log("Update completed successfully");
        }
    });
}
```

### PromptUpdateOptions Builder

| Method                                   | Parameter    | Description                                                                                      |
| ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------ |
| `SetPromptTitle(string)`                 | Title text   | Title displayed in update dialog                                                                 |
| `SetPromptMessage(string)`               | Message text | Message explaining why user should update                                                        |
| `SetIsForceUpdate(bool)`                 | true/false   | If true, user cannot dismiss the prompt (default: false)                                         |
| `SetAllowInstallationIfDownloaded(bool)` | true/false   | Android: install immediately if the flexible flow already downloaded the package (default: true) |
| `Build()`                                | -            | Returns configured `PromptUpdateOptions` instance                                                |

### Progress Callback

The progress callback fires multiple times during the update:

**iOS Behavior:**

* Fires once with `progress = 1.0f` if user chose to update
* Fires with `progress = 0.0f` if user dismissed the prompt (only for optional updates)

**Android Behavior:**

* Fires multiple times with progress from `0.0f` to `1.0f` during in-app download
* Falls back to iOS behavior if In-App Update is unavailable

{% hint style="success" %}
Show a loading indicator during Android in-app updates by tracking progress. The callback fires frequently with updated progress values.
{% endhint %}

## Force Updates vs Optional Updates

### Optional Updates (Default)

Allow users to dismiss the prompt and continue using the app:

```csharp
void ShowOptionalUpdate()
{
    var options = new PromptUpdateOptions.Builder()
        .SetPromptTitle("New Features Available!")
        .SetPromptMessage("Update now to try our new tournament mode!")
        .SetIsForceUpdate(false) // User can dismiss
        .Build();

    AppUpdater.PromptUpdate(options, (progress, error) =>
    {
        if (error == null && progress >= 1.0f)
        {
            Debug.Log("User accepted update");
        }
        else if (error == null && progress == 0.0f)
        {
            Debug.Log("User dismissed update");
        }
    });
}
```

### Force Updates (Blocking)

Prevent users from dismissing until they update:

```csharp
void ShowForceUpdate()
{
    var options = new PromptUpdateOptions.Builder()
        .SetPromptTitle("Critical Update Required")
        .SetPromptMessage("This update contains important security fixes and is required to continue.")
        .SetIsForceUpdate(true) // Cannot dismiss
        .Build();

    AppUpdater.PromptUpdate(options, (progress, error) =>
    {
                if (error != null)
                {
                    Debug.LogError($"Force update failed: {error.Description}");
                    Debug.LogError("Show retry UI so the player can attempt the update again.");
                }
        else if (progress >= 1.0f)
        {
            Debug.Log("Force update completed");
        }
    });
}
```

{% hint style="warning" %}
Use force updates sparingly. Users cannot play your game until they update, which may lead to frustration. Reserve for critical bugs or security issues.
{% endhint %}

## Platform-Specific Behavior

### iOS

* Uses iTunes Store API to query for updates
* Shows native alert dialog with App Store redirect
* No progress tracking (binary result: updated or dismissed)
* Requires valid App Store ID in Essential Kit Settings

```csharp
// iOS prompt flow
AppUpdater.PromptUpdate(options, (progress, error) =>
{
    if (progress >= 1.0f)
    {
        // User tapped "Update" and was redirected to App Store
        // App will terminate when user returns after updating
    }
});
```

### Android

* Uses Google Play In-App Update API for seamless updates
* Shows in-app update UI with progress tracking
* Falls back to Play Store redirect if In-App Update fails
* Requires valid package name in Essential Kit Settings

```csharp
void PromptUpdateWithProgress()
{
    // Android prompt flow with progress
    AppUpdater.PromptUpdate(options, (progress, error) =>
    {
        // Android fires multiple times with increasing progress
        if (progress > 0 && progress < 1.0f)
        {
            Debug.Log($"Downloading: {progress * 100}%");
            Debug.Log($"Update progress bar to {progress * 100}%.");
        }
        else if (progress >= 1.0f)
        {
            Debug.Log("Download complete, installing...");
        }
    });
}
```

### Install Downloaded Update (Android)

If status is `Downloaded`, install without re-downloading:

```csharp
void InstallDownloadedUpdate()
{
    var options = new PromptUpdateOptions.Builder()
        .SetPromptTitle("Install Update")
        .SetPromptMessage("Update is ready to install. App will restart.")
        .SetAllowInstallationIfDownloaded(true)
        .Build();

    AppUpdater.PromptUpdate(options, (progress, error) =>
    {
        if (error == null && progress >= 1.0f)
        {
            Debug.Log("Installing update...");
        }
    });
}
```

## Core APIs Reference

| API                                          | Purpose                                               | Returns                                         |
| -------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------- |
| `AppUpdater.RequestUpdateInfo(callback)`     | Query app store for available updates                 | `AppUpdaterUpdateInfo` with status via callback |
| `AppUpdater.PromptUpdate(options, callback)` | Show update prompt to user                            | Float progress (0-1) via callback               |
| `AppUpdater.IsAvailable()`                   | Check if App Updater is available on current platform | `bool`                                          |
| `PromptUpdateOptions.Builder()`              | Configure update prompt                               | Chain `.SetX()` methods → `Build()`             |

## Error Handling

Handle errors in both `RequestUpdateInfo` and `PromptUpdate` callbacks:

```csharp
void CheckForUpdates()
{
    AppUpdater.RequestUpdateInfo((result, error) =>
    {
        if (error != null)
        {
            HandleUpdateError(error);
            return;
        }

        if (result.Status == AppUpdaterUpdateStatus.Available)
        {
            ShowUpdatePrompt(false);
        }
    });
}

void HandleUpdateError(Error error)
{
    var code = (AppUpdaterErrorCode)error.Code;

    switch (code)
    {
        case AppUpdaterErrorCode.NetworkIssue:
            Debug.LogWarning("No internet connection - cannot check for updates.");
            Debug.LogWarning("Show an in-game network error prompt with retry.");
            break;

        case AppUpdaterErrorCode.UpdateInfoNotAvailable:
            Debug.LogWarning("Call RequestUpdateInfo before prompting the update.");
            break;

        case AppUpdaterErrorCode.UpdateNotAvailable:
            Debug.Log("User already has the latest version.");
            break;

        case AppUpdaterErrorCode.UpdateInProgress:
            Debug.Log("Update is already running in another flow. Show progress UI.");
            break;

        case AppUpdaterErrorCode.UpdateNotCompatible:
            Debug.LogError("Device cannot install the target build (architecture or version mismatch).");
            break;

        case AppUpdaterErrorCode.UpdateCancelled:
            Debug.LogWarning("User cancelled the update.");
            break;

        default:
            Debug.LogError($"Update check failed: {error.Description}");
            break;
    }
}
```

### Common Error Codes

| Error Code               | Trigger                                          | Recommended Action                                      |
| ------------------------ | ------------------------------------------------ | ------------------------------------------------------- |
| `NetworkIssue`           | No internet connection                           | Show error message and retry button                     |
| `UpdateInfoNotAvailable` | `PromptUpdate` called before `RequestUpdateInfo` | Request info first or handle null result                |
| `UpdateNotAvailable`     | Store reports no newer build                     | Hide update UI and continue                             |
| `UpdateInProgress`       | Another update flow is already running           | Reuse or resume that flow instead of starting a new one |
| `UpdateCancelled`        | User backed out of the update UI                 | Offer a "Try again" button or continue gameplay         |
| `UpdateNotCompatible`    | Device cannot install the target build           | Inform player and prompt them to update their OS/device |
| `Unknown`                | Platform-specific error                          | Log for diagnostics, show generic error to user         |

{% hint style="info" %}
Always handle errors gracefully. Update checks can fail due to network issues, store API changes, or configuration problems.
{% endhint %}

## Advanced: Manual Initialization

Essential Kit auto-initializes App Updater from the Essential Kit Settings asset. Only use manual initialization for runtime configuration:

```csharp
void Awake()
{
    var settings = new AppUpdaterUnitySettings(
        isEnabled: true,
        defaultPromptTitle: "Server-driven title",
        defaultPromptMessage: "Server-driven message");

    AppUpdater.Initialize(settings);
}
```

**Use Cases for Manual Initialization:**

* Setting custom update prompt defaults from server configuration
* Configuring different update policies for beta vs production builds
* Loading app store URLs dynamically from server
* Implementing A/B testing for update messaging

{% hint style="warning" %}
Advanced initialization is for specific scenarios only. For most games, use [standard setup](/features/app-updater/setup.md) with Essential Kit Settings.
{% endhint %}

## Related Guides

* Demo scene: `Assets/Plugins/VoxelBusters/EssentialKit/Examples/Scenes/AppUpdaterDemo.unity`
* Pair with **Network Services** to check connectivity before requesting updates
* Use with **Notification Services** to remind users about pending updates
* Combine with **Native UI** for custom update dialog designs

{% hint style="success" %}
Ready to test? Head to the [Testing Guide](/features/app-updater/testing.md) to validate your implementation.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://assetstore.essentialkit.voxelbusters.com/features/app-updater/usage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
