Headless Universal Checkout has changed to solidify the integration experience and make the interfaces clearer and more consistent.
Below is a summary of the changes and examples of how to migrate to this new integration, however we recommend you consult the full documentation during integration.
Starting Headless Universal Checkout
Like before, you still prepare the PrimerHeadlessUniversalCheckoutListener
and start headless universal checkout with your client token.
onAvailablePaymentMethodsLoaded
now returns a list of payment methods with improved functionality.
Instead of just a string, each payment method returned contains the following:
paymentMethodType
a unique string identifier for the payment method.paymentMethodManagerCategories
a list that defines the payment method managers that can be used with this payment method (i.e.NATIVE_UI
orRAW_DATA
).- [Optional]
requiredInputDataClass
this is provided whenpaymentMethodManagerCategories
containsRAW_DATA
and indicates the type of data that should be captured for the payment method. supportedPrimerSessionIntents
a list ofPrimerSessionIntent
which defines what intents can be used with this payment method (i.e.CHECKOUT
orVAULT
).
See an example below:
1234567891011121314151617181920212223242526
class CheckoutActivity : AppCompatActivity() { private val listener = object : PrimerHeadlessUniversalCheckoutListener { override fun onAvailablePaymentMethodsLoaded(paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>) { // Primer will return the available payment methods based on configuration. // Use it to enable users to select a payment method. paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) } } override fun onCheckoutCompleted(checkoutData: PrimerCheckoutData) { // Primer checkout has been completed // checkoutData contains the payment that has been created // show an order confirmation screen, fulfil the order... } override fun onFailed(error: PrimerError, checkoutData: PrimerCheckoutData?) { // your custom method to show an error view } } // your custom method to render the list of payment method buttons UI. private fun setupPaymentMethod(paymentMethodType: String) { // implement payment method UI }}
Building your UI
Before when building your UI, you could create your own buttons using headlessUniversalCheckout.makeView
like in the example below:
123456789101112131415161718192021
private val listener = object : PrimerHeadlessUniversalCheckoutListener { override fun onAvailablePaymentMethodsLoaded( paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod> ) { paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) } }} // your custom method to render the list of payment method buttonsprivate fun setupPaymentMethod(paymentMethodType: String) { val containerView = findViewById<ViewGroup>(R.id.container) val view = headlessUniversalCheckout.makeView(paymentMethodType) view?.apply { containerView.addView(this) setOnClickListener { // TODO } }}
You can now import the PrimerHeadlessUniversalCheckoutAssetsManager
that provides payment method assets per payment method type. See below:
1234567891011121314151617
private val listener = object : PrimerHeadlessUniversalCheckoutListener { override fun onAvailablePaymentMethodsLoaded( paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod> ) { paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) } }} // your custom method to render the list of payment method buttonsprivate fun setupPaymentMethod(paymentMethodType: String) { val paymentMethodAsset = try { PrimerHeadlessUniversalCheckoutAssetsManager.getPaymentMethodAsset(this, paymentMethodType) } catch (e: SdkUninitializedException) { null }}
The payment method asset contains the following:
paymentMethodType
a unique string identifier for the payment method.paymentMethodName
an user friendly English localized string identifier for the payment method (e.g.Google Pay
)paymentMethodLogo
an instance of thePrimerPaymentMethodLogo
paymentMethodBackgroundColor
an instance of thePrimerPaymentMethodBackgroundColor
The PrimerPaymentMethodLogo
holds Drawable
objects for different scenarios
- [Optional]
colored
aDrawable
to be used anywhere - [Optional]
dark
aDrawable
to be used in dark mode - [Optional]
light
aDrawable
to be used in light mode
The PrimerPaymentMethodBackgroundColor
holds @ColorInt
objects for different scenarios
- [Optional]
colored
a@ColorInt
to be used anywhere - [Optional]
dark
a@ColorInt
to be used in dark mode - [Optional]
light
a@ColorInt
to be used in light mode
With the above images and colors you can build your own payment method buttons 💪
Handling Payment Methods
Before, you had to call showPaymentMethod
directly for some payment methods while having managers for others.
Now each payment method belongs to a payment method manager, as indicated by paymentMethodManagerCategories
on the list of available payment methods.
Native UI Manager
Used for any payment method that needs to present its own UI, like Google Pay. See example integration below:
12345678910111213141516
class CheckoutActivity : AppCompatActivity() { // other code goes here private fun onPaymentMethodSelected(paymentMethodType: String) { try { val nativeUiManager = PrimerHeadlessUniversalCheckoutNativeUiManager.newInstance(paymentMethodType) nativeUiManager.showPaymentMethod(this, PrimerSessionIntent.CHECKOUT) } catch (e: SdkUninitializedException) { // handle exception } catch (e: UnsupportedPaymentIntentException) { // handle exception } catch (e: UnsupportedPaymentMethodException) { // handle exception } }}
Raw Data Manager
Used for payment methods that require you to pass data to the SDK, for example for cards. As before, you have to render your own input elements and capture the required data before finally calling submit
on the raw data manager. See example integration below:
123456789101112131415161718192021222324252627282930313233
class CheckoutActivity : AppCompatActivity() { // Enable your pay button val submitButton = findViewById<Button>(R.id.pay_with_card) private lateinit var rawDataManager: PrimerHeadlessUniversalCheckoutRawDataManagerInterface private val rawDataManagerListener: PrimerHeadlessUniversalCheckoutRawDataManagerListener = object : PrimerHeadlessUniversalCheckoutRawDataManagerListener { override fun onValidationChanged( isValid: Boolean, errors: List<PrimerInputValidationError> ) { // modify your UI submitButton.isEnabled = isValid } override fun onMetadataChanged(metadata: PrimerPaymentMethodMetadata) { // show card icon } }} private fun setupManager(paymentMethodType: String) { try { rawDataManager = PrimerHeadlessUniversalCheckoutRawDataManager.newInstance(paymentMethodType) rawDataManager.setListener(rawDataManagerListener) } catch (e: SdkUninitializedException) { // handle exception } catch (e: UnsupportedPaymentMethodException) { // handle exception } }
Other changes
PrimerHeadlessUniversalCheckoutUiListener addition
We have created new listener in order to separate payment events and UI ones. You can attach a listener by calling PrimerHeadlessUniversalCheckout.current.start(uiListener = )
.
PrimerHeadlessUniversalCheckoutListener updates
Some listener functions have been renamed.
Before v2.17.0 | After 2.17.0 |
---|---|
| Renamed to |
| Renamed to |
Some listener functions have been removed and moved to different classes.
Before v2.17.0 | After 2.17.0 |
---|---|
| Moved to |
| Moved to |
Resume handler updates
Some listener functions provide a decision handler.
You can process the data provided and once you’re ready you can call the decision handler with your relevant decision. Once you do, the SDK will continue the flow. We have changed the handler class name and signature of following functions have changed:
Before v2.17.0 | After 2.17.0 |
---|---|
1234 fun onTokenizeSuccess( paymentMethodTokenData: PrimerPaymentMethodTokenData, decisionHandler: PrimerResumeDecisionHandler) kotlin copy | 1234 fun onTokenizeSuccess( paymentMethodTokenData: PrimerPaymentMethodTokenData, decisionHandler: PrimerHeadlessUniversalCheckoutResumeDecisionHandler) kotlin copy |
1234 fun onResumeSuccess( resumeToken: String, decisionHandler: PrimerResumeDecisionHandler) kotlin copy | 1234 fun onCheckoutResume( resumeToken: String, decisionHandler: PrimerHeadlessUniversalCheckoutResumeDecisionHandler) kotlin copy |
Miscellaneous changes
Models that need to be passed to the SDK when using Raw Data Managers
have changed structures and naming:
Before v2.17.0 | After 2.17.0 |
---|---|
1234567 data class PrimerRawCardData( val cardNumber: String, val expirationMonth: String, val expirationYear: String, val cvv: String, val cardHolderName: String? = null,) kotlin copy | 123456 data class PrimerCardData( val cardNumber: String, val expiryDate: String, val cvv: String, val cardHolderName: String? = null,) kotlin copy |
123456 data class PrimerRawBancontactCardData( val cardNumber: String, val expirationMonth: String, val expirationYear: String, val cardHolderName: String,) kotlin copy | 12345 data class PrimerBancontactCardData( val cardNumber: String, val expiryDate: String, val cardHolderName: String,) kotlin copy |
123 data class PrimerRawPhoneNumberData( val phoneNumber: String) kotlin copy | 1 data class PrimerPhoneNumberData(val phoneNumber: String) kotlin copy |
1 data class PrimerRawRetailerData(val id: String) kotlin copy | 1 data class PrimerRetailerData(val id: String) kotlin copy |