Skip to main content

Swift SDK Changelog

This page documents version-by-version API changes for the AppCoins iOS Swift SDK. Each entry lists breaking changes, new features, and migration steps where applicable.


Version 5.x (Upcoming)

Breaking Changes

  • PurchaseIntent removed — the PurchaseIntent type, the Purchase.updates stream, PurchaseIntent.confirm(), and PurchaseIntent.reject() are all removed. Purchase results are now returned directly from product.purchase() as VerificationResult<Transaction>.

  • Product property renames — three properties on Product have been renamed to align with the StoreKit 2 naming convention:

    Old nameNew name
    product.skuproduct.id
    product.titleproduct.displayName
    product.priceLabelproduct.displayPrice
  • Product.products() signature change — the domain: parameter has been removed:

    OldNew
    Product.products(for: ["sku"], domain: "com.example.app")Product.products(for: ["sku"])
  • Purchase type replaced by Transaction — the Purchase type no longer exists. All transaction data is now represented by Transaction.

  • purchase() now throws — the .failed(let error) case has been removed from Product.PurchaseResult. Errors are now thrown. Wrap all calls to product.purchase() in a do/catch block.

  • Purchase.unfinished() replaced by Transaction.unfinished stream — the function returning [Purchase] is replaced by a non-throwing AsyncStream:

    OldNew
    let purchases = try await Purchase.unfinished()for await result in Transaction.unfinished { }
  • transaction.finish() no longer throws — replace try await purchase.finish() with await transaction.finish().

  • transaction.id is now String — previously typed as UInt64. Update any code that stores, compares, or transmits this value as a number.

New Features

  • Transaction.all — an AsyncStream<VerificationResult<Transaction>> of the full transaction history for the app, newest first.

  • Transaction.latest(for:) — async static method returning the most recent VerificationResult<Transaction>? for a given product identifier.

  • product.latestTransaction — async computed property on Product returning the most recent transaction for that product.

  • product.currentEntitlement — async computed property on Product returning the current unfinished transaction for that product, if one exists.

Migration Steps

  1. Replace all Purchase references with Transaction. Use Xcode's Find & Replace (Cmd+Shift+H) to rename the type across your project.

  2. Rename product properties. Replace product.skuproduct.id, product.titleproduct.displayName, product.priceLabelproduct.displayPrice.

  3. Remove the domain: parameter from Product.products() calls.

  4. Wrap product.purchase() in do/catch and remove the .failed case.

    Before:

    let result = await product.purchase()
    switch result {
    case .success(let verification): break
    case .pending: break
    case .userCancelled: break
    case .failed(let error): print("Purchase failed: \(error)")
    }

    After:

    do {
    let result = try await product.purchase()
    switch result {
    case .success(let verification): break
    case .pending: break
    case .userCancelled: break
    }
    } catch {
    print("Purchase failed: \(error)")
    }
  5. Change try await purchase.finish() to await transaction.finish().

  6. Replace Purchase.unfinished() with the Transaction.unfinished stream.

    Before:

    let purchases = try await Purchase.unfinished()
    for purchase in purchases {
    giveItemToUser(productID: purchase.productID)
    try await purchase.finish()
    }

    After:

    for await verificationResult in Transaction.unfinished {
    switch verificationResult {
    case .verified(let transaction):
    giveItemToUser(productID: transaction.productID)
    await transaction.finish()
    case .unverified(let transaction, let error):
    print("Unverified: \(error.description)")
    }
    }
  7. Remove the Purchase.updates / PurchaseIntent stream. Handle purchase results from the product.purchase() return value instead. Use Transaction.unfinished on launch for recovery.

  8. Update transaction.id usages from UInt64 to String wherever the value is stored, compared, or transmitted.


Version 4.x (Current)

v4.3.3 — July 2026

Bug Fixes & Improvements

  • Improved attribution reliability with exponential backoff retry logic.
  • Increased log levels to ensure SDK lifecycle logs are persisted on device.

