Java (Android)
In this topic:
Device Requirements
- Minimum API level is 22 (open_in_newplatform version 5.1Link opens new window)
- Gradle Plugin 4.2.2
- The target API the Commerce SDK sample application uses out of the box is 32 (open_in_newplatform version 12Link opens new window). You can lower the target SDK requirements in
build.gradle
in the sample app and disable the runtime permissions in the code of the sample app. - Device cannot be rooted
- Emulator / simulator is not supported
Workstation Configuration
If your workstation is already configured for Android development then you can most likely jump to the next section. Otherwise you can follow this high-level overview for setting up your environment.
Minimum Requirements
You can review the minimum workstation requirements in open_in_newAndroid StudioLink opens new window.
Set Up the Environment
- Download and install the latest open_in_newOracle 1.8 32-bit JDKLink opens new window.
- Set the
JAVA_HOME
variable to point to the appropriate directory. - Add
JAVA_HOME\bin
to your shell’s Path variable. - Download and install either open_in_newAndroid StudioLink opens new window or open_in_newIntelliJLink opens new window and the open_in_newAndroid SDKLink opens new window.
- Set the
ANDROID_HOME
variable to the appropriate directory. - Configure your IDE to use the JDK and Android SDK as default platforms for new projects.
Refer to the open_in_newAndroid Developer DocumentationLink opens new window for more information.
Build the Sample Application
Unzip the sample app zip file. This example will assume you extracted the files into
c:\sample-app
.Open
build.gradle
and look forcompileSdkVersion
andbuildToolsVersion
. If you do not have those particular versions of the Android SDK installed, you have two choices:- You can change the values of those two variables to match the API level of the SDK you installed. Then save and close
build.gradle
. - You can install the Android SDK platform version to match these versions.
- You can change the values of those two variables to match the API level of the SDK you installed. Then save and close
Open your IDE and create a New project from Existing Sources.
Navigate to
c:\sample-app
and select thebuild.gradle
file. Click Ok to continue through the wizard.Once the IDE has stopped churning, open up the gradle tool window (View > Tool Windows > Gradle).
In the Gradle tool window, click Tasks > Build then double-click Build.
Once the IDE has stopped processing that task, you will find a new APK in the
build/outputs/apk
folder.At this point you should be able run the application from the IDE or you can manually install the APK onto your device.
When the app starts up, you will want to tap the menu in the top right corner.
Select Credentials which will let you enter your merchant ID, user ID, etc.
Set Up Your App
You can use the sample app’s build.gradle
file as a starting point for your app. It is already configured to pull in the Commerce SDK libraries during build processing.
As part of your initial application setup, you will need to include the following permissions in your AndroidManifest.xml
file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- Only needed when using RP457c card reader audio connection -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
note
If you plan to support any of the Roam readers (RP457c, Moby/5500), then you also need the following permission to establish device pairing:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Some permissions are considered “dangerous” and need to be explicitly requested from the user at runtime. These are:
- READ_PHONE_STATE
- BLUETOOTH_SCAN
- BLUETOOTH_CONNECT
- ACCESS_FINE_LOCATION
- RECORD_AUDIO
You can check the sample app code to see how these permissions are requested.
Here is a high level overview of the steps necessary to perform a Credit Card Sale transaction. For more details, review the sample application.
note
The sample application is provided to help assist you on integrating Commerce SDK. It is not intended to be used to run production transactions. At times additional features may be exposed through the sample application that are not currently functional as these are associated with potential future enhancements to the product. Please refer to the transaction pages for the supported functionality for each transaction type.
Initialize the Commerce Android module and check for errors.
ECCError error = ECLCommerceAndroid.initialize(getApplication()); if (error instanceof ECLCommerceError) { ... }
Implement the
ECLAccountListener
interface.Refer to
AccountListenerFactory
for more information.The
ECLAccountListener
interface defines the methods where specific properties can be overridden for a gateway account. Depending on the backend server the application needs to communicate to, implement either theECLConvergeAccountListener
orECLCreditCallAccountListener
interface.class AccountListenerFactory { static ECLAccountListener create(final Context context, final MainActivity activity, final Handler handler) { ... return new ECLConvergeAccountListener() { @Override public Context getApplicationContext() { // do something - look in the sample app code for a concrete example } @Override public ECCSensitiveData getMerchantId(ECLAccountInterface account) { // returns your Converge account's merchant ID } @Override public ECCSensitiveData getUserId(ECLAccountInterface account) { // returns your Converge account's user ID } @Override public ECCSensitiveData getPin(ECLAccountInterface account) { // returns your Converge account's PIN } @Override public ECCSensitiveData getPartnerAppId(ECLAccountInterface account) { // returns your Converge account's partner app ID if you have one // this is optional and can be null } @Override public ECCSensitiveData getVendorId(ECLAccountInterface eclAccountInterface) { // returns your vendor ID } @Override public ECCSensitiveData getVendorAppName(ECLAccountInterface eclAccountInterface) { // returns your application name } @Override public ECCSensitiveData getVendorAppVersion(ECLAccountInterface eclAccountInterface) { // returns your application version } @Override public ECLProxyInfo getProxyInfo() { // do something - look in the sample app code for a concrete example } @Override public ECLPersistentSettingsInterface getPersistentSettings() { return new ECLPersistentSettingsInterface() { @Override public void saveSetting(String key, String value) { // do something - look in the sample app code for a concrete example } @Override public String retrieveSettingForKey(String key) { // do something - look in the sample app code for a concrete example } @Override public void clearSettingForKey(String key) { // do something - look in the sample app code for a concrete example } }; } @Override public void accountDidInitialize(ECLAccountInterface account) {
Once the account is initialized, you can override certain properties associated with it, like terminal language or US common debit preferences. You also have the chance to setup listeners for different events associated with the account, like get notifications when a key update occurs.
account.setUpdateKeysListener(new ECLUpdateKeysListener() { @Override public void updateKeysFailed(ECCError eccError) { // do something - look in the sample app code for a concrete example } @Override public void updateKeysCompleted() { // do something - look in the sample app code for a concrete example } @Override public void updateKeysProgress(ECLTransactionProgress eclTransactionProgress) { // do something - look in the sample app code for a concrete example } }); // set up listener to be notified when a scheduled reboot is about to occur - for V4 pin pads account.setCardReaderDailyRebootNotificationListener(new ECLCardReaderDailyRebootNotificationListener() { @Override public void cardReaderWillPerformDailyReboot(long millisUntilReboot) { // do something - look in the sample app code for a concrete example } });
The language used for transaction can be overridden. This applies to RBA pinpads only and will have no effect for other pinpads. This is completely optional. If not used, a possibly server supplied language preference info is going to be used. You can specify a pair of (language, country) to determine the language to be used on pinpad during a transaction. If the pair you supplied is not supported, the return value will indicate the language CSDK chose to use. This is determined to be the closest match to what you specified. Currently, Commerce SDK supports English in US and English and French in Canada.
ECLLanguageInformation desiredLanguage = ...; ECLLanguageInformation finalValue = account.overrideDefaultTerminalLanguage(desiredLanguage);
You can override the Commerce SDK setting for the debit network preference in the US. This applies to US RBA pinpads only and will have no effect for other pinpads. This is completely optional. If not used, a possibly server supplied value is going to be used. The possible choices are: global debit network, us common debit network or no preference at all, in which case the user will be asked to do the selection on the pinpad, if applicable. Be advised that in case of contactless transactions, the pinpad will not ask the user for a selection, but it will select the AID with the highest priority remaining after filtering them based on the setting. For example, if the choice is to use the global network and there are 2 global AIDs on the card, RBA will automatically select the one with the highest priority.
ECLDebitNetworkPreferences debitNetworkPreferences = ...; account.overrideDebitNetworkPreferences(debitNetworkPreferences); } @Override public void accountDidFailToInitialize(ECLAccountInterface account, ECCError error) { // do something - look in the sample app code for a concrete example } @Override public void accountDefaultCurrencyDidChange(ECLAccountInterface account, ECLCurrencyCode newCurrencyCode) { // do something - look in the sample app code for a concrete example } @Override public ECLServerType getServerType() { // do something - look in the sample app code for a concrete example } };
In 5.5, the following methods were added.
@Override public void certificateUpdateRequired(ECLCertificateInfo eclCertificateInfo) { // do something - look in the sample app code for a concrete example } @Override public ECCSensitiveDataInterface getBridgeMaintenanceSystemUsername(ECLAccountInterface eclAccountInterface) { // return the bmsUsername - each integrator will have unique BMS credentials - get them from your solution engineer } @Override public ECCSensitiveDataInterface getBridgeMaintenanceSystemPassword(ECLAccountInterface eclAccountInterface) { // return the bmsPassword - each integrator will have unique BMS credentials - get them from your solution engineer } @Override public void bridgeMaintenanceSystemFailure(ECCError eccError) { // BMS is the system used to get TMS updates. For example BMS provides updated certificates. // // WARNING WARNING WARNING // !!! Something went wrong when trying to communicate with BMS. !!! /// !!! If the failure is ECLAccountInvalidCredentials it MUST be addressed. !!! /// !!! Valid BMS credentials are required in order to keep certificates up to date. !!! /// !!! No transactions will be processed if connecting over IP without valid BMS credentials. !!! /// } @Override public void bridgeMaintenanceSystemSuccess() { // no need to do anything here } @Override public ECLProxyInfo getProxyInfo() { // do something if proxy info is needed - look in the sample app code for a concrete example }
Kickoff the gateway account initialization process.
handler = new AndroidHandler(new android.os.Handler(android.os.Looper.getMainLooper())); final ECLDispatcher dispatcher = new ECLDispatcher(handler); ECLAccountListener delegate = AccountListenerFactory.create(new deckard.content.android.AndroidContext(getApplicationContext()), this, handler); ECLCommerce.createAccount(delegate, dispatcher);
You will receive some callbacks on the delegate which will allow you to pass your credentials into Commerce SDK. Then you will receive another callback that will let you know whether the account initialization process was successful or not. Once the account has been initialized, you will get back an instance of
ECLAccountInterface
which is hereby referred to as account.Start a Sale transaction.
Create a money object representing $3.00.
ECLMoney amount = new ECLMoney(ECLCurrencyCode.USD, 300L);
Create a transaction interface.
ECLCurrencyTransactionInterface transaction = account.getTransactionProcessor().createSaleTransactionWithSubtotal(amount);
Create a card tender.
ECLCardTenderInterface tender = account.getTransactionProcessor().createCardTender();
Create a transaction listener so we can receive callbacks during transaction processing.
ECLTransactionProcessingListener transactionListener = new ECLTransactionProcessingListener() { @Override public void uponSearchingDevice(ECLConnectionMethod eclConnectionMethod) { // do something - look in the sample app code for a concrete example } @Override public void transactionDidComplete(ECLTransactionInterface transaction, ECLTenderInterface tender, final ECLTransactionOutcome outcome) { // do something - look in the sample app code for a concrete example } @Override public void transactionDidCancel(ECLTransactionInterface transaction, ECLTenderInterface tender) { // do something - look in the sample app code for a concrete example } @Override public void transactionDidFail(ECLTransactionInterface transaction, ECLTenderInterface tender, List<ECCError> errors) { // do something - look in the sample app code for a concrete example } @Override public void shouldProvideInformation(final ECLTransactionInterface transaction, final ECLTenderInterface tender, ECLTransactionRequirementsInterface transactionRequires, ECLTenderRequirementsInterface tenderRequires) { // We need more information to process the transaction! // During transaction processing, this callback may be executed one or more times for the purpose // of collecting more information to continue processing the transaction. // Look in the sample app code for a concrete example } @Override public void shouldSetCardReaderToUse(final ECLTransactionInterface transaction, final ECLTenderInterface tender, final List<String> cardReadersReadyForUse) { // Commerce detected more than one card reader so you need to let the user choose which one from the list should be used // Should this scenario arise, provide a mechanism to select the appropriate card reader. // Look in the sample app code for a concrete example } public void shouldSetCardReaderToUse(ECLTransactionInterface transaction, ECLTenderInterface tender) { // do something - look in the sample app code for a concrete example } @Override public void transactionProgress(final ECLTransactionProgress progress, final ECLTransactionInterface transaction, final ECLTenderInterface tender) { // Always good to know what is happening while the transaction is processing! // Use this callback to provide status information (i.e. "progress" messages) // Look in the sample app code for a concrete example } };
Now it is time to actually start processing the transaction.
account.getTransactionProcessor().processTransaction(transaction, tender, transactionListener);
Your
transactionListener
will receive various callbacks throughout the lifecycle of a transaction. At some point, you will receive atransactionDidCancel
,transactionDidFail
, ortransactionDidComplete
callback signaling the end of a transaction.
Client Certificate for IP Communication
POS must implement certificateUpdateRequired()
. In this method, POS should
store the certificate files
info_outlinenote
It is recommended to store the files in the application’s data directory.
upon connecting, supply information in connection criteria (see [doclink id=“device-connection-criteria” product=“commerce-sdk”]Device Connection Criteria[/doclink])
- supply certificate files using
setConnectionParameters()
. - supply client keystore date using
setClientKeyStoreDate()
.
- supply certificate files using
POS must implement connectWithUpdatedKeystoreInfo()
. In this method POS should
- call
ECLCardReaderInterface.connectWithUpdatedKeystoreInfo()
passing ECLConnectionParameters.
note
Before CSDK 5.6, when using RBASDKAdapter, POS should pass null as ECLConnectionParameters and the certificate files should be passed to RBASDKAdapter. See 5.5.0 sample app.
Starting from CSDK 5.6, CSDK can handle certificate files internally on Android as described above. This is recommended over using RBASDKAdapter in the POS application to handle certificate file streams.