To install the React Native module run:
npm install @weavr-io/push-provisioning-react-native
or
yarn add @weavr-io/push-provisioning-react-native
For further instructions and documentations go to our website documentations
Wallet Extensions feature is app extension based and lets the issuer app extend custom functionality and content, and make it available in Apple Wallet. All of the methods are triggered by Apple Wallet and the app extensions ability to enable behavior is solely based on the completion handlers and return values. This feature relies on two extensions:
-
Issuer app should provide a non-UI extension (subclass of
PKIssuerProvisioningExtensionHandler
) to report on the status of the extension and the payment passes available for provisioning like when adding payment passes to Apple Pay from within the issuer app. -
Issuer app should provide a UI extension (
UIViewController
that conforms toPKIssuerProvisioningExtensionAuthorizationProviding
) to perform authentication of the user if the non-UI extension reports in its status that authentication is required. The UI extension is a separate screen that uses the same issuer app login credentials. UI extension is not a redirect to the issuer app.
Wallet Extensions do not use a specific extension type template.
Select Intents Extension as the base. Create two app extensions IssuerNonUIExtension and IssuerUIExtension following the steps below.
- Add an app extension to Xcode app project, choose
File
>New
>Target
, selectiOS
>Application Extension
>Intents Extension
.
-
Set options for the new target. Create a unique bundle ID for the extension and add App IDs to associatedApplicationIdentifiers in PNO metadata.
-
Check the box for "Include UI Extension" if UI Extension will be needed.
For example,
Bundle Identifier |
---|
ABCDE12345.com.weavr.app |
ABCDE12345.com.weavr.app.WalletExtension |
ABCDE12345.com.weavr.app.WalletExtensionUI |
- Activate the created scheme, if asked.
- Add
PassKit.framework
toFrameworks and Libraries
of theIssuerNonUIExtension
andIssuerUIExtension
targets, and removeIntents.framework
which is not needed. - Remove
Intents.framework
of theIssuerUIExtension
target.
Add newly created target in Podfile and add 'ApplePayProvisioning' pod with version 5.0.0
Make sure to set iOS version to 14.0
Register both app extension bundle identifiers in Apple Developer portal Identifiers section. Create provisioning profiles accordingly.
Create a new App Group if currently there is no App Group for the app and add the main app and both app extension bundle identifiers to the app group, so data can be shared between them.
IssuerAuthorizationExtensionHandler UI extension should conform to PKIssuerProvisioningExtensionAuthorizationProviding
protocol. Apple Wallet interrogates the issuer app to determine the user's authorization status, and the authorization UI extension performs user authentication.
App UI extension has a memory limit of 60 MB, developers are responsible to optimize the code and libraries to fit this requirement.
import PassKit
import UIKit
@available(iOS 14.0, *)
class IssuerAuthorizationExtensionHandler: UIViewController, PKIssuerProvisioningExtensionAuthorizationProviding {
var completionHandler: ((PKIssuerProvisioningExtensionAuthorizationResult) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
// Set up view and authenticate user.
}
func authenticateUser() {
let userAuthenticated = true // User authentication outcome.
let authorizationResult: PKIssuerProvisioningExtensionAuthorizationResult = userAuthenticated ? .authorized : .canceled
self.completionHandler?(authorizationResult)
}
}
Implementing Issuer Extension Handler IssuerExtensionHandler non-UI class must be a subclass of PKIssuerProvisioningExtensionHandler. Issuer app must be installed and the user must open the issuer app at least once for the system to call the issuer extension handler.
App Non-UI extension has a memory limit of 55 MB, developers are responsible to optimize the code and libraries to fit this requirement.
import PassKit
import weavr_react_native
@available(iOS 14.0, *)
class IssuerExtensionHandler: PKIssuerProvisioningExtensionHandler {
// Determines if there is a pass available and if adding the pass requires authentication.
// The completion handler takes a parameter status of type PKIssuerProvisioningExtensionStatus that indicates
// whether there are any payment cards available to add as Wallet passes.
// PKIssuerProvisioningExtensionStatus has the following properties:
// requiresAuthentication: Bool - authorization required before passes can be added.
// passEntriesAvailable: Bool - passes will be available to add (at least one).
// remotePassEntriesAvailable: Bool - passes will be available to add on the remote device (at least one).
// The handler should be invoked within 100ms. The extension is not displayed to the user in Wallet if this criteria is not met.
override func status(completion: @escaping (PKIssuerProvisioningExtensionStatus) -> Void) {
let status = PKIssuerProvisioningExtensionStatus()
// For this example let's say that we store user available cards pans in shared UserDefaults (UserData.cardsPan)
status.passEntriesAvailable = UserData.cardsPan.first { pan in
// call SDK to check pan for phone pass
return AddToWalletUtil.canAddCardToApplePay(panLastFour: pan, onDeviceType: .phone) == "notAdded"
} != nil
completion(status)
}
// Finds the list of passes available to add to an iPhone.
// The completion handler takes a parameter entries of type Array<PKIssuerProvisioningExtensionPassEntry> representing
// the passes that are available to add to Wallet.
// PKIssuerProvisioningExtensionPaymentPassEntry has the following properties:
// art: CGImage - image representing the card displayed to the user. The image must have square corners and should not include personally identifiable information like user name or account number.
// title: String - a name for the pass that the system displays to the user when they add or select the card.
// identifier: String - an internal value the issuer uses to identify the card. This identifier must be stable.
// addRequestConfiguration: PKAddPaymentPassRequestConfiguration - the configuration data used for setting up and displaying a view controller that lets the user add a payment pass.
// Do not return payment passes that are already present in the user’s pass library.
// The handler should be invoked within 20 seconds or will be treated as a failure and the attempt halted.
override func passEntries(completion: @escaping ([PKIssuerProvisioningExtensionPassEntry]) -> Void) {
// Use AddToWalletUtil.canAddCardToApplePay method to determine if the card is added already to Apple Wallet for iPhone
// Use AddToWalletUtil.makePassEntryForCardWith to create a Pass Entry for every card that is available for adding to Apple Wallet
}
// identifier: String - an internal value the issuer uses to identify the card.
// configuration: PKAddPaymentPassRequestConfiguration - the configuration the system uses to add a secure pass. This configuration is prepared in methods passEntriesWithCompletion: and remotePassEntriesWithCompletion:.
// certificates, nonce, nonceSignature - parameters are generated by Apple Pay identically to PKAddPaymentPassViewControllerDelegate methods.
// The completion handler is called by the system for the data needed to add a card to Apple Pay.
// This handler takes a parameter request of type PKAddPaymentPassRequestConfiguration that contains the card data the system needs to add a card to Apple Pay.
// The continuation handler must be called within 20 seconds or an error is displayed.
// Subsequent to timeout, the continuation handler is invalid and invocations is ignored.
override func generateAddPaymentPassRequestForPassEntryWithIdentifier(
_ identifier: String,
configuration: PKAddPaymentPassRequestConfiguration,
certificateChain certificates: [Data],
nonce: Data,
nonceSignature: Data,
completionHandler completion: @escaping (PKAddPaymentPassRequest?) -> Void) {
let authenticationToken = "authenticationToken"
AddToWalletUtil.addPaymentPassWith(authenticationToken: authenticationToken, clientPaymentCardId: identifier, certificates: certificates, nonce: nonce, nonceSignature: nonceSignature, completionHandler: completion)
}
}
Updating Extension's Info.plist Modify NSExtension dictionary in extension's Info.plist, delete NSExtensionAttributes entry.
NSExtensionPointIdentifier and NSExtensionPrincipalClass should be specified in the extension Info.plist properties dictionary:
Non-UI App Extension
Key | Type | Value |
---|---|---|
NSExtensionPointIdentifier | String | com.apple.PassKit.issuer-provisioning |
NSExtensionPrincipalClass | String | $(PRODUCT_MODULE_NAME).IssuerExtensionHandler |
UI App Extension
Key | Type | Value |
---|---|---|
NSExtensionPointIdentifier | String | com.apple.PassKit.issuer-provisioning.authorization |
NSExtensionPrincipalClass | String | $(PRODUCT_MODULE_NAME).IssuerAuthorizationExtensionHandler |
Issuer Extensions use the same entitlement file used for issuer app In-App Provisioning.