v4.3.2 — March 2026

Bug Fixes & Improvements

  • Fixed a bug where getWalletList returned a duplicated wallet after a guest-to-user account conversion.

v4.3.0 — March 2026

Bug Fixes & Improvements

  • Removed the SwiftyRSA dependency, which caused conflicts with Apple's MessageProtection framework. If you added a workaround for this conflict, it can be removed.
  • Added availability checks for the MarketplaceKit TransactionReporting API on Swift versions prior to 6.2.

v4.2.0 — February 2026

Bug Fixes & Improvements

  • Added installation_origin and oem_id parameters to the Web Checkout URL for improved attribution.

v4.1.2 — February 2026

Bug Fixes & Improvements

  • Fixed an issue where the MMP installation event was triggered regardless of installation source. The event now fires only for Aptoide-distributed installs.

v4.1.1 — February 2026

New Features

  • Added CTC (Catappult Token Contribution) transaction reporting. To enable reporting, add MKSellsDigitalGoods (YES, Boolean) to your app's Info.plist.

v4.0.1 — December 2025

Bug Fixes & Improvements

  • AppcSDK.isAvailable() now returns false by default again. The previous change that altered this default has been reverted.
  • Raised the web3swift package dependency version for Swift 6.2 compatibility.

v4.0.0 — November 2025

Breaking Changes

  • Sandbox.getTestingWalletAddress() is now async — add await to every call site:

    // Before
    let address = Sandbox.getTestingWalletAddress()

    // After
    let address = await Sandbox.getTestingWalletAddress()
  • AppcSDK.initialize() is now enforced — calls to product.purchase() will fail at runtime if initialize() has not been called at every app entry point. This was previously a recommendation; it is now a hard requirement.

New Features

  • Replaced the native checkout UI with a Web Checkout flow. No API changes are required beyond the breaking changes above — the SDK handles checkout presentation internally.
  • Added support for older iOS versions.

Migration Steps

  1. Add await to Sandbox.getTestingWalletAddress(). Find every call site and add await. Mark the enclosing function async if needed.

  2. Call AppcSDK.initialize() at every entry point. See the integration guide for the required setup in SceneDelegate and AppDelegate.

⚠️
AppcSDK.initialize() must be called at every application entry point. See the integration guide for the required setup in SceneDelegate and AppDelegate.

Version 3.x

v3.2.0 — August 2025

Bug Fixes & Improvements

  • AppcSDK.isAvailable() now returns false for TestFlight-distributed builds. Only apps distributed through Aptoide are eligible for AppCoins billing.

v3.1.0 — May 2025

New Features

  • Added a Manage Account sheet accessible from within the SDK.
  • Implemented the Delete Account flow.

v3.0.0 — May 2025

Breaking Changes

  • TransactionResult renamed to PurchaseResult — the enum returned by product.purchase() is renamed. Update all switch statements and type annotations:

    // Before
    let result: TransactionResult = await product.purchase()

    // After
    let result: PurchaseResult = await product.purchase()
  • Purchase.updates now emits PurchaseIntent — previously emitted VerificationResult. The stream now delivers a PurchaseIntent that must be explicitly confirmed or rejected before the purchase completes:

    // Before
    for await verificationResult in Purchase.updates {
    if case .verified(let purchase) = verificationResult {
    giveItem(for: purchase.sku)
    try await purchase.finish()
    }
    }

    // After
    for await intent in Purchase.updates {
    let result = await intent.confirm()
    if case .success(let verificationResult) = result,
    case .verified(let purchase) = verificationResult {
    giveItem(for: purchase.sku)
    try await purchase.finish()
    }
    }

New Features

  • PurchaseIntent.confirm() and PurchaseIntent.reject() for explicit two-step purchase completion.

