Skip to content

Installing updates

Once the user confirms, you install the new build. On iOS this happens over the air; on other platforms, or when you want the raw bytes, you resolve or download the release yourself.

Over-the-air install (iOS)

The SDK adds a UIKit-facing method on iOS (not watchOS):

@discardableResult
public func beginInstall(for update: UpdateInfo) async throws -> Bool

beginInstall(for:) opens the release's itms-services manifest URL with UIApplication.open, which asks iOS to install the new build in place. It returns false when the update has no iOS over-the-air manifest (so there is nothing to open), and true when the install was handed off to the system.

Under the hood the install uses an itms-services URL of the form:

itms-services://?action=download-manifest&url=<https manifest url>

If you need the manifest URL yourself (for example to open it through your own code path), resolve it directly:

public func iosInstallURL(for update: UpdateInfo) throws -> URL?

It returns the itms-services URL, or nil if the update has no iOS manifest. The HTTPS manifest URL carried inside it already includes a short-lived signed capability token, so treat it as sensitive and short-lived.

Signing and provisioning requirements

Over-the-air install has hard platform requirements that the SDK cannot work around:

  • The app must be signed for distribution to your testers: ad-hoc, enterprise/in-house, or another distribution profile that the target device trusts.
  • For ad-hoc distribution, the device must be provisioned (its UDID in the provisioning profile).

The SDK cannot install the binary itself

The SDK hands the install off to iOS by opening the manifest URL. It cannot install the .ipa in-process and cannot observe SpringBoard's install progress. After beginInstall(for:) returns, the system UI takes over. Use reportInstall(...) to record what your app knows (that an install was started), not to track SpringBoard.

Direct download

For non-iOS platforms, or when you want the bytes yourself instead of the iOS OTA install, resolve a signed URL or download the file:

// A signed URL to the release artifact. No download happens.
public func downloadURL(forRelease releaseId: UUID) async throws -> URL

// Downloads to a temporary file. The caller owns (and should clean up)
// the returned file.
public func downloadRelease(_ releaseId: UUID) async throws -> URL
let signedURL = try await updates.downloadURL(forRelease: info.releaseId!)
let fileURL = try await updates.downloadRelease(info.releaseId!) // you own the file

downloadRelease(_:) returns a temporary file URL that you own: move it where you need it and delete it when you are done.

Reporting the install lifecycle

Record where the install got to. This is optional and is the only data the SDK sends (see Privacy):

public func reportInstall(
    releaseId: UUID,
    state: InstallState,
    errorMessage: String? = nil
) async throws

InstallState is one of downloading, installing, installed, or failed. Pass errorMessage only on failed:

try await updates.reportInstall(releaseId: releaseId, state: .installing)
// ... later, if your own install flow fails ...
try await updates.reportInstall(
    releaseId: releaseId,
    state: .failed,
    errorMessage: "user cancelled"
)

The models

checkForUpdate() returns an UpdateInfo, and appMetadata() returns an AppMetadata.

public struct UpdateInfo: Codable, Sendable, Equatable {
    let updateAvailable: Bool
    let alreadyCurrent: Bool
    let isMandatory: Bool
    let releaseId: UUID?
    let platform: Platform?
    let latestVersionName: String?
    let latestBuildNumber: Int?
    let releaseNotes: String?
    let sizeBytes: Int?
    let releasedAt: Date?
    let downloadURL: String?     // path relative to /sdk/v1
    let iosManifestURL: String?  // path relative to /sdk/v1, signed
}
public struct AppMetadata: Codable, Sendable, Equatable {
    let name: String
    let platform: Platform
    let hasRelease: Bool
    let latestVersionName: String?
    let latestBuildNumber: Int?
    let minOSVersion: String?
    let iconURL: String?
}

downloadURL and iosManifestURL are paths relative to the /sdk/v1 base; prefer the downloadURL(forRelease:), downloadRelease(_:), iosInstallURL(for:), and beginInstall(for:) helpers, which resolve and sign them for you.

Next