Checkout Screen
Checkout Screen
The Checkout screen takes a quote and outputs a booked trip or an error when booking the quote.
The quote capabilities section can be displayed by clicking on the Learn More
The pricing info section can be expanded or retracted by pressing the info button right next to the METERED | FIXED | ESTIMATED label
Colors can be fully customized by overriding the color pallet provided by the Karhoo UISDK.


The iOS checkout screen with all the necessary data for completing a booking
Loyalty
The loyalty section is available when Loyalty is enabled for the user. In order to enable the loyalty, you need to integrate with our Loyalty API. This would allow the users to earn or burn loyalty points from their balance after completing taxi rides with Karhoo.


Android Checkout Component with all sections expanded
The Checkout is implemented as an iOS ViewController / Android Activity to automatically handle the presentation, dismissal and handling of the payment flow.
let bookingDetails = KarhooBookingStatus.shared.getBookingDetails()!
let checkoutScreen = KarhooUI()
.screens()
.checkout()
.buildCheckoutScreen(quote: quote,
bookingDetails: bookingDetails,
bookingMetadata: nil,
callback: { [weak self] result in
if let trip = result.completedValue() {
print(trip)
}
})
checkoutScreen.modalPresentationStyle = .fullScreen
self.present(checkoutScreen, animated: true, completion: nil)
private var passengerDetails: PassengerDetails? = null
private var bookingComments: String? = ""
private var bookingMetadata: HashMap<String, String>? = null
private var bookingStatus: BookingStatus(pickupLocationInfo, destinationLocationInfo, date)
val builder = CheckoutActivity.Builder()
.quote(quote)
.bookingMetadata(bookingMetadata)
.bookingStatus(bookingStatus)
passengerDetails?.let {
builder.passengerDetails(it)
}
bookingComments?.let {
builder.comments(it)
}
startActivityForResult(builder.build(this), REQ_CODE_BOOKING_REQUEST_ACTIVITY)
iOS Sample
Payment flow handling
The checkout component requires a URL scheme to be set for the SDK to fully manage 3DSecure payment flows.
We've added a summary below for convenience. For more details please consult the aforementioned guides.
---- BraintreeURLTypeContext.swift -----
import Foundation
struct BraintreeURLTypeContext {
static func currentScheme() -> String {
guard let bundleId = Bundle.main.bundleIdentifier else {
return ""
}
return "\(bundleId).braintree"
}
}
import Braintree
import Adyen
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ...
BTAppSwitch.setReturnURLScheme(BraintreeURLTypeContext.currentScheme())
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
if url.scheme?.localizedCaseInsensitiveCompare(BraintreeURLTypeContext.currentScheme()) == .orderedSame {
return BTAppSwitch.handleOpen(url, options: options)
}
let adyenThreeDSecureUtils = AdyenThreeDSecureUtils()
if url.scheme?.localizedCaseInsensitiveCompare(adyenThreeDSecureUtils.current3DSReturnUrlScheme) == .orderedSame {
return RedirectComponent.applicationDidOpen(from: url)
}
return false
}
}
Please replace the [BUNDLE_ID] mentioned below with your application Bundle ID. If you have a sandbox build type, you need to include add the URL types for sandbox as well.
---- info.plist -----
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleURLSchemes</key>
<array>
<string>[BUNDLE_ID]</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>App-Payments-AppStore</string>
<key>CFBundleURLSchemes</key>
<array>
<string>[BUNDLE_ID].braintree</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>App-Payments-Adyen-AppStore</string>
<key>CFBundleURLSchemes</key>
<array>
<string>[BUNDLE_ID].adyen</string>
</array>
</dict>
</array>
</key>
Android Sample
When an authenticated user selects a quote, they are then taken to the checkout screen which enables them to change passenger details, enable loyalty earning or burning, see the capabillities of a ride, add or update their payment details and end up by booking the ride.
The Checkout Activity can be launched independently from the Booking Activity. In order to launch it succesfully, a valid Quote is required for the component to work, the rest of the parameters are optional.
| The activity will take the quote object and use this to prepopulate eta, pricing and vehicle details fields |
---|---|
| If an metadata map is passed in the activity, it will be used as part of the Booking API meta data |
| By passing booking status into the Booking activity it will automatically prefill the origin, destination and date of the desired trip. |
| If a passenger is added, then it will be used to prefill the passenger details in the booking request component |
| By passing comments into the Checkout Component it will automatically prefill the comments of the desired trip. |
| Sets the validity timestamp of the quote |
The Checkout Activity can be launched similar to the Booking Activity, containing a builder which can handle the above params
// launching for primary flow
val builder = CheckoutActivity.Builder()
.quote(actions.quote)
.bookingMetadata(bookingMetadata)
.passengerDetails(passengerDetails)
.comments(bookingComments)
.bookingInfo(BookingInfo(pickup, destination, date))
.currentValidityDeadlineTimestamp(ts)
// launching for callback example
startActivityForResult(builder.build(this), REQ_CODE_BOOKING_REQUEST_ACTIVITY)
When an error occurs in the Checkout Component, the activity will be finished with a result containing an error code or string
In order to catch the error result, override onActivityResult in the calling activity and listen for BOOKING_CHECKOUT_ERROR
result code
/**
* Method used for finishing up the booking request activity with an error
* The activity which launches the BookingRequestActivity should handle the error result
* under BOOKING_REQUEST_ERROR (result code 10) and act accordingly
* @param error reason for closing the BookingRequestActivity
*/
private fun finishWithError(error: String) {
val data = Intent()
data.putExtra(BOOKING_CHECKOUT_ERROR_KEY, error)
setResult(BOOKING_CHECKOUT_ERROR, data)
finish()
}
When the Checkout Component successfully books a trip, the resulting tripId will be available on the returning's intent extras of CheckoutActivity.BOOKING_CHECKOUT_PREBOOK_TRIP_INFO_KEY
if (resultCode == Activity.RESULT_OK && requestCode == REQ_CODE_BOOKING_REQUEST_ACTIVITY) {
if (data?.hasExtra(CheckoutActivity.BOOKING_CHECKOUT_PREBOOK_TRIP_INFO_KEY) == true) {
//In case of prebook,the trip is instantly booked. Show a confirmation
showPrebookConfirmationDialog(data)
} else {
//Send the data to the trip allocation widget
tripAllocationWidget.onActivityResult(requestCode, resultCode, data)
}
}
Updated 5 months ago