Android
Last updated
Last updated
Server side
Client side
Firstly, you need a MoneyCollect account. Register now.
If the client side wants to access most of the MoneyCollect Server API, it needs MoneyCollect dashboard to initiate a request through the private key.
Download the mock merchant portal interface code on github.
the public key
and private key
in the MobilePayController.java file//Your account PUBLIC_SECRET("Bearer "+PUBLIC_SECRET)
private static final String PUBLIC_SECRET = "Bearer live_pu_OGJ0EidwEg4GjymEiRD7cUBk7IQIYmhwhJlUM****";
//Your account PRIVATE_SECRET("Bearer "+PRIVATE_SECRET)
private static final String PRIVATE_SECRET = "Bearer live_pr_OGJ0EidwEg4GjymEiRD4MRxBCo0OumdH6URv****";
The format of PUBLIC_SECRET & PRIVATE_SECRET is("Bearer"+PUBLIC_SECRET)
server.port=9898
The merchant replaces the public key
and private key
in the code with their own, and then switch on the server. (Default server port is 9099 which can be modified).(The dashboard interface address is the local ip:9898)
Import MoneyCollect android SDK and initialize SDK.
To install the SDK, add moneycollect-android
to the dependencies block of your build.gradle
file:
repositories {
jcenter()
maven{ url "https://raw.githubusercontent.com/MoneyCollect/moneycollect-api-android-demo/mcsdk" }
}
buildFeatures{
viewBinding = true
}
dependencies {
//The specific version number will be determined according to your needs
implementation "com.moneycollect.payment:android_mc:0.0.1"
}
Initialize MoneyCollect android sdk() in the project application
/**
* context: Context, (context)
* publishableKey: String, (publishable key)
* customerServerUrl: String? (Local ip:9898)
**/
MoneyCollectSdk.init(this, "live_pu_OGJ0EidwEg4GjymEiRD7cUBk7IQIYmhwhJlUM****","http://192.168.2.100:9898/")
The merchant constructs the transaction request parameters and clicks the Checkout button to start the payment activity.(TestRequestData
is data constant class,please check moneycollect-api-android-demo for more details)
// ...
class PaymentSheetDemoActivity: AppCompatActivity() {
//RequestCreatePayment Object
var testRequestPayment = TestRequestData.testRequestPayment
//RequestConfirmPayment Object
var testConfirmPayment = TestRequestData.testConfirmPayment
//RequestPaymentMethod Object
var testRequestPaymentMethod = TestRequestData.testRequestPaymentMethod
//support payment credit card
var testBankIvList = TestRequestData.testBankIvList
//customerId
var customerId = TestRequestData.customerId
// ...
fun presentPaymentSheet() {
//PayCardActivity contain SaveWithPaymentCardFragment and AddWithPaymentFragment,Support them to switch to each other
var intent = Intent(this, PayCardActivity::class.java)
//Bundle Object
var bundle = Bundle()
//pass currentPaymentModel
bundle.putSerializable(Constant.CURRENT_PAYMENT_MODEL, currentPaymentModel)
//pass RequestCreatePayment
bundle.putParcelable(Constant.CREATE_PAYMENT_REQUEST_TAG, testRequestPayment)
//pass RequestConfirmPayment
bundle.putParcelable(Constant.CONFIRM_PAYMENT_REQUEST_TAG, testConfirmPayment)
//pass customerId
bundle.putString(Constant.CUSTOMER_ID_TAG, TestRequestData.customerId)
//pass default RequestPaymentMethod
bundle?.putParcelable(Constant.CREATE_PAYMENT_METHOD_REQUEST_TAG, testRequestPaymentMethod)
//pass default supportBankList
bundle?.putSerializable(Constant.SUPPORT_BANK_LIST_TAG, testBankIvList)
intent.putExtra(CURRENT_PAYMENT_BUNDLE, bundle)
//start payment
startActivityLauncher.launch(intent)
}
private val startActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
}
}
After the customer completes the payment by clicking Pay Now button, the payment activity will be dismissed and return to the PaymentSheetDemoActivity. At the same time,will callback PAYMENT_RESULT_PAYMENT.
// ...
class PaymentSheetDemoActivity: AppCompatActivity() {
private val startActivityLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Constant.PAYMENT_RESULT_CODE) {
// resultPayment
var payment =
it.data?.getParcelableExtra<Payment>(Constant.PAYMENT_RESULT_PAYMENT)
if (payment != null) {
when (payment.status) {
Constant.PAYMENT_SUCCEEDED -> {
Log.e(TAG, Constant.PAYMENT_SUCCEEDED)
}
Constant.PAYMENT_FAILED -> {
payment?.errorMessage?.let { it1 ->
Log.e(TAG, it1)
}
}
Constant.PAYMENT_UN_CAPTURED -> {
Log.e(TAG, Constant.PAYMENT_UN_CAPTURED_MESSAGE)
}
Constant.PAYMENT_PENDING -> {
Log.e(TAG, Constant.PAYMENT_PENDING_MESSAGE)
}
Constant.PAYMENT_CANCELED -> {
Log.e(TAG, Constant.PAYMENT_CANCELED_MESSAGE)
}
else -> {
Log.e(TAG, Constant.PAYMENT_PENDING_MESSAGE)
}
}
}
}
}
}
Use the completion block for handling the payment result.
If payment fails with an error, display the appropriate message to your customer so they can take action and try again. If no error has occurred, tell your customer that the payment was successful.
// ...
public class PaymentSheetDemoActivity extends AppCompatActivity {
//RequestCreatePayment Object
RequestCreatePayment testRequestPayment = TestRequestData.Companion.getTestRequestPayment();
//RequestConfirmPayment Object
RequestConfirmPayment testConfirmPayment = TestRequestData.Companion.getTestConfirmPayment();
//RequestPaymentMethod Object
RequestPaymentMethod testRaymentMethod = TestRequestData.Companion.getTestRequestPaymentMethod();
//support payment credit card
List<Integer> testBankIvList = TestRequestData.Companion.getTestBankIvList();
//customerId
String customerId = TestRequestData.Companion.getCustomerId();
// ...
private void presentPaymentSheet() {
//PayCardActivity contain SaveWithPaymentCardFragment and AddWithPaymentFragment,Support them to switch to each other
Intent intent = new Intent(this, PayCardActivity.class);
//Bundle Object
Bundle bundle = new Bundle();
//pass currentPaymentModel
bundle.putSerializable(
Constant.CURRENT_PAYMENT_MODEL,
currentPaymentModel
);
//pass RequestCreatePayment
bundle.putParcelable(
Constant.CREATE_PAYMENT_REQUEST_TAG,
testRequestPayment
);
//pass RequestConfirmPayment
bundle.putParcelable(
Constant.CONFIRM_PAYMENT_REQUEST_TAG,
testConfirmPayment
);
//pass currentId
bundle.putString(
Constant.CUSTOMER_ID_TAG,
customerId
);
//pass RequestPaymentMethod
bundle.putParcelable(Constant.CREATE_PAYMENT_METHOD_REQUEST_TAG, testRaymentMethod);
//pass default supportBankList
bundle.putSerializable(Constant.SUPPORT_BANK_LIST_TAG, TestRequestData.Companion.getTestBankIvList());
intent.putExtra(CURRENT_PAYMENT_BUNDLE, bundle);
startActivityLauncher.launch(intent);
}
private ActivityResultLauncher<Intent> startActivityLauncher =
PaymentSheetDemoActivity.this.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@SuppressLint("LongLogTag")
@Override
public void onActivityResult(ActivityResult result) {
}
});
}
After the customer completes the payment by tapping Pay Now button, the payment activity will be dismissed and return to the PaymentSheetDemoActivity. At the same time,will callback PAYMENT_RESULT_PAYMENT.
// ...
public class PaymentSheetDemoActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> startActivityLauncher =
PaymentSheetDemoActivity.this.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@SuppressLint("LongLogTag")
@Override
public void onActivityResult(ActivityResult result) {
// resultPayment
if (result.getResultCode() == Constant.PAYMENT_RESULT_CODE) {
Payment payment =
result.getData().getParcelableExtra(Constant.PAYMENT_RESULT_PAYMENT);
if (payment != null) {
if(payment.getStatus() != null) {
switch (payment.getStatus()) {
case Constant.PAYMENT_SUCCEEDED:
Log.e(TAG, Constant.PAYMENT_SUCCESSFUL_MESSAGE);
break;
case Constant.PAYMENT_FAILED:
Log.e(TAG, payment.getErrorMessage());
break;
case Constant.PAYMENT_UN_CAPTURED:
Log.e(TAG, Constant.PAYMENT_UN_CAPTURED_MESSAGE);
break;
case Constant.PAYMENT_PENDING:
Log.e(TAG, Constant.PAYMENT_PENDING_MESSAGE);
break;
case Constant.PAYMENT_CANCELED:
Log.e(TAG, Constant.PAYMENT_CANCELED_MESSAGE);
break;
default:
Log.e(TAG, Constant.PAYMENT_PENDING_MESSAGE);
break;
}
}else {
Log.e(TAG, Constant.PAYMENT_PENDING_MESSAGE);
}
}
}
}
});
}
Use the completion block for handling the payment result.
If payment fails with an error, display the appropriate message to your customer so they can take action and try again. If no error has occurred, tell your customer that the payment was successful.
There are several test cards you can use to make sure your integration is ready for production. Use them with any CVC, postal code, and future expiration date.
Card Number | Brand | DESCRIPTION |
---|---|---|
4242 4242 4242 4242 | Visa | Succeeds and immediately processes the payment. |
3566 0020 2036 0505 | JCBA | Succeeds and immediately processes the payment. |
6011 1111 1111 1117 | Discover | Succeeds and immediately processes the payment. |
3782 8224 6310 0052 | American Express | Succeeds and immediately processes the payment. |
5555 5555 5555 4444 | Mastercard | Succeeds and immediately processes the payment. |
4000002500003155 | Visa | This card requires 3D authentication on all transactions |
4000 0000 0000 0077 | Visa | Always fails with a decline code of |
Server side
Client side
Firstly, you need a MoneyCollect account. Register now
If the client side wants to access most of the MoneyConnectServer
API, it needs MoneyCollect dashboard to initiate a request through the private key
.
Download the mock merchant portal server interface code on github.
//Your account PUBLIC_SECRET("Bearer "+PUBLIC_SECRET)
private static final String PUBLIC_SECRET = "Bearer live_pu_OGJ0EidwEg4GjymEiRD7cUBk7IQIYmhwhJlUM****";
//Your account PRIVATE_SECRET("Bearer "+PRIVATE_SECRET)
private static final String PRIVATE_SECRET = "Bearer live_pr_OGJ0EidwEg4GjymEiRD4MRxBCo0OumdH6URv****";
The format of PUBLIC_SECRET & PRIVATE_SECRET is("Bearer"+PUBLIC_SECRET)
server.port=9898
The merchant replaces the public key
and private key
in the code with their own, and then switch on the server. (Default server port is 9099 which can be modified).(The dashboard interface address is the local ip:9898)
Import MoneyCollect android SDK and initialize SDK.
repositories {
jcenter()
maven{ url "https://raw.githubusercontent.com/MoneyCollect/moneycollect-api-android-demo/mcsdk" }
}
buildFeatures{
viewBinding = true
}
dependencies {
//The specific version number will be determined according to your needs
implementation "com.moneycollect.payment:android_mc:0.0.1"
}
Initialize MoneyCollect android sdk() in the project application
/**
* context: Context, (context)
* publishableKey: String, (publishable key)
* customerServerUrl: String? (Local ip:9898)
**/
MoneyCollectSdk.init(this, "live_pu_OGJ0EidwEg4GjymEiRD7cUBk7IQIYmhwhJlUM****","http://192.168.2.100:9898/");
After the merchant collects the user information, create a payment and complete the payment on the client side.(TestRequestData
is data constant class,please check moneycollect-api-android-demo for more details).
//RequestCreatePayment Object
RequestCreatePayment testRequestPayment = TestRequestData.Companion.getTestRequestPayment();
//RequestCreatePayment Object
val requestCreatePayment= TestRequestData.testRequestPayment
moneyCollect.createPayment(testRequestPayment , new ApiResultCallback<Payment>() {
@Override
public void onSuccess(@NotNull Payment result) {
if (result.getConfirmationMethod().equals(RequestCreatePayment.ConfirmationMethod.Manual)) {
confirmPayment(result);
}
}
@Override
public void onError(@NotNull Exception e) {
moneyCollectResultBackInterface.failExceptionBack(e.getMessage());
}
});
moneyCollect.createPayment(requestCreatePayment, object : ApiResultCallback<Payment> {
override fun onSuccess(result: Payment) {
if (result.confirmationMethod.equals(RequestCreatePayment.ConfirmationMethod.Manual)) {
confirmPayment(result)
}
}
override fun onError(e: Exception) {
moneyCollectResultBackInterface?.failExceptionBack(e.message)
}
})
When the transaction is created andconfirmationMethod
is manual
,confirmation of the payment is required to complete this transaction.
If confirmationMethod
is automatic
, the transaction can be completed directly.
private void confirmPayment(Payment payment) {
RequestConfirmPayment requestConfirmPayment = new RequestConfirmPayment(
BigInteger.valueOf(payment.getAmount()),
payment.getCurrency(),
payment.getId(),
payment.getIp(),
payment.getNotifyUrl(),
payment.getPaymentMethod(),
payment.getReceiptEmail(),
payment.getReturnUrl(),
payment.getSetupFutureUsage(),
new RequestConfirmPayment.Shipping(
currentRequestConfirmPayment.getShipping().address,
currentRequestConfirmPayment.getShipping().firstName,
currentRequestConfirmPayment.getShipping().lastName,
currentRequestConfirmPayment.getShipping().phone
), currentRequestConfirmPayment.getWebsite()
);
moneyCollect.confirmPayment(requestConfirmPayment, payment.getClientSecret(), new ApiResultCallback<Payment>() {
@Override
public void onSuccess(@NotNull Payment payment) {
if (payment==null){
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_PENDING_MESSAGE);
return;
}
if (payment.getNextAction() != null) {
String redirectToUrl = payment.getNextAction().redirectToUrl;
if (!TextUtils.isEmpty(redirectToUrl)) {
Intent intent = new Intent(getActivity(), ValidationWebActivity.class);
intent.putExtra(Constant.VALIDATION_PARAM_URL, redirectToUrl);
intent.putExtra(Constant.VALIDATION_PAYMENT_ID, payment.getId());
startActivityLauncher.launch(intent);
} else {
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_PENDING_MESSAGE);
}
} else {
String status = payment.getStatus();
if (status != null) {
switch (status) {
case Constant.PAYMENT_SUCCEEDED:
Intent intent = new Intent();
intent.putExtra(Constant.PAYMENT_RESULT_PAYMENT, payment);
if (getActivity()!=null) {
getActivity().setResult(Constant.PAYMENT_RESULT_CODE, intent);
}
moneyCollectResultBackInterface.paymentConfirmResultBack(true, "");
break;
case Constant.PAYMENT_FAILED:
moneyCollectResultBackInterface.paymentConfirmResultBack(false, payment.getErrorMessage());
break;
case Constant.PAYMENT_UN_CAPTURED:
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_UN_CAPTURED_MESSAGE);
break;
case Constant.PAYMENT_PENDING:
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_PENDING_MESSAGE);
break;
case Constant.PAYMENT_CANCELED:
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_CANCELED_MESSAGE);
break;
default:
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_PENDING_MESSAGE);
break;
}
} else {
moneyCollectResultBackInterface.paymentConfirmResultBack(false, Constant.PAYMENT_PENDING_MESSAGE);
}
}
}
@Override
public void onError(@NotNull Exception e) {
moneyCollectResultBackInterface.failExceptionBack(e.getMessage());
}
}
);
}
private fun confirmPayment(payment: Payment) {
var testConfirmPayment = RequestConfirmPayment(
amount = payment.amount?.toBigInteger(),
currency = payment.currency,
id = payment.id,
ip = payment.ip,
notifyUrl = payment.notifyUrl,
paymentMethod = payment.paymentMethod,
receiptEmail = payment.receiptEmail,
returnUrl = payment.returnUrl,
setupFutureUsage = payment.setupFutureUsage,
shipping = RequestConfirmPayment.Shipping(
address = address,
firstName = "Jenny",
lastName = "Rosen",
phone = "+18008675309"
),
website = "https://baidu222.com"
)
moneyCollect.confirmPayment(requestConfirmPayment, payment.clientSecret, object : ApiResultCallback<Payment> {
override fun onSuccess(result: Payment) {
//if nextAction object is not null and redirectToUrl address is not null, further 3 d verification
if (result.nextAction != null) {
if (!TextUtils.isEmpty(result.nextAction?.redirectToUrl)) {
val intent = Intent(activity, ValidationWebActivity::class.java)
intent.putExtra(Constant.VALIDATION_PARAM_URL,result.nextAction?.redirectToUrl)
intent.putExtra(Constant.VALIDATION_PAYMENT_ID, result.id)
intent.putExtra(Constant.VALIDATION_PAYMENT_CLIENTSECRET, result.clientSecret)
startActivityLauncher.launch(intent)
} else {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,Constant.PAYMENT_PENDING_MESSAGE)
}
} else {
//Need to deal with the state has succeeded, uncaptured, pending, failed, canceled
when (result.status) {
Constant.PAYMENT_SUCCEEDED -> {
var intent = Intent()
intent.putExtra(Constant.PAYMENT_RESULT_PAYMENT, result)
activity?.setResult(Constant.PAYMENT_RESULT_CODE,intent)
moneyCollectResultBackInterface?.paymentConfirmResultBack(true,"")
}
Constant.PAYMENT_FAILED -> {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,result.errorMessage)
}
Constant.PAYMENT_UN_CAPTURED -> {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,Constant.PAYMENT_UN_CAPTURED_MESSAGE)
}
Constant.PAYMENT_PENDING -> {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,Constant.PAYMENT_PENDING_MESSAGE)
}
Constant.PAYMENT_CANCELED -> {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,Constant.PAYMENT_CANCELED_MESSAGE)
}
else -> {
moneyCollectResultBackInterface?.paymentConfirmResultBack(false,Constant.PAYMENT_PENDING_MESSAGE)
}
}
}
}
override fun onError(e: Exception) {
moneyCollectResultBackInterface?.failExceptionBack(e.message)
}
})
}
If the payment needs to integrate 3D secure authentication, please refer to 3D secure authentication.
There are several test cards you can use to make sure your integration is ready for production. Use them with anyCVC
, postal code
, and future expiration date
.
Card Number | Brand | DESCRIPTION |
---|---|---|
4242 4242 4242 4242 | Visa | Succeeds and immediately processes the payment. |
3566 0020 2036 0505 | JCBA | Succeeds and immediately processes the payment. |
6011 1111 1111 1117 | Discover | Succeeds and immediately processes the payment. |
3782 8224 6310 0052 | American Express | Succeeds and immediately processes the payment. |
5555 5555 5555 4444 | Mastercard | Succeeds and immediately processes the payment. |
4000002500003155 | Visa | This card requires 3D authentication on all transaction |
4000 0000 0000 0077 | Visa | Always fails with a decline code of |