Getting Started with Visa Developer
First time to the Visa Developer Center? Watch this tutorial to learn where to find the Visa APIs th...
This document provides best practices for VCO integration in Android. The scenarios included in this document extracted from real world integration issues which merchants had faced. For any iOS Developers, we've got a guide for you as well, check it out here.
Android Best Practices
Here are the recommended devices and environment requirements:
```
android {
...
repositories {
...
flatDir { dirs 'libs' }
}
}
```
Add the Visa Checkout SDK to the `dependencies` block.
```
dependencies {
...
implementation(name:'visacheckout-android-sdk-7.1.1', ext:'aar')
}
```
*Ensure a minimum SDK version of 19 in the `defaultConfig` block.
```
defaultConfig {
...
minSdkVersion 19
}
```
```
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
```
* (Optional) Override `allowBackup` if it's set to true by adding the `replace` attribute.
```
<application
android:allowBackup="true"
tools:replace="allowBackup"
...
</application>
```
The recommended way to use the `CheckoutButton` is to add the Visa Checkout Button in your layout and prepare the button with profile and purchase information using the `init` method. This method will provide the button with the needed information to configure Visa Checkout and prepare for a button tap.
In your layout add the Visa Checkout Button in the following way:
```xml
<com.visa.checkout.CheckoutButton
android:id="@+id/btn_visa_checkout"
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_height"/>
```
```Java
public class CheckoutButtonActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Profile profile = new Profile.ProfileBuilder("MERCHANT-API-KEY", // TODO: Replace 'MERCHANT-API-KEY' with Api Key obtained from Visa Developer portal.
Environment.SANDBOX).setProfileName("PROFILE") // TODO: Replace 'PROFILE' with Profile Name obtained from Visa Developer portal.
.build();
PurchaseInfo purchaseInfo = new PurchaseInfo.PurchaseInfoBuilder(new BigDecimal("10.23"),
PurchaseInfo.Currency.USD) .build();
visaCheckoutButton = findViewById(R.id.btn_visa_checkout);
setUpCheckoutButton(profile, purchaseInfo) {
}
// Visa Checkout functionality is supported for devices running on KITKAT or above.
// Below version check needs to be added for client apps supporting minSdkVersion = 16
void setUpCheckoutButton(Profile profile, PurchaseInfo purchaseInfo) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
visaCheckoutButton.init(this, profile, purchaseInfo, new VisaCheckoutSdk.VisaCheckoutResultListener() {
@Override
public void onButtonClick(LaunchReadyHandler launchReadyHandler) {
launchReadyHandler.launch();
}
@Override
public void onResult(VisaPaymentSummary visaPaymentSummary) {
if (VisaPaymentSummary.PAYMENT_SUCCESS.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Success");
} else if (VisaPaymentSummary.PAYMENT_CANCEL.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Canceled");
} else if (VisaPaymentSummary.PAYMENT_ERROR.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Error");
} else if (VisaPaymentSummary.PAYMENT_FAILURE.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Generic Unknown failure");
}
}
});
}
}
```
Override the onResult() method as shown above to receive a `VisaPaymentSummary` object from Visa Checkout, which contains the encrypted payload, if requested and available. You have now completed the steps in adding the VCO standard button.
You also have the option to launch the Visa Checkout SDK using your own custom button instead of the Visa Checkout button. For instance, you may want to create a custom button and launch the Visa Checkout SDK whenever the button is tapped. Here’s how you can do it:
```Java
private ManualCheckoutSession.ManualCheckoutLaunchHandler launchHandler;
```
The following code snippet shows how to use the `VisaCheckoutSdk.initManualCheckoutSession` method in `onCreate` of the Activity you present Visa Checkout SDK from.
Replace 'MERCHANT-API-KEY' with Api Key obtained from Visa Developer portal.
Replace 'PROFILE' with Profile Name obtained from Visa Developer portal.
```Java
public class CustomButtonActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Profile profile = new Profile.ProfileBuilder("MERCHANT-API-KEY", // TODO: Replace 'MERCHANT-API-KEY' with Api Key obtained from Visa Developer portal.
Environment.SANDBOX).setProfileName("PROFILE") // TODO: Replace 'PROFILE' with Profile Name obtained from Visa Developer portal.
.build();
PurchaseInfo purchaseInfo = new PurchaseInfo.PurchaseInfoBuilder(new BigDecimal("10.23"),
PurchaseInfo.Currency.USD)
.build();
setUpCustomButton(profile, purchaseInfo);
}
void setUpCustomButton(Profile profile, PurchaseInfo purchaseInfo) {
final ImageView customButton = findViewById(R.id.custom_button);
customButton.setVisibility(View.VISIBLE);
customButton.setBackground(VisaCheckoutSdk.getCardArt(this.getApplicationContext()));
// Visa Checkout is supported for devices running Android KITKAT or above.
// Below version check needs to be added for apps supporting minSdkVersion = 16
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
VisaCheckoutSdk.initManualCheckoutSession(this, profile, purchaseInfo, new ManualCheckoutSession() {
@Override
public void onReady(ManualCheckoutLaunchHandler manualCheckoutLaunchHandler) {
// store launch handler for later use on click event
launchHandler = manualCheckoutLaunchHandler;
}
@Override
public void onResult(VisaPaymentSummary visaPaymentSummary) {
//this call invokes the function VisaCheckoutSdk.initManualCheckoutSession and makes sure that you have the right handler
if (VisaPaymentSummary.PAYMENT_SUCCESS.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Success");
} else if (VisaPaymentSummary.PAYMENT_CANCEL.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Canceled");
} else if (VisaPaymentSummary.PAYMENT_ERROR.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Error");
} else if (VisaPaymentSummary.PAYMENT_FAILURE.equalsIgnoreCase(visaPaymentSummary.getStatusName())) {
Log.d("AppTag", "Generic Unknown failure");
}
setUpCustomButton(profile, purchaseInfo);
}
});
}
}
```
```Java
customButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
if (launchHandler != null) {
launchHandler.launch();
}
}
});
```
Great, you should now be able to add the custom button on your app. Let's move on.
1. In your layout add a parent `RelativeLayout` to your `Activity's layout` file.
```xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/parentRelativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</RelativeLayout>
```
2. Call `VisaCheckoutHybridPlugin's configure()` from the `Activity` that contains the `WebView` used to show Visa Checkout.
```Java
public class HybridPluginActivity extends AppCompatActivity {
RelativeLayout relativeLayout;
Webview webview;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
relativeLayout = findViewById(R.id.parentRelativeLayout);
webview = findViewById(R.id.webview);
setWebView();
}
// Visa Checkout functionality is supported for devices running on KITKAT or above.
// Below version check needs to be added for client apps supporting minSdkVersion = 16
void setWebView() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
mWebView.getSettings().setSupportMultipleWindows(true);
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, true);
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, final Message resultMsg) {
WebView.HitTestResult result = view.getHitTestResult();
// finish configure by sending the Message object if all conditions are true.
if(result.getType() == WebView.HitTestResult.UNKNOWN_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
try {
Message href = view.getHandler().obtainMessage();
view.requestFocusNodeHref(href);
Bundle data = href.getData();
if (data.get("url") == null && data.get("title") == null) {
if(visaCheckoutHybridPlugin != null) {
visaCheckoutHybridPlugin.finishConfigure(resultMsg);
return true;
}
}
} catch (Exception e) {
}
}
return false;
}
});
initHybridPlugin();
}
webview.loadUrl(url);
}
void initHybridPlugin() {
if(visaCheckoutHybridPlugin != null) {
// call VisaCheckoutHybridPlugin.clean() when reloading webView and leaving this activity/fragment
visaCheckoutHybridPlugin.clean();
}
// make visaCheckoutHybridPlugin an Activity gloabl variable
visaCheckoutHybridPlugin = new VisaCheckoutHybridPlugin();
visaCheckoutHybridPlugin.configure(webView, this, relativeLayout,
new HybridPluginViewListener() {
@Override
public void hideViews() {
// Hide any views that will overlay the plugin
// Will be called as soon as the user taps the button
webView.setVisibility(View.INVISIBLE);
}
@Override
public void showViews() {
// Show any views that were hidden for the plugin
// Will be called after user finishes a flow (Success, Error, Canceled, Generic Unknown failure)
webView.setVisibility(View.VISIBLE);
}
});
}
}
```
3. Call `VisaCheckoutHybridPlugin's overrideBackButton()` from the `Activity` to override its `onBackPressed()`.
```Java
@Override
public void onBackPressed() {
if(visaCheckoutHybridPlugin != null) {
if (visaCheckoutHybridPlugin.overrideBackButton()) {
return;
}
visaCheckoutHybridPlugin = null;
}
super.onBackPressed();
}
```
private void launchOnReady() {
VisaCheckoutSdk.initManualCheckoutSession(this, profile, purchaseInfo
, new ManualCheckoutSession() {
@Override
public void onResult(VisaPaymentSummary paymentSummary) {
Log.i(TAG, "onResult: " + paymentSummary.getStatusName());
Log.i(TAG, "callID: " + paymentSummary.getCallId());
if (this != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
launchOnReady();
}
});
}
}
@Override
public void onReady(ManualCheckoutLaunchHandler manualLaunchHandler) {
Log.i(TAG, "OnReady...");
manualHandler = manualCheckoutLaunchHandler;
if (manualHandler != null) {
manualHandler.launch();
}
}
});
}
When the user calls the launchOnReady() recursively in the onResult(...){...}, then once the user tries to come to the calling application, VCO SDK will launch the lightbox continuously. So to end the cycle, the user has to terminate the application.
When the VCO SDK get launched like this, and for some reason if the Dialog does not visible to the user, or set isCancelable to true, then the user accidently presses the screen just outside the dialog box, then the user will not be able to launch the VCO lightbox.
- When the merchant initializes the VCO SDK multiple times, the VCO lightbox may launch several times and sometimes it will lead to errors.
- When the merchant uses automation tools to automate the lightbox at front end, at the backend, it will detect and stop responding to the user.
We hope this helps as you integrate the Visa Checkout Android SDK. Any questions? Comment below, we're here to help.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
First time to the Visa Developer Center? Watch this tutorial to learn where to find the Visa APIs th...
Watch the recording of my How to Run a Visa Direct Transaction using Python webinar as you follow al...
Learn how to create a project and where to find test data, credentials and sample code. Leave a comm...
We feel that the Visa Developer Center has come full circle since launch in 2016. It hosts many APIs...