Skip to content

The update prompt

Once checkForUpdate() reports updateAvailable, you show the user a prompt. You have two options: the built-in SwiftUI UpdatePromptView, or your own UI built from the returned data. There is no delegate or callback protocol; your app owns the presentation.

The built-in view

AppGantrySDK ships an optional SwiftUI view. It is available on iOS 16, macOS 13, tvOS 16, and watchOS 9.

public struct UpdatePromptView: View {
    public init(
        content: UpdatePromptContent,
        onInstall: @escaping () -> Void,
        onLater: (() -> Void)? = nil
    )
}

You give it a UpdatePromptContent, an onInstall closure to run when the user confirms, and an optional onLater closure for dismissal.

Building the content

UpdatePromptContent is Sendable and Equatable. The convenient initializer builds it from an UpdateInfo plus optional metadata and icon bytes:

public struct UpdatePromptContent: Sendable, Equatable {
    public init(update: UpdateInfo, metadata: AppMetadata? = nil, iconData: Data? = nil)

    public init(
        appName: String,
        versionName: String? = nil,
        buildNumber: Int? = nil,
        releaseNotes: String? = nil,
        isMandatory: Bool = false,
        iconData: Data? = nil
    )
}

Putting it together:

let info = try await updates.checkForUpdate()
guard info.updateAvailable else { return }

let metadata = try await updates.appMetadata()
let icon = try await updates.iconData(for: metadata)
let content = UpdatePromptContent(update: info, metadata: metadata, iconData: icon)

UpdatePromptView(
    content: content,
    onInstall: { Task { try await updates.beginInstall(for: info) } },
    onLater: { /* dismiss the prompt */ }
)

Mandatory updates hide "Later"

When the update is mandatory (info.isMandatory is true), the view hides the "Later" button automatically, so the user cannot dismiss it. Your onLater closure is simply not invoked in that case.

Graceful degradation

The icon and the release notes are optional. If iconData is nil (for example the app has no icon, so iconData(for:) returns nil) or the release has no notes, the view renders cleanly without them. You do not need to special-case their absence.

Building your own UI

If the built-in view does not fit your design, build your own prompt. Everything you need is on the returned models: no delegate is involved, you just read the values and render whatever you like.

let info = try await updates.checkForUpdate()
guard info.updateAvailable else { return }

let metadata = try await updates.appMetadata()
let icon = try await updates.iconData(for: metadata) // nil if none

// Read the fields you care about and drive your own view:
let title = metadata.name
let version = info.latestVersionName ?? metadata.latestVersionName
let notes = info.releaseNotes            // may be nil
let mustInstall = info.isMandatory       // hide your dismiss control

The fields available on UpdateInfo and AppMetadata are listed in Installing updates and Tokens and errors. When the user confirms, call beginInstall(for:) exactly as you would from the built-in view's onInstall closure.

Next

  • Installing updates: what onInstall should trigger, and the signing requirements.
  • Privacy: recording the install lifecycle with reportInstall(...).