light-mode-image
Learn
SDKs

iOS Holder SDK v5.0.0 Migration Guide

Overview

This guide provides a comprehensive overview of the changes introduced in MobileCredentialHolderSDK v5.0.0 for iOS, including breaking changes, new features, and migration steps.

Key Features

  • Seamless, OS-native credential presentation (DC API support): The iOS Holder SDK now integrates with the Digital Credentials API, allowing credentials to be presented via an OS overlay without launching your holder app. The OS automatically surfaces only matching credentials across installed holders — reducing friction, avoiding dead ends, and significantly improving the user experience.
  • Clearer OID4VCI interoperability (v1.0 alignment): The iOS Holder SDK now aligns with the finalized OID4VCI v1.0 specification (upgraded from draft-12). This alignment improves interoperability across the ecosystem, enabling other systems to clearly identify your supported version and feature set, ensuring smoother integrations and consistent behavior across platforms.
  • Improved reliability in contactless flows: Enhanced BLE performance delivers more consistent proximity credential exchanges and faster engagements.
  • Stronger cryptography and standards alignment: Updated COSE algorithms (as per RFC 9864) strengthen cryptographic compatibility and ensure continued compliance with evolving standards.
  • General stability and performance improvements: Multiple refinements reduce integration friction, increase consistency across mobile environments, and improve overall user experience.

For a detailed list of changes included in this release, refer to the SDK Changelog.

Breaking Changes

This section outlines the breaking changes introduced in v5.0.0 that require updates to your existing implementation:

#ElementChangeImpact
1MobileCredentialHolder.getCredential(credentialId:skipStatusCheck:)Parameter renamed to fetchUpdatedStatusList: with inverted semanticsAll call sites using skipStatusCheck: must be updated.
2MobileCredentialHolder.deinitialize()No longer asyncRemove await from all call sites.
3MobileCredentialHolder.initialize(...)New dcConfiguration: param + @available(iOSApplicationExtension, unavailable)Extensions must use new initializeAppExtension.
4OfferedCredentialNew required property credentialConfigurationId: StringManual decoders must handle new field.
5getCurrentLogFilePath()New appGroup: param + unavailable in extensionsSource compatible in apps; breaks extensions.
6VerifierAuthenticationResultNew enum case .unsigned(origin: String?)Exhaustive switch statements must add new case.
720+ methods (see list below)Now @available(iOSApplicationExtension, unavailable)Extensions must migrate to DC APIs.
8Xcode / ToolchainSDK built with Xcode 26.0.0Requires Xcode 26.0.0+. Builds will fail on earlier toolchains (e.g. Xcode 16.4). CI environments must be upgraded.

The following methods are unavailable in App Extensions:

  • Initialization and lifecycle:
    • initialize
    • deinitialize
    • destroy
  • Credential claiming:
    • discoverCredentialOffer
    • createAuthorizationSession
    • retrieveCredentials
  • Credential management:
    • addCredential
    • deleteCredential
    • getCredentials
    • getCredential
  • Key and certificate management:
    • generateDeviceKey
    • addTrustedIssuerCertificates
    • getTrustedIssuerCertificates
    • deleteTrustedIssuerCertificate
    • addTrustedVerifierCertificates
    • getTrustedVerifierCertificates
    • deleteTrustedVerifierCertificate
  • Presentation sessions:
    • createProximityPresentationSession
    • getCurrentProximityPresentationSession
    • createOnlinePresentationSession
    • ProximityPresentationSession.sendResponse
    • terminateSession
    • OnlinePresentationSession.sendResponse
  • Logging:
    • getCurrentLogFilePath

New Additions

Types (iOS 26+)

TypePurpose
DCConfigurationConfigure Digital Credentials support (appGroup, supportedDocTypes)
DCConfiguration.SupportedDocTypeEnum: .mDL, .eudi, .euav, .photoid, .jpMnc
DCErrorErrors for DC operations
DCPresentationSessionHandle system-initiated credential requests

Methods

MethodAvailabilityPurpose
initializeAppExtension(instanceID:appGroup:loggerConfiguration:)iOS 26+Initialize SDK in Identity Document Provider extension
createDcPresentationSession(from:)iOS 26+Create session from system ISO18013MobileDocumentRequestContext
performRegistrationUpdates()iOS 26+Sync credentials with system Identity Document Store

Enum Cases

TypeNew Case
VerifierAuthenticationResult.unsigned(origin: String?)
MobileCredentialHolderError.storageInitializedInBackground

Protocol Conformances

TypeAdded Conformance
VerifierAuthenticationErrorEncodable

Framework Imports

import IdentityDocumentServices      // iOS 26+
import IdentityDocumentServicesUI    // iOS 26+

Backwards Compatible Changes

ChangeNote
MobileCredentialDataTypes nested typealiases@available removed (inherited from parent)
OnlinePresentationSession.VerifiedBy@available removed (inherited from parent)

Deprecations

No new deprecations. Existing deprecations unchanged:

@available(*, deprecated, message: "Use .userPresence instead")
case biometricOrPasscode

@available(*, deprecated, message: "Use .biometryCurrentSet instead")
case biometricOnly

