This guide outlines how to update your integration from using the soon-to-be-deprecated PayPal Mobile Checkout SDK to the new PayPal Mobile iOS SDK.
In order to use this migration guide, you must:
- Have a server-side integration with the PayPal Orders v2 API. Please update to Orders v2 if you're on Payments V1 or NVP/SOAP.
- Obtain your client ID. Follow the steps in Get Started to create a client ID in your PayPal Developer Dashboard.
- Enable your server to create an Order ID.
- Enable your server to PATCH an order.
- Note: This is only required if you create your order ID with
shipping_preference
=GET_FROM_FILE
. See step 6 in the guides below.
- Note: This is only required if you create your order ID with
Assuming the pre-requisites are met, this migration should take ~1 developer day to complete.
- Add the new SDK to your app
-
Swift Package Manger
- In Xcode, add the PayPal SDK as a package dependency to your Xcode project. Enter https://github.com/paypal/paypal-ios.git as the package URL.
- Tick the
PayPalNativePayments
,PaymentButtons
, andCorePayments
boxes to add the libraries to your app.
-
CocoaPods
- Include the
PayPalNativePayments
, andPaymentButtons
sub-modules in yourPodfile
:pod 'PayPal/PayPalNativePayments' pod 'PayPal/PaymentButtons'
Note: Updating your existing
paypalcheckout-ios
dependency to the latest will resolve any dependency conflicts. - Include the
-
Update Configuration
- Remove
CheckoutConfig
and relatedset()
methods. - Instantiate a
CoreConfig
with your client ID from the pre-requisite steps. - Construct a
PayPalNativeCheckoutClient
. - Set delegates (more details to follow).
private func configurePayPalCheckout() { - let config = CheckoutConfig( - clientID: "<CLIENT_ID>", - environment: .sandbox - ) - Checkout.set(config: config) - Checkout.setCreateOrderCallback { createOrderAction in - createOrderAction.set(orderId: "<ORDER_ID>") - } + let coreConfig = CoreConfig(clientID: "<CLIENT_ID>"", environment: CorePayments.Environment.sandbox) + paypalClient = PayPalNativeCheckoutClient(config: coreConfig) + paypalClient?.delegate = self // always required + paypalClient?.shippingDelegate = self // required for `GET_FROM_FILE` orders }
- Remove
-
Update your Button
- Update your UI to display a
PaymentButtons.PayPalButton()
, instead of aPaymentButtonContainer()
. - The
PayPalButton
needs a corresponding@objc
action method.
private func addPayPalButton() { - let container = PaymentButtonContainer() + let paypalButton = PaymentButtons.PayPalButton() + paypalButton.addTarget(self, action: #selector(payPalButtonTapped), for: .touchUpInside) - view.addSubview(container) + view.addSubview(paypalButton) }
- Update your UI to display a
-
Implement a button action method
- Create a
PayPalNativeCheckoutRequest
with your Order ID from the pre-requisite steps. - Call
PayPalNativeCheckoutClient.start()
to present the PayPal Paysheet.
+ @objc private func payPalButtonTapped() { + let request = PayPalNativeCheckoutRequest(orderID: "<ORDER_ID>") + Task { await self.paypalClient?.start(request: request) } + }
- Create a
-
Implement delegate & remove
Checkout
callbacks- Implement the required
PayPalNativeCheckoutDelegate
. This is how your app will receive notifications of the PayPal flow's success, cancel, error, and willStart events. - Remove the analogous
Checkout
singletonsetCallback()
methods.
private func configurePayPalCheckout() { - Checkout.setOnApproveCallback { approval in - approval.actions.capture { response, error in - // Handle result of order approval (authorize or capture) - } - - Checkout.setOnCancelCallback { - // Handle cancel case - } - - Checkout.setOnErrorCallback { error in - // Handle error case - } - - Checkout.setOnShippingChangeCallback { shippingChange, shippingChangeAction in - // Handle user shipping address & method selection change - } } + extension ViewController: PayPalNativeCheckoutDelegate { + func paypal(_ payPalClient: PayPalNativePayments.PayPalNativeCheckoutClient, didFinishWithResult result: PayPalNativePayments.PayPalNativeCheckoutResult) { + // Handle result of order approval (authorize or capture) + } + func paypal(_ payPalClient: PayPalNativePayments.PayPalNativeCheckoutClient, didFinishWithError error: CorePayments.CoreSDKError) { + // Handle error case + } + func paypalDidCancel(_ payPalClient: PayPalNativePayments.PayPalNativeCheckoutClient) { + // Handle cancel case + } + func paypalWillStart(_ payPalClient: PayPalNativePayments.PayPalNativeCheckoutClient) { + // Handle any UI clean-up before paysheet presents + } + }
- Implement the required
-
Implement shipping delegate
⚠️ Only implementPayPalNativeShippingDelegate
if your order ID was created withshipping_preference
=GET_FROM_FILE
. If you created your order ID withshipping_preference
=NO_SHIPPING
orSET_PROVIDED_ADDRESS
, skip this step (step 6).PayPalNativeShippingDelegate
notifies your app when the user updates their shipping address or shipping method.- In the previous SDK, both shipping change types were lumped into one
ShippingChangeCallback
.
- In the previous SDK, both shipping change types were lumped into one
- You are required to PATCH the order details on your server if the shipping method (or amount) changes. Do this with the PayPal Orders API - Update order functionality.
+ extension ViewController: PayPalNativeShippingDelegate { + func paypal( + _ payPalClient: PayPalNativeCheckoutClient, + didShippingAddressChange shippingAddress: PayPalNativeShippingAddress, + withAction shippingActions: PayPalNativePaysheetActions + ) { + // called when the user updates their chosen shipping address + // REQUIRED: you must call actions.approve() or actions.reject() in this callback + actions.approve() + // OPTIONAL: you can optionally patch your order. Once complete, call actions.approve() if successful or actions.reject() if not. + } + func paypal( + _ payPalClient: PayPalNativeCheckoutClient, + didShippingMethodChange shippingMethod: PayPalNativeShippingMethod, + withAction shippingActions: PayPalNativePaysheetActions + ) { + // Handle user shipping method selection change + + // REQUIRED: patch your order server-side with the updated shipping amount + // Once complete, call `actions.approve()` or `actions.reject()` + if patchOrder() == .success { + actions.approve() + } else { + actions.reject() + } + } + }
-
Remove the old SDK dependency