Migration Steps

  1. Rename TransactionResult to PurchaseResult throughout your project using Xcode's Find & Replace (Cmd+Shift+H).

  2. Update Purchase.updates observers to handle PurchaseIntent. Call intent.confirm() to complete the purchase or intent.reject() to decline it.

📘
PurchaseIntent is removed in v5.x. If you are upgrading directly from v3.x to v5.x, skip PurchaseIntent entirely and follow the v5.x migration steps above.

Version 2.x

v2.1.1 — March 2025

Bug Fixes & Improvements

  • Fixed an issue where the developer callback was not invoked when mobile data was disabled during checkout.

v2.1.0 — March 2025

Bug Fixes & Improvements

  • Bug fixes and stability improvements.

v2.0.0 — February 2025

New Features

  • Purchase.updates — a new AsyncStream<VerificationResult> that delivers indirect in-app purchases initiated outside the app (for example, from a promotional link or the app's store page). Subscribe to this stream on app launch to receive and finish pending purchases:

    Task {
    for await verificationResult in Purchase.updates {
    if case .verified(let purchase) = verificationResult {
    giveItemToUser(productID: purchase.sku)
    try await purchase.finish()
    }
    }
    }

Version 1.x

v1.6.1 — December 2024

Bug Fixes & Improvements

  • Fixed a pagination issue where only the first page of results was returned on large product and purchase catalogs.
  • Auth localization and UI improvements.

v1.6.0 — November 2024

Bug Fixes & Improvements

  • Replaced URLImage with native AsyncImage to fix disappearing payment method icons.
  • Fixed bonus and balance amounts being rounded incorrectly.
  • Improved developer error debugging with more descriptive error messages.

v1.5.0 — October 2024

Bug Fixes & Improvements

  • Changed distribution format to .xcframework for improved compatibility.

v1.4.0 — October 2024

Bug Fixes & Improvements

  • Added landscape orientation support for the payment sheet.
  • Localization improvements with new language support.

v1.3.0 — August 2024

New Features

  • Added sandbox payment support for testing without real transactions.
  • Products now display prices in the user's local currency.

v1.2.0 — August 2024

New Features

  • Added verification data to Purchase to support server-side validation.

v1.1.0 — July 2024

New Features

  • Added MMP attribution support with guest_id and oem_id tracking parameters.
  • Sandbox.getTestingWalletAddress() is now synchronous.

v1.0.4 — July 2024

Bug Fixes & Improvements

  • Bug fixes and stability improvements.

v1.0.3 — May 2024

Bug Fixes & Improvements

  • Bug fixes and stability improvements.

v1.0.2 — May 2024

Bug Fixes & Improvements

  • Bug fixes and stability improvements.

v1.0.1 — April 2024

Bug Fixes & Improvements

  • Bug fixes and stability improvements.

v1.0.0 — February 2024

Initial Release

The first public release of the AppCoins iOS Swift SDK.

API surface:

  • Product.products(domain:for:) — fetches available in-app products by SKU.
  • product.purchase(domain:payload:orderID:) — initiates a purchase, returning TransactionResult (does not throw; errors surface as the .failed case).
  • TransactionResult.success(verificationResult:), .pending, .userCancelled, .failed(error:).
  • VerificationResult.verified(purchase:), .unverified(purchase:error:).
  • Purchase — transaction data class with uid, sku, state, orderUid, payload, created.
  • purchase.finish() — marks the purchase as consumed. Throws on failure.
  • Purchase.unfinished() — returns [Purchase] of unfinished purchases. Throws.
  • Purchase.all() — returns [Purchase] of all purchases. Throws.
  • Purchase.latest(sku:) — returns the most recent Purchase? for a given SKU. Throws.
  • AppcSDK.initialize() — registers the app with the SDK at launch.
  • AppcSDK.isAvailable() — returns whether AppCoins billing is active on this device.
  • AppcSDK.handle(redirectURL:) — processes billing deep link callbacks.