Java (Android)
In this topic:
Device Requirements
- Minimum API level is 22 (platform version 5.1open_in_newLink opens new window)
- Gradle Plugin 4.4.2
- The target API the Commerce SDK sample application uses out of the box is 32 (platform version 12open_in_newLink 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 Android Studioopen_in_newLink opens new window.
Set Up the Environment
- Download and install the latest Oracle 1.8 32-bit JDKopen_in_newLink 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 Android Studioopen_in_newLink opens new window or IntelliJopen_in_newLink opens new window and the Android SDKopen_in_newLink 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 Android Developer Documentationopen_in_newLink 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 } }; } }
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
Commerce SDK integrators receive the following certificate files from Elavon:
Client_CERT.PEM
- Client CertificateClient_KEY.PEM
- Certificate’s Private KeyEntrust_G2.PEM
- Certificate Authority (used to create theClient_CERT.PEM
file)
Integrators must use these certificate files to create a BKS key store, which is required during application runtime.
To create a BKS key store file, complete these steps:
Download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7open_in_newLink opens new window from Oracle. Extract these policy files into your JRE’s security directory.
Convert a PEM certificate file and a private key to
PKCS#12
(.pfx .p12
) with the following command. You will then be prompted for a password. Make sure you remember this password as it will be used in the next step.openssl pkcs12 -export -out CLIENT.p12 -inkey CLIENT_KEY.PEM -in CLIENT_CERT.PEM -certfile Entrust_G2.PEM
Convert
.p12
to a Java Key Store file:keytool -importkeystore -deststorepass [password_from_the_previous_step] -destkeypass [password_from_the_previous_step] -destkeystore CLIENT.jks -srckeystore CLIENT.p12 -srcstoretype PKCS12 -srcstorepass [password_from_the_previous_step] -alias 1
Now we need to convert a
.jks
file to a.bks
file. To do that, you can download a tool named portecleopen_in_newLink opens new window, and run the tool with the following command:java -jar portecle.jar
In the program you should:
- Use File > Open Keystore File to navigate to your
CLIENT.jks
and open it. - Use Tools > Change Keystore Type > BKS to convert the key store to BKS format.
- Use File > Save Keystore to save your new
CLIENT_L1K.BKS
file to disk.
- Use File > Open Keystore File to navigate to your
Add
CLIENT_L1K.BKS
andEntrust_G2.PEM
as assets for your application.You can see an example in the Android sample application (
src/main/assets
).