This guide will help you integrate your existing POS system, which runs on Android, with the Adyen payments platform.
To proceed with this tutorial you should sign up for a test account. If you haven't done so yet, submit your details on this page.
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; } } }; }