This guide will help you integrate your existing POS system, which runs on Android, with the Adyen payments platform.
Before you begin to integrate, make sure you have followed the Get started with Adyen guide to:
- Get an overview of the steps needed to accept live payments.
- Create your test account.
Add the Adyen library module as a dependency to your app module
-
Import the new Adyen Android Library module.
- Go to File > Project Structure in Android Studio.
- Press the + button on the upper-left corner of the Project Structure window to add a new module.
-
In the Create new module screen:
- Select Import .JAR/.AAR Package and click Next.
- In the file selector, browse to the unzipped adyen-android-library-{version}.aar file.
-
Add a dependency in the app module to the Adyen library module.
-
Go to File > Project structure in Android Studio.
-
Select the app module in the Modules list on the left.
-
Select the Dependencies tab.
-
Add dependency on the + button on the lower left corner.
-
Select 3.Module dependency in the drop down menu.
-
Select the Adyen library module you have previously added in step 3.
-
-
Add dependency for appcompat-v7.
-
Go to File > Project Structure in Android Studio.
-
Select the app module in the Modules list on the left.
-
Select the Dependencies tab.
-
Click the + button on the lower left to add the dependency.
-
Select 1. Library dependency in the drop down menu.
-
From the Choose Library Dependency screen choose the com.android.support:appcompat-v7:{version}.
-
Click OK.
-
-
Sync project with gradle files.
You can now use the Adyen library in your Android application.
Register your app module
-
Register your app module with the Adyen library module.
public class App extends Application { @Override public void onCreate() { super.onCreate(); try { LibraryReal.registerLib(getApplicationContext(), getString(R.string.app_name)); } catch (final AlreadyRegisteredException e) { // Do nothing. } } }
app_name
- Format this value like so: Cash register company and product / Cash register product version / Adyen integration name / Adyen integration version. For example, Acme Corp POS / 1.2.1 / Acme Adyen connector / 0.1
Get an instance of the Adyen library
-
Once the Adyen library is registered, you can use functionality from the Adyen library instance.
@Nullable public AdyenLibraryInterface getAdyenLibrary() { if (mAdyenLibrary == null) { try { mAdyenLibrary = LibraryReal.getLib(); } catch (NotYetRegisteredException e) { Log.e(TAG, "Failed to get AdyenLibraryInterface, the library must be registered first", e); } } return mAdyenLibrary; }
Register the merchant credentials with the Adyen library
-
Register merchant credentials (merchant, username, password) with the Adyen library, and set the desired ServerMode [DEV/TEST/BETA/LIVE].
AdyenLibraryInterface adyenLibrary = getAdyenLibrary(); adyenLibrary.setServerMode(ServerMode.TEST); try { adyenLibrary.registerApp(merchant, username, password, createRegistrationCompleteListener()); } catch (AppAlreadyRegisteredException e) { e.printStackTrace(); } catch (AlreadyRegisteringAppException e) { e.printStackTrace(); } catch (InvalidRequestException e) { e.printStackTrace();
-
Implement the
RegistrationCompleteListener
to handle the response from registration of merchant credentials.private RegistrationCompleteListener createRegistrationCompleteListener() { return (statusCode, appInfo, statusMessage) -> { Log.i(TAG, "statusCode: " + statusCode + ", statusMessage: " + statusMessage); switch (statusCode) { case OK: // Redirect from the LoginActivity to your HomeActivity Intent intent = HomeActivity.getIntent(LoginActivity.this); startActivity(intent); finish(); break; case ERROR_NONETWORK: // Failed to register the app, network issues. break; case ERROR_BADCREDENTIALS: // Failed to register the app, bad merchant credentials. break; case ERROR_NOROUTE: // Failed to register the app, network issues. // The phone cannot connect to the Adyen backend (even if there is internet connection) case ERROR: // Failed to register the app, general error look at the statusMessage. default: Log.e(TAG, "statusCode: " + statusCode + ", statusMessage: " + statusMessage); break; } }; }
Register a payment terminal
-
Create a new DeviceInfo instance:
Wi-Fi devices:DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setConnectionType(DeviceInfo.TYPE_WIFI); deviceInfo.setDeviceId(mDeviceIpAddressEditText.getText().toString()); deviceInfo.setFriendlyName("Cash register 1"); onAddDevice(deviceInfo);
Bluetooth devices:
DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setConnectionType(DeviceInfo.TYPE_BT); deviceInfo.setFriendlyName(device.getName()); deviceInfo.setDeviceId(device.getAddress()); onAddDevice(deviceInfo);
-
Add the device to the Adyen library:
private void addDevice(@NonNull DeviceInfo deviceInfo) { Log.d(TAG, "addDevice() called with: deviceInfo = [" + deviceInfo + "]"); try { getAdyenLibrary().addDevice(createAddDeviceListener(), deviceInfo); } catch (DeviceAlreadyAddedException e) { e.printStackTrace(); } catch (AlreadyAddingDeviceException e) { e.printStackTrace(); } catch (AppNotRegisteredException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
-
Implement the
AddDeviceListener
to handle adding devices to the Adyen library:private AddDeviceListener createAddDeviceListener() { return new AddDeviceListener() { @Override public void onAddDeviceComplete(CompletedStatus completedStatus, String statusMessage, DeviceData deviceData) { Log.d(TAG, "onAddDeviceComplete() called with: completedStatus = [" + completedStatus + "], statusMessage = [" + statusMessage + "], deviceData = [" + deviceData + "]"); switch (completedStatus) { case OK: // Boarding the device succeeded break; case TIMEOUT: // Failed to board the device, connection timeout. break; case ERROR: // Failed to board the device, general error look at the status message. break; case ERROR_SYNCACTION: // Failed to board the device, ??? break; case ERROR_VERIFY: // Failed to board the device, couldn't verify ??? break; case ERROR_NOROUTE: // Failed to board the device, // The phone cannot connect to the Adyen backend (even if there is internet connection) break; case ERROR_IDENTIFY: // Failed to board the device, couldn't identify terminal device with Adyen backend. break; case ERROR_REGISTER: // Failed to board the device, couldn't register the teminal device with Adyen backend. break; case ERROR_NONETWORK: // Failed to board the device, network issues. break; case ERROR_SYNCDEVICE: // Failed to board the device. failed to sync device with Adyen backend. break; case ERROR_CONFLICTING_SERVER_MODE: // Failed to board the device, due to server mode try to register the Adyen library with a different server mode. break; } } @Override public void onProgress(ProcessStatus processStatus, String message) { Log.d(TAG, "onProgress() called with: processStatus = [" + processStatus + "], message = [" + message + "]"); switch (processStatus) { case PREPARING: break; case IDENTIFY: break; case REGISTER: break; case SYNCACTION: break; case SYNCDEVICE: break; case VERIFY: break; case RUNNING_TRANSACTION: break; case STEP_4_OK: break; case NONETWORK: break; case NOROUTE: break; } if (!TextUtils.isEmpty(message)) { // Notify the user with the progress status message. mStatusTextView.setText(message); } } }; }
Connect to the registered payment terminal
-
Once the payment terminal is added, you can connect it by using the
connectDevice
method:private void connectDevice(@NonNull DeviceInfo deviceInfo) { try { getAdyenLibrary().connectDevice(deviceInfo, true, true); getAdyenLibrary().setDefaultDeviceInfo(deviceInfo); } catch (UnknownDeviceIdException e) { Log.e(TAG, "Failed to connect to device, first add the device to the Adyen library: ", e); } catch (IOException e) { Log.e(TAG, "Failed to connect to device, network issues: ", e); } }
Accept payments
Once the terminal device is added and connected to the Adyen library. You can start making payment requests:
-
Create new
TransactionRequest
instance (This is the most basic transaction request):transactionRequest = new TransactionRequest(); transactionRequest.setValue(value); transactionRequest.setCurrencyCode(currency); transactionRequest.setVendorDescription(description); transactionRequest.setTransactionType(transactionType); transactionRequest.setShopperLocale(Locale.getDefault().toString()); ArrayList<TenderOptions> tenderOptions = new ArrayList<>(); transactionRequest.setTenderOptions(tenderOptions);
-
Initiate a transaction with the previously created
TransactionRequest
instance.private void initiateTransaction(@NonNull TransactionRequest transactionRequest) { try { getAdyenLibrary().initiateTransaction(transactionRequest, createTransactionListener()); } catch (InvalidTransactionRequestException e) { Log.e(TAG, "Invalid transaction request: ", e); } catch (AlreadyProcessingTransactionException e) { Log.e(TAG, "Transaction failed, that transaction already processed: ", e); } catch (NoDefaultDeviceException e) { Log.e(TAG, "Transaction failed, first set default terminal device, then try again: ", e); } catch (IOException e) { Log.e(TAG, "Transaction failed, network issues: ", e); } }
-
Implement a
TransactionListener
to handle transaction responses as follows:private TransactionListener createTransactionListener() { return new TransactionListener() { @Override public void onTransactionComplete(CompletedStatus completedStatus, String statusMessage, Integer code, Map<String, String> additionalData) { Log.d(TAG, "onTransactionComplete() called with: completedStatus = [" + completedStatus + "], statusMessage = [" + statusMessage + "], code = [" + code + "], additionalData = [" + additionalData + "]"); switch (completedStatus) { case APPROVED: // Transaction succeeded. break; case DECLINED: // Declined because: // The amount too low or other card reasons. // Transaction was canceled by getAdyenLibrary().cancelTransaction(). // etc. break; case CANCELLED: // Transaction was cancel: // By the merchant from the Android app. // By the shopper from the Terminal device. break; case ERROR: // My be because network issues, communication is lost. break; } } @Override public void onProgress(ProcessStatus processStatus, String message) { Log.d(TAG, "onProgress() called with: processStatus = [" + processStatus + "], message = [" + message + "]"); switch (processStatus) { case CONNECTING: // App is connecting to the terminal - just starts a connection break; case IDENTIFYING: // Identifying the terminal - the connection was established and now the terminal is been identified break; case PROCESSING: // The terminal is processing the payment break; case NONETWORK: // The phone doesn't have internet connection break; case NOROUTE: // The phone cannot connect to the Adyen backend (even if there is internet connection) break; case CANCELLING: // The merchant or the shopper cancelled the transaction break; } } @Override public void onStateChanged(TenderStates tenderStates, String s, Map<String, String> map) { Log.d(TAG, "onStateChanged() called with: tenderStates = [" + tenderStates + "], s = [" + s + "], map = [" + map + "]"); switch (tenderStates) { case PIN_DIGIT_ENTERED: // pin digits was entered in the terminal device break; case INITIAL: // transaction was initiated break; case TENDER_CREATED: // a new tender was created break; case CARD_INSERTED: // the card was inserted break; case CARD_SWIPED: // the card was swiped break; case WAIT_FOR_APP_SELECTION: // waiting for some input from the customer on the terminal break; case APPLICATION_SELECTED: // the customer selected something from the previous step break; case WAIT_FOR_AMOUNT_ADJUSTMENT: // waiting for an amount to be adjusted based on the gratuity break; case ASK_GRATUITY: // gratuity option was selected in tender options and the shuttle requests for it break; case GRATUITY_ENTERED: // gratuity amount was entered break; case ASK_DCC: // dynamic currency conversion was selected in tender options break; case DCC_ACCEPTED: // the conversion amount was accepted break; case DCC_REJECTED: // the conversion amount was rejected break; case PROCESSING_TENDER: // the payment is being processed (on the terminal you can see the progress bar) break; case WAIT_FOR_PIN: // pin is being requested on the terminal break; case PIN_ENTERED: // the user accepted the pin break; case PROVIDE_CARD_DETAILS: // for MKE the card details are requested break; case CARD_DETAILS_PROVIDED: // for MKE the card details were provided break; case PRINT_RECEIPT: // starting printing the receipt (receipt generation) break; case RECEIPT_PRINTED: // the receipt printing was finished break; case REFERRAL: // the acquirer sends a referral status break; case REFERRAL_CHECKED: // the referral code was checked break; case CHECK_SIGNATURE: // after the user has entered the signature, there's a check between the signature on the card and the one on the screen/receipt break; case SIGNATURE_CHECKED: // the signature matched the one on the card break; case ADDITIONAL_DATA_AVAILABLE: // additional data (like currency conversion rate, adjusted amount for gratuity and others) are available break; case ERROR: // final states of a transaction break; case APPROVED: // transaction was approved break; case DECLINED: // transaction was declined break; case CANCELLED: // transaction was cancelled break; case UNKNOWN: break; case ACKNOWLEDGED: break; } } }; }