NAV Navbar

Getting Started

There is Getting Started document for PC SDK for Mobile.
For better understand, how to work with PC, we recommend to read futher documents:

PC SDK for Mobile contains native libraries for Android and iOS operating systems.

These libriaries allows to implement all of PC functionality right in your mobile App.

Project Integration - Android

Add library to gradle-script

PC SDK library for Android can be integrated into your project as maven-dependency using SafeTech or Airome repository.

To add PC SDK you need to do following:

Sample of top-level build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()

        maven {
            url "https://repo.paycontrol.org/android/maven"
            credentials {
                username = "[get from safetech/airome]"
                password = "[get from safetech/airome]"
            }
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
    implementation 'tech.paycon.sdk.v5:pcsdk:<LATEST_VERSION>'

Android manifest

To use all of the features of PC SDK (like device data collection, device scoring, etc.) you should add permissions for your app in AndroidManifest.xml

<!-- to communicate via internet -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- to collect device location and translate it to PC Server -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- to collect SIM info and translate it to PC Server -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- to collect device network settings and translate it to PC Server -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- to get device name (like "Peter's phone") -->
<uses-permission android:name="android.permission.BLUETOOTH" />

<!-- if you use QR-code scanner -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>

Minification and obfuscation

If you use proguard or D8 for minification and obfuscation, then you should keep in mind that PC SDK uses Spongy Castle library as dependency.
To make this library work properly after minification you should add following rules to your proguard-rules file (for example, with name proguard-rules.pro)

-keep class org.spongycastle.** { *; }
-dontwarn org.spongycastle.**

Sample build config in your build.gradle will be like this

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        proguardFiles fileTree('proguard').asList().toArray()
    }
    debug {
        minifyEnabled false
        debuggable true
    }
}

Project Integration - iOS

