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:
- Architecture and functionalty presentation
- Architecture and functionalty
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:
- add external maven repository to top-level gradle script
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
}
- add PC SDK to your project as dependency. Latest version can be discovered in the repository
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
andXcode 11+
is required.
- Download the latest version of the framework.
- Unzip archive and add
PCSDKModule.xcframework
into theProject 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:
- Get personalization data from the PC Server (via QR, QR + activation code, JSON-value)
see Architecture and functionality document - Register PC User on PC Server
during this process PC SDK will generate needed keys sets - 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.