Updeto is a lightweight Swift SDK to check whether the currently installed app version is up to date on the App Store.
It exposes the same check in three styles:
async/awaitCombine- completion callback
- optional error-aware variants (
Result/throwing/failing publisher) - optional rich metadata output (
AppStoreUpdateInfo)
- No App Store scraping logic in your app code
- Consistent result model (
AppStoreLookupResult) - Provider architecture, so you can swap App Store checks for your own backend
- Storefront-aware lookup via optional
countryparameter - Configurable
requestTimeoutandretryCount
- Swift 5.10+
- iOS 15+
- macOS 12+
- tvOS 15+
.package(url: "https://github.com/manasv/Updeto.git", from: "1.0.0")import Updeto
let updeto = Updeto()
updeto.isAppUpdated { result in
switch result {
case .updated:
print("You're on the latest version.")
case .outdated:
print("An update is available.")
case .developmentOrBeta:
print("Installed version is newer than App Store (dev/beta).")
case .noResults:
print("No App Store match found for this bundle ID.")
}
}If you want to force a specific App Store storefront:
import Updeto
let provider = AppStoreProvider(
bundleId: "com.example.app",
installedAppVersion: "1.0.0",
country: "US",
requestTimeout: 10,
retryCount: 1
)
let updeto = Updeto(provider: provider)Updeto is a facade over a pluggable UpdateProvider.
Default flow:
UpdetousesAppStoreProvider.AppStoreProviderbuilds a lookup request to Apple iTunes Lookup API using yourbundleId.- The API response is decoded into
AppStoreLookup. - App Store version is compared with installed version.
- SDK returns one
AppStoreLookupResult.
Version comparison behavior:
appStoreVersion == installedVersion->.updatedappStoreVersion > installedVersion->.outdatedappStoreVersion < installedVersion->.developmentOrBeta- no decode/result ->
.noResults
Storefront behavior:
- If
countryis set, lookup includescountry=<CODE>(for exampleUS). - If
countryisnil, provider uses current locale region by default.
import Updeto
let updeto = Updeto()
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
Task {
let result = await updeto.isAppUpdated()
print(result.description)
}
}import Combine
import Updeto
let updeto = Updeto()
var cancellables = Set<AnyCancellable>()
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
updeto.isAppUpdated()
.sink { result in
print(result)
}
.store(in: &cancellables)
}import Updeto
let updeto = Updeto()
updeto.isAppUpdated { result in
print(result)
}Use these variants when you need to distinguish network, decode, and HTTP failures from .noResults.
import Updeto
let updeto = Updeto()
updeto.isAppUpdatedResult { result in
switch result {
case .success(let status):
print(status)
case .failure(let error):
print(error)
}
}Use updateInfo when you need more than enum-only status.
import Updeto
let updeto = Updeto()
updeto.updateInfo { info in
print(info.result) // .updated / .outdated / ...
print(info.installedVersion) // local version
print(info.storeVersion ?? "-")
print(info.appId ?? "-")
print(info.country ?? "-")
}import Updeto
let updeto = Updeto()
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
Task {
do {
let info = try await updeto.updateInfoResult()
print(info.result)
print(info.storeVersion ?? "-")
} catch {
print(error)
}
}
}Inject your own provider if your update source is not App Store.
import Combine
import Foundation
import Updeto
final class InternalReleaseProvider: UpdateProvider {
let bundleId: String = "com.example.app"
let installedAppVersion: String = "1.0.0"
var appId: String = ""
var appstoreURL: URL? { nil }
func isAppUpdated(completion: @escaping (AppStoreLookupResult) -> Void) {
completion(.updated)
}
@available(iOS 15.0, macOS 12.0, tvOS 15.0, *)
func isAppUpdated() -> AnyPublisher<AppStoreLookupResult, Never> {
Just(.updated).eraseToAnyPublisher()
}
}
let updeto = Updeto(provider: InternalReleaseProvider())Updeto: entry point used by appsAppStoreProvider: default implementation calling Apple lookup APIUpdateProvider: protocol for custom providersAsyncUpdateProvider: optional async protocol for custom providersAppStoreLookupResult: enum output (updated,outdated,developmentOrBeta,noResults)AppStoreUpdateInfo: rich output withresult,installedVersion,storeVersion,appId,bundleId,countryUpdetoError: error output for error-aware APIs (network,badServerResponse,decoding)
appstoreURLbecomes available when an App StoreappIdis resolved..noResultscan mean invalid bundle ID, network/decode failure, or no store match.- Apple lookup availability depends on region/store state.
Updeto includes an opt-in live test (Tests/UpdetoLiveIntegrationTests.swift) for nightly CI checks.
UPDETO_RUN_LIVE_TESTS=1 \
UPDETO_LIVE_BUNDLE_ID=com.example.app \
UPDETO_LIVE_COUNTRY=US \
swift testMIT © 2025 Manuel Sánchez