This SDK provides an UI to take required information from user to execute transaction.
Sample Project to implement the Android SDK here.
Latest Version
Download the latest version here.
Latest Released version logs on Github release page.
Android SDK Changes
version 1.28.0
:
1.28.0
:- If using UIKit and the device is going to use 3G/4G internet (Data network), it is required on Android to have
READ_PHONE_STATE
permission in order to access network type of the device. the purpose ofREAD_PHONE_STATE
permission is to capture network on event tracker. Therefore, before launching the UI kit, it is mandatory to check if this permission has been granted or not. If it has not been granted, we need to keep asking user. It is not needed for WIFI connection and version below1.28.0
.
Request Permission before launching UI kit for Android SDK version 1.28.0 and above
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 101);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 101);
}
- If the Host app got build error with message
Invoke-customs are only supported starting with Android O
a block of code to specify java version is needed onbuild.gradle
.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Starting version 1.29.0
:
1.29.0
:-
To avoid crash in SDK Version
1.29.0
, it will make optional to implementREAD_PHONE_STATE
permission, so the host app is not required to ask the user to give the permission. -
Since we increase the
localizationVersion
to1.2.10
it required to addmultiDexEnabled true
in Host Appbuild.gradle
[Important] Starting version 1.34.0
:
1.34.0
:- To avoid inconsistencies for e-money method on tablet, starting from version
1.34.0
the payment type for gopay on tablet is no longergopay
but changed toqris
same as ShopeePay usingqris
- The JSON fields format response is different between
"payment_type": "qris"
and"payment_type": "gopay"
. This will affect Webhook/HTTP Notification and Get Status API Response. Refer to the notification example section for details. - Due to the difference in response between qris and gopay, you need to remap the response for the Notification and Get Status API. So please ensure that your system’s implementation can handle this behavior without breaking your system & its payment flow. Especially on the following parts (if applicable):
- Your Notifications Handler implementation logic.
- Get Status API implementation logic.
- Reconciliation implementation logic.
- For more details regarding QRIS related behavior, please refer to this section
[Important] Starting version 2.0.0
:
2.0.0
:- Midtrans SDK 2.0.0 is a major revamp for Midtrans SDK that includes UI changes and updates to improve user experience.
- There are two scenarios for the existing users to write code using this Revamp SDK:
- Using Existing Code: For existing users who want to continue using their existing code, simply upgrade the SDK version in the
build.gradle
file. This revamp supports backward compatibility, so there is no need to make any changes to the existing code. - Using Revamped Code: For existing users who want to take advantage of the new UI changes and improvements, we recommend using the revamped code. This approach will ensure that future updates to the SDK, since the next updates will released with the revamp-first mindset.
- Using Existing Code: For existing users who want to continue using their existing code, simply upgrade the SDK version in the
- For new users who are just starting to use the Midtrans Mobile SDK, we highly recommend using the revamped approach. This will ensure that you have access to the latest updates and improvements to the SDK.
Please make sure to follow the setup instructions and guidelines provided in the Snap SDK documentation to ensure a smooth integration process. If you have any questions or concerns, don't hesitate to reach out to our support team.
Android Permission
UI KIT
- ACCESS_NETWORK_STATE
- READ_PHONE_STATE
Installation
Add SDK installation following into your build.gradle
Midtrans Maven Repository
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
Sample SDK Sandbox Dependencies
dependencies {
// For using the Midtrans Sandbox
implementation 'com.midtrans:uikit:2.0.0-SANDBOX' // change the number to the latest version
}
dependencies {
// For using the Midtrans Sandbox
implementation 'com.midtrans:uikit:2.0.0-SANDBOX' // change the number to the latest version
}
Sample SDK Production Dependencies
dependencies {
// For using the Midtrans Production
implementation 'com.midtrans:uikit:2.0.0' // change the number to the latest version
}
dependencies {
// For using the Midtrans Production
implementation 'com.midtrans:uikit:1.34.0' // change the number to the latest version
}
You need to add Midtrans SDK inside your app’s module build.gradle
. Make sure to use the proper environment (SANDBOX / PRODUCTION).
Midtrans SDK Initialization
UiKitApi.Builder()
.withMerchantClientKey(CLIENT_KEY) // client_key is mandatory
.withContext(CONTEXT) // context is mandatory
.withMerchantUrl(BASE_URL) // set transaction finish callback (sdk callback)
.enableLog(true) // enable sdk log (optional)
.withFontFamily(ASSET_FONT)
.withColorTheme(CustomColorTheme("#FFE51255", "#B61548", "#FFE51255"))
.build()
setLocaleNew("en") //`en` for English and `id` for Bahasa
...
// function to set the SDK language
private fun setLocaleNew(languageCode: String?) {
val locales = LocaleListCompat.forLanguageTags(languageCode)
AppCompatDelegate.setApplicationLocales(locales)
}
SdkUIFlowBuilder.init()
.setClientKey(CLIENT_KEY) // client_key is mandatory
.setContext(CONTEXT) // context is mandatory
.setTransactionFinishedCallback(new TransactionFinishedCallback() {
@Override
public void onTransactionFinished(TransactionResult result) {
// Handle finished transaction here.
}
}) // set transaction finish callback (sdk callback)
.setMerchantBaseUrl(BASE_URL) //set merchant url (required)
.enableLog(true) // enable sdk log (optional)
.setColorTheme(new CustomColorTheme("#FFE51255", "#B61548", "#FFE51255")) // set theme. it will replace theme on snap theme on MAP ( optional)
.setLanguage("en") //`en` for English and `id` for Bahasa
.buildSDK();
Then you need to initialize it on your activity or application class.
Note:
- CONTEXT: Application/activity context
- CLIENT_KEY: Your midtrans client key (provided in MAP)
- BASE_URL: Your merchant server URL
Differentiate Sandbox and Production in one app (Optional)
Differentiate Sandbox and Production Flavors
android {
...
// Define Merchant BASE URL and CLIENT KEY for each flavors
productFlavors {
sandbox {
buildConfigField "String", "BASE_URL", "\"https://merchant-url-sandbox.com/\""
buildConfigField "String", "CLIENT_KEY", "\"VT-CLIENT-sandbox-client-key\""
}
production {
buildConfigField "String", "BASE_URL", "\"https://merchant-url-production.com/\""
buildConfigField "String", "CLIENT_KEY", "\"VT-CLIENT-production-client-key\""
}
}
...
}
// Define Midtrans SDK dependencies for each flavors
dependencies {
...
sandboxImplementation 'com.midtrans:uikit:2.0.0-SANDBOX' // change the version to latest one
productionImplementation 'com.midtrans:uikit:2.0.0' // change the version to latest one
...
}
android {
...
// Define Merchant BASE URL and CLIENT KEY for each flavors
productFlavors {
sandbox {
buildConfigField "String", "BASE_URL", "\"https://merchant-url-sandbox.com/\""
buildConfigField "String", "CLIENT_KEY", "\"VT-CLIENT-sandbox-client-key\""
}
production {
buildConfigField "String", "BASE_URL", "\"https://merchant-url-production.com/\""
buildConfigField "String", "CLIENT_KEY", "\"VT-CLIENT-production-client-key\""
}
}
...
}
// Define Midtrans SDK dependencies for each flavors
dependencies {
...
sandboxImplementation 'com.midtrans:uikit:1.34.0-SANDBOX' // change the version to latest one
productionImplementation 'com.midtrans:uikit:1.34.0' // change the version to latest one
...
}
You can support two payment environments in your app by defining two flavors in your build.gradle
.
Initialize Midtrans SDK using provided base URL and client key in BuildConfig
UiKitApi.Builder()
.withMerchantClientKey(CLIENT_KEY) // client_key is mandatory
.withContext(CONTEXT) // context is mandatory
.withMerchantUrl(BASE_URL) // set transaction finish callback (sdk callback)
.enableLog(true) // enable sdk log (optional)
.withFontFamily(ASSET_FONT) // set font family
.withColorTheme(CustomColorTheme("#FFE51255", "#B61548", "#FFE51255")) // set theme. it will replace theme on snap theme on MAP ( optional)
.build()
SdkUIFlowBuilder.init()
.setClientKey(CLIENT_KEY) // client_key is mandatory
.setContext(CONTEXT) // context is mandatory
.setTransactionFinishedCallback(new TransactionFinishedCallback() {
@Override
public void onTransactionFinished(TransactionResult result) {
// Handle finished transaction here.
}
}) // set transaction finish callback (sdk callback)
.setMerchantBaseUrl(BASE_URL) //set merchant url (required)
.enableLog(true) // enable sdk log (optional)
.setColorTheme(new CustomColorTheme("#FFE51255", "#B61548", "#FFE51255")) // set theme. it will replace theme on snap theme on MAP ( optional)
.buildSDK();
Initialize your SDK using merchant BASE_URL and CLIENT_KEY provided by BuildConfig data.
Starting Payment
Use Snap Token Flow
The easiest way to use the SDK - what you need to do will be to integrate to Midtrans' backend and retrieve the Snap Token, then pass Snap token as argument of startPaymentUiFlow
method. SDK will then show the payment page immediately; no need to create any transaction object on the SDK.
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result?.resultCode == RESULT_OK) {
result.data?.let {
val transactionResult = it.getParcelableExtra<TransactionResult>(UiKitConstants.KEY_TRANSACTION_RESULT)
Toast.makeText(this,"${transactionResult?.transactionId}", Toast.LENGTH_LONG).show()
}
}
}
UiKitApi.getDefaultInstance().startPaymentUiFlow(
this@MainActivity, // Activity
launcher, // ActivityResultLauncher
"25e3659b-f00c-4d98-bfff-9f72978c8df5" // Snap Token
)
MidtransSDK.getInstance().startPaymentUiFlow(ACTIVITY_CONTEXT, SNAP_TOKEN);
Transaction Finished Callback
In order to get the Transaction Result, you can subscribe for a Transaction Finished Callback by overriding onTransactionFinished
method. The method will provide TransactionResult
object which has several states.
When response is not null:
TransactionResult.STATUS_SUCCESS
TransactionResult.STATUS_PENDING
TransactionResult.STATUS_FAILED
When transaction is canceled, it can be checked with result.isTransactionCanceled()
When response is null:
TransactionResult.STATUS_INVALID
//In revamp we use launcher instead of callback, the transaction result will send to the launcher.
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result?.resultCode == RESULT_OK) {
result.data?.let {
val transactionResult = it.getParcelableExtra<TransactionResult>(UiKitConstants.KEY_TRANSACTION_RESULT)
Toast.makeText(this,"${transactionResult?.transactionId}", Toast.LENGTH_LONG).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == RESULT_OK) {
val transactionResult = data?.getParcelableExtra<TransactionResult>(
UiKitConstants.KEY_TRANSACTION_RESULT
)
if (transactionResult != null) {
when (transactionResult.status) {
STATUS_SUCCESS -> {
Toast.makeText(this, "Transaction Finished. ID: " + transactionResult.transactionId, Toast.LENGTH_LONG).show()
}
STATUS_PENDING -> {
Toast.makeText(this, "Transaction Pending. ID: " + transactionResult.transactionId, Toast.LENGTH_LONG).show()
}
STATUS_FAILED -> {
Toast.makeText(this, "Transaction Failed. ID: " + transactionResult.transactionId, Toast.LENGTH_LONG).show()
}
STATUS_CANCELED -> {
Toast.makeText(this, "Transaction Cancelled", Toast.LENGTH_LONG).show()
}
STATUS_INVALID -> {
Toast.makeText(this, "Transaction Invalid. ID: " + transactionResult.transactionId, Toast.LENGTH_LONG).show()
}
else -> {
Toast.makeText(this, "Transaction ID: " + transactionResult.transactionId + ". Message: " + transactionResult.status, Toast.LENGTH_LONG).show()
}
}
} else {
Toast.makeText(this, "Transaction Invalid", Toast.LENGTH_LONG).show()
}
}
super.onActivityResult(requestCode, resultCode, data)
}
@Override
public void onTransactionFinished(TransactionResult result) {
if (result.getResponse() != null) {
switch (result.getStatus()) {
case TransactionResult.STATUS_SUCCESS:
Toast.makeText(this, "Transaction Finished. ID: " + result.getResponse().getTransactionId(), Toast.LENGTH_LONG).show();
break;
case TransactionResult.STATUS_PENDING:
Toast.makeText(this, "Transaction Pending. ID: " + result.getResponse().getTransactionId(), Toast.LENGTH_LONG).show();
break;
case TransactionResult.STATUS_FAILED:
Toast.makeText(this, "Transaction Failed. ID: " + result.getResponse().getTransactionId() + ". Message: " + result.getResponse().getStatusMessage(), Toast.LENGTH_LONG).show();
break;
}
result.getResponse().getValidationMessages();
} else if (result.isTransactionCanceled()) {
Toast.makeText(this, "Transaction Canceled", Toast.LENGTH_LONG).show();
} else {
if (result.getStatus().equalsIgnoreCase(TransactionResult.STATUS_INVALID)) {
Toast.makeText(this, "Transaction Invalid", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Transaction Finished with failure.", Toast.LENGTH_LONG).show();
}
}
}
Logging
Enable to show SDK log for debugging. For security purposes however, we encourage merchants to disable it on production apps.
UiKitApi.Builder()
.withMerchantClientKey(CLIENT_KEY) // client_key is mandatory
.withContext(CONTEXT) // context is mandatory
.withMerchantUrl(BASE_URL) // set transaction finish callback (sdk callback)
.enableLog(true) // enable sdk log (optional)
.withFontFamily(ASSET_FONT)
.withColorTheme(CustomColorTheme("#FFE51255", "#B61548", "#FFE51255"))
.build()
setLocaleNew("en") //`en` for English and `id` for Bahasa
...
Note:
Enable during initialization.
CONTEXT: Application/activity context
CLIENT_KEY: Your Midtrans client key
BASE_URL: Your merchant server URL
enableLog: enable to show sdk log for debugging