Bug Fixes

  • Fixed intermittent "unable to initialize storage" errors during app launch. The issue was caused by using UserDefaults for keyId storage, which does not guarantee persistence—particularly during iOS app prewarming when protected data may be unavailable. The SDK now stores the keyId in the Keychain and performs explicit availability checks before initialization, throwing a new storageInitializedInBackground error when the keychain is inaccessible.
  • Fixed a crash that could occur when getCredentials() or updateMobileCredentialStatus() were called concurrently from multiple threads. The crash was caused by unsafe concurrent access to internal state. The SDK now properly serializes access to shared resources during credential operations.

Minimum Requirements

  • iOS 15+ for core SDK functionality
  • iOS 26+ for Digital Credentials API (DC API) features

Dependencies

Third party dependencies

Apple frameworks

Toolchain dependencies

  • Swift 5.10.
  • iOS support: The SDK functionality is only available for devices from iOS 15 onwards.
  • Xcode: The SDK requires Xcode 26.0.0 (17A324) or later. Our CI builds use the latest stable Xcode available in GitHub Actions (setup-xcode action with the latest-stable label). Ensure that your development environment and CI pipelines meet or exceed this minimum to avoid build failures.
  • macOS 15 or later.

Migration Steps

Update getCredential calls

The skipStatusCheck parameter has been renamed to fetchUpdatedStatusList with inverted semantics. When fetchUpdatedStatusList is true (default), the SDK will fetch the latest status list to ensure up-to-date revocation information. When false, it will skip fetching the status list. Update all calls accordingly:

- let credential = try await holder.getCredential(credentialId: id, skipStatusCheck: true)
+ let credential = try await holder.getCredential(credentialId: id, fetchUpdatedStatusList: false)
Old ParameterNew ParameterMapping
skipStatusCheck: false (default)fetchUpdatedStatusList: true (default)No change needed
skipStatusCheck: truefetchUpdatedStatusList: falseInvert the boolean

Refer to Revocation Status check for more information.

Update deinitialize calls

The deinitialize() method is no longer async, so remove await from all call sites:

- await MobileCredentialHolder.shared.deinitialize()
+ MobileCredentialHolder.shared.deinitialize()

Handle OfferedCredential changes

The OfferedCredential struct now includes a new required property credentialConfigurationId: String. If you are using the default decoding provided by the SDK, no changes are needed. However, if you have implemented a custom decoder for OfferedCredential, you must update it to handle the new field:

  struct OfferedCredential: Decodable {
+     let credentialConfigurationId: String
      let docType: String
      let claims: [Claim]
      let name: String?
  }

Handle VerifierAuthenticationResult changes

The VerifierAuthenticationResult enum now includes a new case .unsigned(origin: String?) to represent unsigned/unauthenticated requests. If you have any exhaustive switch statements on VerifierAuthenticationResult, you must add a new case to handle this scenario:

  switch verifierAuthenticationResult {
  case .authenticated(let verifierInfo):
      // Handle authenticated verifier
  case .failed(let error):
      // Handle authentication failure
+ case .unsigned(let origin):
+     // Handle unsigned/unauthenticated request (new in v5.0.0)
+     // origin contains the requesting website origin if available
  }

Enable Presenting Credentials via the Digital Credentials API (iOS 26+, optional)

The iOS Holder SDK v5.0.0 introduces support for the Digital Credentials API, allowing credentials to be presented via an OS-native overlay without launching your app. To enable this feature, you need to initialize the SDK with a DCConfiguration that specifies your supported document types and app group. This is optional but recommended for a seamless user experience.

// In main app initialization
if #available(iOS 26.0, *) {
    let dcConfig = DCConfiguration(
        appGroup: "group.com.yourcompany.app",
        supportedDocTypes: [.mDL, .eudi]
    )
    try MobileCredentialHolder.shared.initialize(
        instanceID: instanceID,
        dcConfiguration: dcConfig
    )
} else {
    try MobileCredentialHolder.shared.initialize(instanceID: instanceID)
}

App Extension Migration (iOS 26+)

The methods marked as @available(iOSApplicationExtension, unavailable) are no longer accessible from app extensions. If you have an Identity Document Provider extension, you must migrate to using the new Digital Credentials APIs for handling credential requests. This involves initializing the SDK for extension use and creating presentation sessions from the system-provided context.

// In your IdentityDocumentProviderExtension
@available(iOS 26.0, *)
func handleRequest(_ context: ISO18013MobileDocumentRequestContext) async throws {
    // Initialize for extension context
    try MobileCredentialHolder.shared.initializeAppExtension(
        appGroup: "group.com.yourcompany.app"
    )
    
    // Create presentation session
    let session = try MobileCredentialHolder.shared.createDcPresentationSession(from: context)
    
    // Handle request...
    try await session.sendResponse(credentialIDs: selectedCredentialIDs)
}

Update Toolchain

The SDK now requires Xcode 26.0.0 (17A324) or later. Ensure that your development environment and CI pipelines are updated to use Xcode 26.0.0+ to avoid build failures.

How would you rate this page?

Last updated on

On this page