manasv/updeto
`Updeto` is a lightweight Swift SDK to check whether the currently installed app version is up to date on the App Store.
Why Use It
- 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
Requirements
- Swift 5.10+
- iOS 15+
- macOS 12+
- tvOS 15+
Installation
Swift Package Manager
.package(url: "https://github.com/manasv/Updeto.git", from: "1.0.0")Quick Start
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)How It Works
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.
API Usage
Async/Await
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)
}
}Combine
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)
}Completion Callback
import Updeto
let updeto = Updeto()
updeto.isAppUpdated { result in
print(result)
}Error-Aware APIs
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)
}
}Rich Metadata Output
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)
}
}
}Dependency Injection
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())Public Types
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)
Notes
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.
Live Integration Test (Opt-in)
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 testLicense
MIT © 2025 Manuel Sánchez
Package Metadata
Repository: manasv/updeto
Default branch: main
README: README.md