Swift 5.2 and Xcode 11+ is required.

  1. Download the latest version of the framework.
  2. Unzip archive and add PCSDKModule.xcframework into the Project settings -> [App's target] -> Frameworks, Libraries, and Embedded Content section.

Base Scenarios

Initalization

To inialize PC SDK library you just need to create PCSDK class instance.
In Android you should call init(...) method.

If you need to set log level for PC SDK, then you sould call setLogLevel method and set log level.

Application MUST use one instance of PCSDK class during operating.
Initialization should be done at application startup.

User registration

User registration process contains followings steps:

  1. Get personalization data from the PC Server (via QR, QR + activation code, JSON-value)
    see Architecture and functionality document
  2. Register PC User on PC Server
    during this process PC SDK will generate needed keys sets
  3. Store user's keys in internal storage for futher using

Universal PC SDK functions calls will be following:


    // Create PCUser object from the source (QR or JSON value)
    if (scanQR_to_get_user_keys)
    {
        // **************
        // scan QR-code with app's QR scanner, get qrValue

        PCSDK.PCQRType qrType = PCSDK.analyzeQR(qrValue);
        if (PCSDK.PCQRType.PCUser != qrType)
            throw error;

        PCUser user = PCUsersManager.importUser(qrValue);
        if (null == user)
            throw error;

        // If there is activation code needed to use a key, then provide it
        if (!user.isActivated)
        {
            // **************
            // ask activation code from a user

            int activationResult = PCUsersManager.activate(user, activation_code);
            if (PC_ERROR_OK != activationResult)
                throw error;    // activation code invalid
        }
    }

    if (getJSON_with_user_keys)
    {
        PCUser user = PCUsersManager.importUser(jsonValue);
        if (null == user)
            throw error;

        // JSON always contains encrypted keys, so we need to decrypt them

        // **************
        // get exportPassword by app's rules
        // this password was used by app's server to export key

        int submitPasswordResult = PCUsersManager.submitPassword(user, exportPassword);
        if (PC_ERROR_OK != submitPasswordResult)
                throw error;    // exportPassword invalid
    }

    // ***************
    // Check App's permissions to collect device data (Android-only)

    // Ask phone data access
    if (user.isCollectSIMInfo())
    {
        // ask for READ_PHONE_STATE permissions
    }

    if (user.isCollectLocation())
    {
        // ask for ACCESS_COARSE_LOCATION permissions
    }

    // Register user's key on a PC Server, do not forget to handle errors
    PCUsersManager.register(...);

    // Determine protection method to store the PCUser object
    if (user.getPasswordPolicy() == 0)
    {
        // show button "Store without password" to a user
    }

    if (!user.isDenyStoreWithOSProtection())
    {
        // show button "Store with TouchID / FaceID / Fingerprint" to a user
    }

    // ***************
    // Ask protection method from a user

    switch (protectionMethod)
    {
        case WITHOUT_PASSWORD:
            storePassword = randomPassword();   // generate random password
            // storePassword should be stored in app's preferences for futher use
            break;
        case USE_PASSWORD:
            storePassword = askPasswordFromUser(); // in this case user should provide storePassword

            if (0 == user.getPasswordPolicy())
                userHint = "Password must contain at least 6 symbols";
            if (1 == user.getPasswordPolicy())
                userHint = "Password must contain at least 6 symbols";
            if (2 == user.getPasswordPolicy())
                userHint = "Password must contain at least 8 symbols, one upper case letter and one lower case letter";
            if (3 == user.getPasswordPolicy())
                userHint = "Password must contain at least 8 symbols, one digit, one upper case letter and one lower case letter";

            break;
        case USE_BIOMETRY:
            storePassword = randomPassword();   // generate random password
            // storePassword should be stored with OS protection (TouchID / FaceID / Fingerprint)
            break;
    }

    PCUsersManager.store(user, "to-store-friendly-name", storePassword);

If you as Application Developer knows all of the variants (for example, protectionMethod, password policy, if activation needed, user's data source), then this flow will be much more simplier.

Transaction Confirmation and Declination

Universal transaction Confirmation and Declination flow (for all of PCUsers in the storage) will be following

    List<PCUser> usersList = PCUsersManager.listStorage();

    // for each PCUser in the storage
    for (PCUser user: usersList)
    {
        // get user's transactions list to confirm
        String[] transactionsList = PCTransactionsManager.getTransactionList(user);

        // for each transaction in the list
        for (String transactionId: transactionsList)
        {
            PCTransaction transaction = PCTransactionsManager.getTransaction(user, transactionId);

            // ******************
            // show transaction data to a user
            //   transaction.getTransactionText()
            //   transaction.getBinaryData()

            // check if we can sign the transaction
            if (!user.isReadyToSign())
            {
                // ******************
                // ask storagePassword from a user
                // or extract if from OS (TouchID / FaceID / Fingerprint)
                // or use pre-defined value

                PCUsersManager.submitPassword(user, storagePassword);
            }

            if (userConfirmed)
                // confirm transaction
                PCTransactionsManager.sign(user, transaction);
            else
                // decline transaction
                PCTransactionsManager.decline(user, transaction);
        }
    }

Process Transaction by Push notification

PC Server can send push notification when transaction was created.
In this case Application can get User ID and Transaction ID from notification and process only one transaction.

The flow will be simplier, because of you do not need to process all of users and transactions.

Default push notification templates are following:

Default android push template (PC Server sends 2 push notifications)

{
 "to":"%DEVICE_TOKEN%",
 "notification":{
    "tag":"%USER_ID%",
    "title":"%PUSH_TITLE%",
    "body":"%PUSH_TEXT%",
    "icon":"pc_push",
    "sound":"default"
 },
 "data":{
    "type":"PayControl_v2"
 }
}

{
 "to":"%DEVICE_TOKEN%",
 "data":{
    "type":"PayControl_v2",
    "userid":"%USER_ID%",
    "transactionid":"%TRANSACTION_ID%"
 }
}

Default iOS push template

{
  "aps": {
    "alert": "%PUSH_TEXT%",
    "sound": "%PUSH_SOUND%",
    "badge": 1
  },
  "type": "PayControl",
  "userid": "%USER_ID%",
  "transactionid": "%TRANSACTION_ID%"
}

Please, be noticed, that push templates can be changed for your app by PC Server configuration.

Offine Confirmation and Declination

If a device is offline, then PC can calculate offline confirmation/declination code for a transaction.

In this case PC SDK can not get transaction data from PC Server, and you should use QR-code scanner to get transaction data.

Calculated confirmation/declination code should be provided to a user. The user will input this code manually into Application web-site. After this Application can verify it using PC Server API.

Flow will be following

    // **************
    // scan QR-code with app's QR scanner, get qrValue

    PCSDK.PCQRType qrType = PCSDK.analyzeQR(qrValue);
    if (PCSDK.PCQRType.PCTransaction != qrType)
        throw error;

    PCTransaction transaction = PCTransactionsManager.importTransaction(qrValue);

    // ******************
    // show transaction data to a user
    //   transaction.getTransactionText()

    PCUser toConfirmUser = null;
    List<PCUser> usersList = PCUsersManager.listStorage();
    // find PCUser object to confirm the transaction
    for (PCUser user: usersList)
    {
        if (user.getUserId().equalsIgnoreCase(transaction.getUserId())
        {
            toConfirmUser = user;
            break;
        }
    }

    if (null == toConfirmUser)
        throw error;

    // check if we can sign the transaction
    if (!toConfirmUser.isReadyToSign())
    {
        // ******************
        // ask storagePassword from a user
        // or extract if from OS (TouchID / FaceID / Fingerprint)
        // or use pre-defined value

        PCUsersManager.submitPassword(toConfirmUser, storagePassword);
    }

    if (userConfirmed)
    {
        // confirm transaction
        PCConfirmation confirmation = PCTransactionsManager.signOffline(toConfirmUser, transaction);

        // ******************
        // show confirmation code to a user
        //     confirmation.getShortConfirmCode()
    }
    else
    {
        // decline transaction
        PCDeclination declination = PCTransactionsManager.declineOffline(toConfirmUser, transaction);

        // ******************
        // show confirmation code to a user
        //     declination.getShortDeclineCode()
    }

Online and Offline transaction processing can be combined in the result scenarios.
sign and decline methods will return PCConfirmation and PCDeclination respectively in case of any error during PC Server interaction.