Netcetera Android 3DS SDK Demo Application

This section describes the Netcetera Android 3DS SDK Demo Application.

Netcetera Android 3DS SDK Demo Application

This documentation provides details about the use of the Netcetera Android 3DS SDK Demo Application and sample how the Netcetera Android 3DS SDK can be integrated.

Requestor Application

The Netcetera Android 3DS SDK Demo Application represents an example integration of the Netcetera Android 3DS SDK. Along with this documentation, it serves as a guide for an easier integration of the Netcetera Android 3DS SDK in an application or a library.

The demo application simulates a real life payment action. It contains all cases from the frictionless and the challenge flows.

When the application is started, the initial screen is the payment details screen. Depending on the selected scenario, the application will present the appropriate flow.

For presenting the integration steps in proper order, the Netcetera Android 3DS SDK Demo Application is configured to work with Netcetera requestor backend which is an internal component and not available with 3DS SDK product. The communication protocol between the merchant application and the PSP is proprietary for that particular PSP backend only and out of the scope for our Netcetera 3DS SDK products.

Appropriate adjustments to the application shall be made in order for the application to work and to perform transactions.

App architecture

Regarding the app architecture, the NCA demo application implements simplified version of MVVM pattern. It uses an Activity for the View, a viewmodel that contains the screen logic, and use cases (model) that contain the business logic about the use of the SDK. The application folder structure is organised by features and screen types.

Example structure of a screen implementation, the src/main/.../splash folder contains the following files:

  • SplashActivity.java - contains the view logic of the splash screen.
  • SplashViewModel.java - contains the splash screen logic for interacting between the view and use cases

Example structure of use case, the src/main/.../initialization folder contains the following files:

  • ThreeDSInitialization.java - use case for initialization of ThreeDS2Service
  • InitializationCallback.java - callback for the result of ThreeDSInitialization

The same structure is followed for the other screen implementations and use cases.

Intended to be used by different use cases, the Android SDK demo application uses ThreeDS2Service as singleton instance in a dagger module.

1
2
3
4
5
6
7
8
9
10
@Module
public class ThreeDS2Module {
  //...
  @Singleton
  @Provides
  ThreeDS2Service getThreeDS2Service() {
    return ThreeDS2ServiceInstance.get();
  }
  //...
}

The creation of the transaction in the Android SDK Demo Application is performed by tapping on the submit button. The pre-defined scenarios of the frictionless and challenge flows can be found in TransactionModelsRepository. By selecting a scenario in PrefillDataActivity, you select the example which will be shown once you tap on submit.

The authentication request is created in DsAuthenticationRequestBuilder. Depending on the response received from the server, the application decides whether or not to opt for a challenge. An example implementation of the authentication request can be found in DsAuthenticationUseCase, while the method which calls this request is located in CheckoutViewModel.

SDK Usage

The Netcetera Android 3DS SDK is initialized by invoking ThreeDSInitialization in the SplashActivity at the start of the Netcetera 3DS Android Demo Application. For the initialization to be successful, the Netcetera Android 3DS SDK needs to be configured with a valid DS Configuration and a valid licence key. Here is how this is done in the demo application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Simplified version of what is in the Netcetera demo application
@Override
public void initialize(Context context, InitializationCallback callback) {
  try {
    threeDS2Service.initialize(context, getConfigParameters(), getLocale(context), getUiCustomization());
    callback.onInitialized(threeDS2Service.getWarnings());
  } catch(SDKAlreadyInitializedException | InvalidInputException | SDKRuntimeException e) {
    callback.onInitializationFailed(e);
  }
}
 
private String getLocale(Context context) {
  Locale defaultLocale = context.getResources().getConfiguration().locale;
  String language = defaultLocale.getLanguage();
  String country = defaultLocale.getCountry();
  return language + "-" + country;
}
 
private UiCustomization getUiCustomization() {
  return new UiCustomization();
}
 
private ConfigParameters getConfigParameters() {
  return new ConfigurationBuilder().license("sample license").build();
}

Once the SDK has been initialized, you can access the warnings generated during the initialization. This is done by calling the ThreeDS2Service.getWarnings() method. In the example above, the warnings are returned on the initialization callback, but you can ask for them anytime as long as the underlying ThreeDS2Service is initialized.

The creation of transaction and sending of the Authentication Request is performed by tapping on the submit button on the checkout screen. This logic can be found in CheckoutViewModel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void submitTransaction(Activity activity, TransactionModel transactionModel) {
  final String dsId;
    try {
      dsId = dsIdMatcher.directoryServerIdForCard(activity, transactionModel.getAccountNumber());
    } catch (InvalidCardNumber e) {
      _invalidCardNumberEvent.postValue(e.getMessage());
      return;
    }
 
    requestStartTime = System.currentTimeMillis();
 
    Transaction transaction = threeDS2Service.createTransaction(dsId, settingsManager.getMessageVersion());
    AuthenticationRequestParameters authenticationRequestParameters = transaction.getAuthenticationRequestParameters();
 
    _transactionStartedEvent.postValue(transaction.getProgressView(activity));
 
    dsAuthenticationUseCase.authenticate(transactionModel, authenticationRequestParameters,
      new DsAuthenticationUseCase.AuthenticationCallback() {
        @Override
        public void onAuthenticated(AuthenticationResponse authenticationResponse) {
          handleResponseWithDelay(transaction, authenticationResponse);
        }
 
        @Override
        public void onAuthenticationFailed(Throwable throwable) {
          logger.warn("Failed AuthenticationRequest.", throwable);
          _transactionFailureEvent.postValue(throwable.getMessage());
        }
      }
    );
}

