iOS Push Provisioning v2.0.0
This version is a major update over v1 that includes breaking changes in the public interface of the SDK.
Make sure you address these changes by following the instructions in the migration guide at the end of the release notes for this version.
Supported versions:
- iOS: 15.1 and onwards
- Xcode: 16.4 and 26
- Swift: 5.9 and onwards
Added
- Added
WPPComponents.initialize(environment: , uiKey:). - Added
WPPComponents.makePassEntriesForCardsWith(authenticationToken:, entries:, imageFallback:). - Added an async version of
WPPComponents.addPaymentPass(authenticationToken: ,clientPaymentCardId: ,certificates: ,nonce: ,nonceSignature:)in case you prefer to avoid callbacks. - Added extra properties
reason,domain,underlyingErrorCode, anderrorCodetoWPPErrorto provide better context into what went wrong. - Added
WeavrProvisioningErrorCodeandWeavrProvisioningErrorDomainto better represent errors. The end of this document contains appendixes with their values. - Added more cases to the
AddCardToWalletStatusenum to better reflect the potential states a card can be in within Apple Pay. - Added a
DeviceTypeenum to let you query the card status in a specific device betweenphone, orwallet. Also included aneithervalue for convenience. The potential values and how to use them are listed in the Appendix. - Added
WeavrProvisioningExtensionHandlerto simplify the non-ui wallet extension integration.
Breaking change
- Changed the completion block of
WPPComponents.addPaymentPass(authenticationToken: ,clientPaymentCardId: ,certificates: ,nonce: ,nonceSignature: , completionHandler:)so that thePKAddPaymentPassRequestbecomes nullable (PKAddPaymentPassRequest?). This allows to report failures to create the request, and is consistent with Apple's requirements in thePKIssuerProvisioningExtensionHandler.generateAddPaymentPassRequestForPassEntryWithIdentifiermethod.
Removed
- Removed
WPPComponents.makePassEntryForCardWith. - Removed
WPPError.messagein favour of newly added properties.
Deprecated
- Deprecated
WPPComponents.canAddCardToWallet(panLastFour:)in favour ofWPPComponents.getCardStatusInWallet(forCardWithLastFourDigits:, deviceType:).
Migration guide
Mandatory : adding provisioning_config file
For the correct functioning of our SDK, we require a configuration file necessary to initialise one of our dependencies.
To do so, you need to add the provisioning_config file to your iOS bundle. For instance, it can be located in an assets folder, and added to your app's and extension targets.
Get in touch with our support team at support@weavr.io to obtain this file.
This file is sensitive, make sure you store and distribute it in a secure manner.
Our recommendation is not to commit this file to your repository, and distribute it via a secure file sharing software amongst your team.
Finally, use the secrets feature of your CI software of choice to avoid impacting your CI/CD pipelines.
Mandatory breaking changes
The following changes must be implemented to be able to provision correctly.
Initialising the SDK
Starting from version 2.0.0, you need to initialise the SDK during your app's start up using the following call:
WPPComponents.initialize(environment: .Sandbox, uiKey: "<MY-UI-KEY>")
Notice that the UI key that is expected as a parameter can be obtained from the Weavr portal.
Provisioning a card via Wallet Extension
Option 1: using Weavr provisioning extension handler
WeavrProvisioningExtensionHandler has been introduced as a simplified way to implement the non-UI Wallet Extension. This class implements PKIssuerProvisioningExtensionHandler and implements the logic required to satisfy Apple's needs.
All you have to do to use it is to change your Extension handler to implement WeavrProvisioningExtensionHandler, and implement the following getters:
import WeavrPushProvisioning
import UIKit
import Foundation
class IntentHandler: WeavrProvisioningExtensionHandler {
override func loadCardsFromDisk() -> [ManagedCard] {
// TODO Load the managed cards from disk.
}
override func loadTokenFromDisk() -> Token? {
// TODO Load the user's token from Disk
}
override func loadCardsFromNetwork() async throws -> [ManagedCard] {
// TODO Load the cards from the network
}
override func uiKey() -> String {
// TODO Return the UI key of the project to use.
}
override func defaultCardImage() -> CGImage {
// TODO Return a CGImage for the card image you want to default to if we can't load the image URL
// or no URL is provided.
}
}
Option 2: using Apple's extension handler
Although we recommend using WeavrProvisioningExtensionHandler to re-use well tested and Apple certified code, you can still implement PKIssuerProvisioningExtensionHandler on your own if you prefer to.
To migrate to v2.0.0 using PKIssuerProvisioningExtensionHandler you must change the following calls:
Making pass entries
We have migrated from makePassEntryForCardWith, which needs to be called once for each card available to provision, to WPPComponents.makePassEntriesForCardsWith(authenticationToken:, entries:, imageFallback:), which takes an array of entries, allowing the workload that the device has to perform to be reduced before obtaining a result.
The following snippet showcases how to call the new method:
let entries: [PassEntryInfo] = cards.compactMap { card in
// Check if the card state is notAdded.
let canAddCard = .notAdded == WPPComponents.getCardStatusInWallet(
forCardWithLastFourDigits: card.cardNumberLastFour,
// Note that the device type will depend on whether you are responding to `passEntries` or
// `remotePassEntries` in the non-UI extension.
deviceType: .phone
)
guard canAddCard else {
return nil
}
// PassEntryInfo is a struct that allows us to encapsulate all data needed for the pass entry.
return PassEntryInfo(
cardId: card.id,
cardholderName: card.cardholder,
panLastFour: card.cardNumberLastFour,
cardDescription: card.friendlyName,
cardImageURL: card.digitalArtworkUrl.flatMap { URL(string: $0) }
)
}
// The new method returns a list of pass entries to provide to Apple.
let passEntries = await WPPComponents.makePassEntriesForCardsWith(
authenticationToken: authenticationToken,
entries: entries.compactMap { $0 },
// TODO Provide default image
imageFallback: myDefaultCardImage
)
Adding the payment pass
The completion block in WPPComponents.addPaymentPass(authenticationToken: ,clientPaymentCardId: ,certificates: ,nonce: ,nonceSignature: , completionHandler:) has been updated to receive a nullable PKAddPaymentPassRequest?.
Therefore, if your method is expecting a non optional value, or explicitly defines the PKAddPaymentPassRequest type received, you need to update your code to handle the nullable value.
More commonly, we expect you to just pass through the same completion block that Apple provides you, and therefore no change would be needed.
Additionally, a coroutine based method has been introduced in case you prefer it over callbacks.
Overall, generateAddPaymentPassRequestForPassEntryWithIdentifier should be implemented in a way similar to the next snippet:
override func generateAddPaymentPassRequestForPassEntryWithIdentifier(
_ identifier: String,
configuration: PKAddPaymentPassRequestConfiguration,
certificateChain certificates: [Data],
nonce: Data,
nonceSignature: Data
) async -> PKAddPaymentPassRequest? {
// Load the token from the storage shared with your app and UI extension
guard let token = loadToken() else {
// If the token is not available, return nil to signal Apple
// that something went wrong
return nil
}
// Otherwise, call `WPPComponents.addPaymentPass` and pass the result back to Apple
return await WPPComponents.addPaymentPass(
authenticationToken: token,
clientPaymentCardId: identifier,
certificates: certificates,
nonce: nonce,
nonceSignature: nonceSignature
)
}
Recommended : migrating deprecated methods
The following changes are not mandatory for this version, but we encourage you accommodate them now in order to avoid breaking changes in the future.
Checking the status of the card
A new method has been added to obtain the card's status, allowing you to specify on which device you want to check. Additionally a new device type either is included allowing to check the status for either the phone or the watch.
// Check the state of the card ending in 1234 on the phone:
WPPComponents.getCardStatusInWallet(forCardWithLastFourDigits: "1234", deviceType: .phone)
// Check the state of the card ending in 1234 on the watch:
WPPComponents.getCardStatusInWallet(forCardWithLastFourDigits: "1234", deviceType: .watch)
// Check the state of the card ending in 1234 on either the phone, or watch:
WPPComponents.getCardStatusInWallet(forCardWithLastFourDigits: "1234", deviceType: .either)
Finally, new states that the card can be in have been added, to better reflect what Apple reports to us. You can observe these potential new states on the Card Status section.
Appendices
Error codes
| WeavrProvisioningErrorCode | Description | Integer Code |
|---|---|---|
cardNotEligibleForProvisioning | The card is not eligible for provisioning. | 1003 |
cantFindProviderToUse | Couldn't find the provider to use. This can occur when there's a problem obtaining the provider from the API, e.g. a client error or server error. | 1004 |
emptyEntries | No card entries provided by the user. | 1005 |
userCancelled | The user cancelled the flow. | 1006 |
unauthorized | The token is not present or is rejected during provisioning. | 2002 |
missingCardId | The card Id provided is empty. | 2003 |
missingCardLastFourDigits | The last four digits of the card provided is empty. | 2005 |
missingCardholderName | The card holder name of the card provided is empty. | 2006 |
missingCardDescription | The card description of the card provided is empty. | 2007 |
cantBeAddedToAppleWallet | Couldn't add the card to Apple Wallet. | 3001 |
cantFindViewController | Couldn't find the top most view controller to display the provisioning view controllers. | 5001 |
cantObtainPaymentPassRequestConfiguration | The payment pass request configuration needed by Apple Wallet to provision the card couldn't be created. | 5002 |
cantCreateProvisioningExtensionPaymentPassEntry | The SDK couldn't create the extension payment pass entry needed by Apple Wallet. | 5003 |
cantCreateProvisioningExtensionPaymentPassRequest | The SDK couldn't create the payment pass request to add the card selected by the user to Apple Wallet. | 5004 |
unknown | An unknown error occurred. | -1 |
Card status
| AddCardToWalletStatus | Description |
|---|---|
unavailable | Apple Pay is not available on the device, or there is no Apple Watch connected when querying for card status on the watch. |
alreadyAdded | The card has already been added to Apple Pay. Equivalent to PKSecureElementPass.PassActivationState.activated. |
notAdded | The card has not been added yet to Apple Pay, but it can be. |
requiresActivation | The card is present in the Wallet but has not yet been activated. |
activating | The card isn't ready to use, but will be soon. |
suspended | The card has been suspended and is not available to use. |
deactivated | The card has been deactivated. |
unknown | An unknown state. Shouldn't occur. |
Device types
| DeviceType | Description |
|---|---|
phone | The card state query will be performed on the phone or tablet itself. |
watch | The card state query will be performed on the user's Apple Watch. |
either | The card state query will be performed on both the phone and the watch. The result of the query will be notAdded if the card hasn't been added to the watch yet. In all other cases, the result will match that of the phone device type. |