Java (Android)

In this topic:

Device Requirements

  • Minimum API level is 22 (platform version 5.1Link 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 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 Android StudioLink opens new window.

Set Up the Environment

  1. Download and install the latest Oracle 1.8 32-bit JDKLink opens new window.
  2. Set the JAVA_HOME variable to point to the appropriate directory.
  3. Add JAVA_HOME\bin to your shell’s Path variable.
  4. Download and install either Android StudioLink opens new window or IntelliJLink opens new window and the Android SDKLink opens new window.
  5. Set the ANDROID_HOME variable to the appropriate directory.
  6. Configure your IDE to use the JDK and Android SDK as default platforms for new projects.

Refer to the Android Developer DocumentationLink opens new window for more information.

Build the Sample Application

  1. Unzip the sample app zip file. This example will assume you extracted the files into c:\sample-app.

  2. Open build.gradle and look for compileSdkVersion and buildToolsVersion. 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.
  3. Open your IDE and create a New project from Existing Sources.

  4. Navigate to c:\sample-app and select the build.gradle file. Click Ok to continue through the wizard.

  5. Once the IDE has stopped churning, open up the gradle tool window (View > Tool Windows > Gradle).

  6. In the Gradle tool window, click Tasks > Build then double-click Build.

  7. 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.

  8. When the app starts up, you will want to tap the menu in the top right corner.

  9. 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.

  1. Initialize the Commerce Android module and check for errors.

    ECCError error = ECLCommerceAndroid.initialize(getApplication());
    if (error instanceof ECLCommerceError)
    {
        ...
    }
    
  2. 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 the ECLConvergeAccountListener or ECLCreditCallAccountListener 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
                }
            };
        }
    }
    
  3. 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.

  4. 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 a transactionDidCancel, transactionDidFail, or transactionDidComplete 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 Certificate
  • Client_KEY.PEM - Certificate’s Private Key
  • Entrust_G2.PEM - Certificate Authority (used to create the Client_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:

  1. Download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7Link opens new window from Oracle. Extract these policy files into your JRE’s security directory.

  2. 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
    
  3. 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
    
  4. Now we need to convert a .jks file to a .bks file. To do that, you can download a tool named portecleLink 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.
  5. Add CLIENT_L1K.BKS and Entrust_G2.PEM as assets for your application.

    You can see an example in the Android sample application (src/main/assets).