App URL

Starting with version 2.2.0 of the EMV 3DS Specification Protocol, the application integrating the 3DS SDK can be called (brought to foreground) from another (authentication) application during an OOB challenge flow to indicate completed OOB authentication. The Netcetera demo application provides sample implementation of this feature summarized bellow.

The activity that calls the challenge flow must be open for calls from an outside application for a specific uri - app url. Moreover, this activity should act as a “singleton” so that the instance holding the ongoing challenge flow is brought to foreground (singleTask) instead of launching new activity instance.

1
2
3
4
5
6
7
8
9
10
11
12
13
<activity
        android:name=".screens.checkout.CheckoutActivity"
        android:launchMode="singleTask">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="http"
              android:host="requestor.netcetera.com"/>
        <data android:scheme="https"
              android:host="requestor.netcetera.com"/>
    </intent-filter>
</activity>

Next, this activity needs to update its current intent when new intent is received in order for the Netcetera Android 3DS SDK to detect that it was brought to foreground from another application using the provided app url.

1
2
3
4
5
@Override
protected void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
  setIntent(intent);
}

Finally, the application sets the correct app url for the ongoing transaction in the challenge parameters ChallengeParameters.setThreeDSRequestorAppURL(String threeDSRequestorAppURL) used for starting the challenge. The threeDSRequestorAppURL value consists of the scheme and host values declared in the activity manifest configuration and a query parameter transID with the value of the SDK Transaction ID (AuthenticationRequestParameters.getSDKTransactionID()) of the ongoing Transaction. Therefore, considering the aforementioned activity manifest configuration, for a Transaction having SDK Transaction ID of “3800cde2-bba6-11ea-b3de-0242ac130004”, the threeDSRequestorAppURL would be equal to https://requestor.netcetera.com?transID=3800cde2-bba6-11ea-b3de-0242ac130004

Proguard configuration

The release build type of the Netcetera Demo Application has set minifyEnabled to true, meaning that during the release task, the source code of the application and its dependencies will go through optimization and obfuscation.

For better tuning which parts of the code are to be optimise and obfuscated, Proguard is used.

Proguard is taken as example configuration as most common measure of simple protection of a given application or library. The same approach should be used when using other similar tools.

Configuration Proguard files

The app/build-resources/proguard-files folder of the Netcetera Demo Merchant application, contains Proguard configuration files that are needed in order the Netcetera Android 3DS SDK to function as expected. One thing to note is that this configuration files are just an example that work for the Netcetera Demo Merchant application and may be further optimized or may not even work in a different integration environment.

The configuration for the Netcetera Android 3DS SDK is included as part of this folder as netcetera-3ds-sdk-rules.pro.

There is a separate configuration for the dependencies of the SDK that require configuration:

  • bouncycastle-rules.pro
  • logger-rules.pro

The dependencies that are embedded in the SDK do not require any configuration.

Proguard Gradle setup

In the build.gradle these configurations shall be listed in order to be taken into consideration one code optimization is performed. Please note that additional proguard configurations are added for dependencies used in the demo app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildTypes {
  release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
      'build-resources/proguard-rules/proguard-rules.pro',
      'build-resources/proguard-rules/netcetera-3ds-sdk-rules.pro',
      'build-resources/proguard-rules/bouncycastle-rules.pro',
      'build-resources/proguard-rules/okhttp-rules.pro',
      'build-resources/proguard-rules/gson-rules.pro',
      'build-resources/proguard-rules/okio-rules.pro',
      'build-resources/proguard-rules/retrofit-rules.pro',
      'build-resources/proguard-rules/logger-rules.pro'
  }
}

Logging

As the Netcetera Android 3DS SDK uses SLF4J for logging purposes, one simple configuration is to use SLF4J implementation that is using the Android Logcat. Additionally by providing different configurations for release and debug build type, logging in debug and release builds can be on different level.

Adding logback-android as dependency

To achieve this, first add logback-android logging framework as dependency in build.gradle:

1
2
3
4
5
dependencies {
  compile 'org.slf4j:slf4j-api:1.7.25'
  compile 'com.github.tony19:logback-android:1.3.0-3'
}

The configuration of logback-android is done via adding logback.xml configuration in the assets directory.

Example Debug configuration for logback-android

Sample configuration for debug builds that usually will be placed in src/debug/assets/. It will log Netcetera Android 3DS SDK info level and above in Android Logcat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<configuration>
  <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>
 
  <!-- Write Netcetera Android 3DS SDK WARN (and higher-level) messages to the logcat -->
  <logger name="com.netcetera.threeds.sdk" level="WARN"/>
 
  <!-- Write global WARN (and higher-level) messages to the logcat -->
  <root level="WARN">
    <appender-ref ref="LOGCAT"/>
  </root>
</configuration>

Example Release configuration for logback-android

Sample configuration for release builds that usually will be placed in src/release/assets/. It will not log any Netcetera Android 3DS SDK in Android Logcat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<configuration>
  <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>
 
  <!-- Don't write any messages from the Netcetera Android 3DS SDK to logcat -->
  <logger name="com.netcetera.threeds.sdk" level="OFF"/>
 
  <!-- Write global WARN (and higher-level) messages to the logcat -->
  <root level="WARN">
    <appender-ref ref="LOGCAT"/>
  </root>
</configuration>