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
onInstallshould trigger, and the signing requirements. - Privacy: recording the install lifecycle with
reportInstall(...).