Pay Using Card Information
Here's how to implement the exact same sections for Android, converting the iOS-based steps into Android using Kotlin and Jetpack Compose:
Ensure your card method connection is set to Server to Server in the MoneyHash dashboard.
Using your account Public API Key on the MoneyHashSDK
class instance, you can access the functionality to collect card data and process payments.
Initialize MoneyHashSDK
Before starting, initialize the MoneyHash SDK with your Public API Key:
val moneyHashSDK = MoneyHashSDKBuilder()
.setPublicKey("<account_public_api_key>")
.build()
Replace "<account_public_api_key>"
with your actual Public API Key from MoneyHash.
Collect Card Data
Once the card form is set up (you can follow the steps here), you can collect card data using the collect()
method from the CardForm
instance:
class CardFormViewModel {
var cardForm: CardForm // Assume this is set up as per the linked documentation
suspend fun collectCardData(): VaultData? {
return try {
cardForm?.collect()
} catch (throwable: Throwable) {
println("Error collecting card data: ${throwable.message}")
throw e
}
}
}
Note: Make sure the card form is properly set up and rendered before attempting to collect card data.
Pay
Once you've collected the card data, you can process the payment using the pay()
method:
class CardFormViewModel {
var cardForm: CardForm? = null // Assume this is set up as per the linked documentation
suspend fun processPayment(intentId: String, saveCard: Boolean, billingData: Map<String, String>?, shippingData: Map<String, String>?) {
try {
val cardData = collectCardData() ?: return@withContext
val intentDetails: IntentDetails? = cardForm?.pay(
intentId = intentId,
cardData = cardData,
saveCard = saveCard,
billingData = billingData,
shippingData = shippingData
)
println("Payment successful: $intentDetails")
} catch (throwable: Throwable) {
println("Payment failed: ${throwable.message}")
}
}
}
Here, the pay()
method processes the payment using the provided card data, intent ID, and optional billing/shipping data for reference. Make sure to check out the basics docs.
Note:
saveCard
Passing
saveCard: true
will allow MoneyHash to tokenize and save the card for future use. Make sure your intent is created with"allow_tokenize_card": true
for tokenization to work.
Complete Example
class CardFormViewModel : ViewModel() {
var cardForm: CardForm? = null
init {
setupCardForm()
}
private fun setupCardForm() {
cardForm = CardFormBuilder()
.setCardNumberField { state ->
println("Card Number Field State: $state")
}
.setCVVField { state ->
println("CVV Field State: $state")
}
.setCardHolderNameField { state ->
println("Card Holder Name Field State: $state")
}
.setExpireMonthField { state ->
println("Expire Month Field State: $state")
}
.setExpireYearField { state ->
println("Expire Year Field State: $state")
}
.setCardBrandChangeListener { brand ->
println("Card Brand Changed: $brand")
}
.build()
}
fun handlePayment(intentId: String) {
viewModelScope.launch {
try {
val cardData = cardForm?.collect()
if (cardData == null) {
println("Failed to collect card data.")
return@launch
}
val intentDetails = cardForm?.pay(
intentId = intentId,
cardData = cardData,
saveCard = true, // Set to true to save the card (optional)
billingData = mapOf("address" to "123 Main St", "city" to "New York"), // Optional
shippingData = mapOf("address" to "456 Elm St", "city" to "Boston") // Optional
)
println("Payment Successful: $intentDetails")
} catch (e: Exception) {
println("Payment Error: ${e.message}")
}
}
}
}
class CardFormActivity : ComponentActivity() {
private val viewModel: CardFormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CardFormScreen(viewModel = viewModel)
}
}
}
@Composable
fun CardFormScreen(viewModel: CardFormViewModel) {
val coroutineScope = rememberCoroutineScope()
Scaffold(
topBar = {
TopAppBar(title = { Text("Payment Form") })
},
content = {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
SecureTextField(
cardForm = viewModel.cardForm!!,
type = FieldType.CARD_HOLDER_NAME,
placeholder = { Text("Cardholder Name") }
)
SecureTextField(
cardForm = viewModel.cardForm!!,
type = FieldType.CARD_NUMBER,
placeholder = { Text("Card Number") }
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
SecureTextField(
cardForm = viewModel.cardForm!!,
type = FieldType.EXPIRE_MONTH,
placeholder = { Text("MM") },
modifier = Modifier.weight(1f)
)
SecureTextField(
cardForm = viewModel.cardForm!!,
type = FieldType.EXPIRE_YEAR,
placeholder = { Text("YY") },
modifier = Modifier.weight(1f)
)
SecureTextField(
cardForm = viewModel.cardForm!!,
type = FieldType.CVV,
placeholder = { Text("CVV") },
modifier = Modifier.weight(1f)
)
}
Button(
onClick = {
viewModel.handlePayment("<intent_id>")
},
modifier = Modifier.fillMaxWidth()
) {
Text("Pay")
}
}
}
)
}
Explanation:
-
ViewModel (
CardFormViewModel
):-
Purpose: Manages the
CardForm
instance, ensuring it is initialized and can be shared across the UI. -
Functions:
setupCardForm()
: Initializes the card form with field listeners.handlePayment(intentId: String)
: Collects the card data and processes the payment.
-
-
Activity (
CardFormActivity
):-
Purpose: Hosts the UI and integrates the
CardForm
with Jetpack Compose. -
setContent
: Sets the UI content to theCardFormScreen
composable, passing theviewModel
.
-
-
Composable Function (
CardFormScreen
):-
Purpose: Displays the form fields using
SecureTextField
for cardholder name, card number, expiry month, expiry year, and CVV. -
Button: Triggers the
handlePayment()
function in the ViewModel to collect and process the payment when clicked.
-
-
SecureTextField Components:
-
Used for: Capturing user input securely for card details.
-
Fields:
- Cardholder Name
- Card Number
- Expiry Month
- Expiry Year
- CVV
-
-
Payment Processing:
handlePayment()
Function:- Collects Card Data: Calls
cardForm.collect()
to gather card data. - Processes Payment: Calls
cardForm.pay()
with the collected card data and intent ID. - Error Handling: Catches and logs exceptions during payment processing.
- Collects Card Data: Calls
Notes:
- Replace
"<intent_id>"
with your actual payment intent ID. - Ensure that the
cardForm
is not null before using it in the composable (cardForm = viewModel.cardForm!!
). - The
viewModelScope.launch
is used to handle coroutines within the ViewModel.
Updated about 2 months ago