Installation
Manual
Download the latest PCSDKModule.xcframework
and add it to the project.
CocoaPods
Add the following line to your Podfile:
pod 'PCSDKModule', :git => 'https://repo.paycontrol.org/git/ios/pcsdk.git'
Swift Package Manager
Select File
> Swift Packages
> Add Package Dependency...
and add a repository URL:
https://repo.paycontrol.org/git/ios/pcsdk.git
Carthage
Since Carthage does not support distribution of binary frameworks this integration way is not supported.
User registration
User registration process contains followings steps:
- Getting personalization data from the PC Server (via QR, QR + activation code, JSON-value)
- Registering PC User on PC Server
- Store user's keys in internal storage for futher using
The activation code could be delivered by other channel (SMS, Push Notifications)
// Checking json validity
guard PCSDK.analyzeQR(userJSON) == .user
else { ... }
// Importing JSON info
let user = try PCUsersManager.importUser(from: userJSON)
// Activating the user
if !user.isActivated {
try PCUsersManager.activate(user: user, using: activationCode)
}
// Registering
PCUsersManager.register(
user: user, // The improrted user
deviceToken: deviceToken // The device token for PUSH notifications
) { result in
switch result {
case .success: ...
case .failure(let error): ...
}
}
// Storing
try PCUsersManager.store(
user: user, // The imported user
name: storingName, // The friendly name to store user
password: storingPassword // The password to store
)
Transactions
Online
// Getting the apropriate user.
// We are using the first stored user in this example
guard let user = PCUsersManager.users.first
else { ... }
// Getting the available transactions list for this user
PCTransactionsManager.getTransactionList(
for: user) { result in
switch result {
case .success(let transactionsList): ...
case .failure(let error): ...
}
}
// Getting transaction's data
// We are using the first transaction in the list in this example
guard let firstTransactionID = transactionsList.first
else { ... }
PCTransactionsManager.getTranaction(
for: firstTransactionID,
user: user
) { result in
switch result {
case .success(let transaction): ...
case .failure(let error): ...
}
}
// Transaction may contain the binary data
// It is necessary to download it before confirming or declining
if transaction.hasBinaryData {
PCTransactionsManager.getTransactionBinaryData(
for: transaction,
user: user
) { result in
switch result {
case .success(let transaction): ...
case .failure(let error): ...
}
}
}
// Providing password before processing
if !user.isReadyToSign {
try PCUsersManager.submit(password: password, for: user)
}
// Confirming
PCTransactionsManager.sign(
transaction: transaction,
by: user
) { result in
switch result {
case .success: ...
case .failure(let error): ...
}
}
Offine
If a device is offline, then PC can calculate offline confirmation/declination code for a transaction.
In this case PC SDK can not get the transaction's data from PC Server, and you should use QR-code scanner to get the transaction's 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
let transactionQRValue = ...
// Validation the value
guard PCSDK.analyzeQR(userJSON) == .transaction
else { ... }
// Importing the QR-code value
let transaction = try PCTransactionsManager.importTransaction(from: transactionQRValue)
// Choosing the apropriate user to process tranaction
// The user and the transaction must have the identical systemID value
// We use the first apropriate user in this example
guard let user = PCUsersManager.first(where: { $0.systemID == transaction.systemID })
else { ... }
// Providing password before processing
if !user.isReadyToSign {
try PCUsersManager.submit(password: password, for: user)
}
// Confirming
let confirmation = try PCTransactionManager.signOffline(
transaction: transaction,
by: user
)
// Getting the code to confirm the transaction offline
let code = confirmation.confirmationCode
Logging
SDK has an option to use an external logger. The external logger must inherit the PCLoggerProtocol
protocol.
public protocol PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory)
func error(_ message: String, category: PCLoggingCategory)
func sensitive(_ message: String, category: PCLoggingCategory)
}
/// Example logger
final class MyLogger: PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory) {
...
}
func error(_ message: String, category: PCLoggingCategory) {
...
}
func sensitive(_ message: String, category: PCLoggingCategory) {
#if DEBUG
// Process sensitive information only in DEBUG mode to keep safe
// user's sensitive data, e.g. symmetric keys values, personal data etc.
...
#endif
}
}
After defining your logger, you must pass it to the method PCSDK.setLogger(...)
:
let myLogger = MyLogger()
// PCSDK.setLogLevels([.debug, .keys]) <- This should be removed from your code
PCSDK.setLogger(myLogger, options: [.debug, .sensitive])
After that, all messages will be sent to your logger.
Saving to file
There are no internal methods to persist logs in files in SDK. But you can adopt any third-party logger to PCLoggerProtocol
protocol.
E.g. you can use CocoaLumberjack. To use it, firstly, confgure CocoaLumberjack's file logger:
import CocoaLumberjack
import CocoaLumberjackSwift
...
let fileLogger = DDFileLogger()
fileLogger.logFileManager.maximumNumberOfLogFiles = 2 // Keeping only 2 files
fileLogger.maximumFileSize = 256 * 1024 // 256kb each one
fileLogger.rollingFrequency = 60 * 60 * 24 // with messages for last 24h
DDLog.add(fileLogger)
Now your logger should just translate messages to CocoaLumberjack's methods:
final class MyLogger: PCLoggerProtocol {
func debug(_ message: String, category: PCLoggingCategory) {
DDLogInfo("[SDK][\(category.rawValue)] \(message)")
}
func error(_ message: String, category: PCLoggingCategory) {
DDLogError("[SDK][\(category.rawValue)] \(message)")
}
func sensitive(_ message: String, category: PCLoggingCategory) {
#if DEBUG
DDLogInfo("[SDK][Sensitive][\(category.rawValue)] \(message)")
#endif
}
}
After that you will be able to get persisted logs using CocoaLumberjack`s API:
fileLogger
.logFileManager
.sortedLogFileInfos
.compactMap { (info: DDInfo) -> Data in
FileManager.default.contents(atPath: info.filePath) // Reading logs content
}
.forEach { (logData: Data) in
... // Process the log's data
}
An additional information about using CocoaLumberjack`s you can read at its GitHub page.
Using PCSDK In Extensions
To use PCSDK in extensions it necessarry to have the shared db and the same access group to the app and the extension.
To do that you must use App Groups and initialize the app and the extension in different ways.
The preparations for both the app and the extension
// Making the shared path to the DB
let appGroupIdentifier = ... // The App Group identifier
guard let sharedContainer = FileManager
.default
.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
else { ... }
let sharedDatabaseURL = sharedContainer.appendingPathComponent(PCSDK.defaultDatabaseFileName)
Initializing app
PCSDK.initialize(
databaseURL: sharedDatabaseURL,
accessGroup: appGroupIdentifier
)
Initializing Extension
let mainAppBundleIdenfifier = ... // Provide the main app's bundleIdenfifier
PCSDK.initialize(
databaseURL: sharedDatabaseURL,
accessGroup: appGroupIdentifier,
mode: .extension(mainAppBundleIdenfifier))
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 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.# PCSDK iOS
KYC
Description
KYC is a part of PC Platform which allows to perform remote identification in the mobile application based on verifying client's photos and/or videos alongside with their scanned documents. The remote identification is intended to be performed prior to issuing keys by the PC Server and personalizing the mobile application.
KYC extension interacts with eKYC Connector which receives data from the application and performs the analysis. Refer to this page to find out more about eKYC Connector and the general description of the KYC concept.
The KYC extension initiates a session with initial data (which may be delivered e.g. by QR code) and asks the KYC Connector about the required data for remote identification. The KYC Connector sends the list of necessary media files (which usually includes a short live video and a photo of the passport) and KYC extension, in turn, collects the required sources and sends them to the analysis. After the KYC Connector has verified that the person in a video and on a passport photo is the same, it starts OCR procedure to retrieve the information from the passport. After OCR is done, the mobile application receives a notification, so that the client can confirm that all the fields in the password have been recognized properly. After performing a successful OCR procedure, the KYC Extension requests the list of available options for verifying documents. The client is supposed to choose a preferable way to get ther documents verified. Once verification method is defined, KYC Connector sends the documents for verification and notifies the application about results. Upon a successful verification, the KYC Extension requests the keys from the Connector and the app may be personalized with a retrieved PCUser
.
Installation
Manual
Download the latest PCKYCModule.xcframework
and add it to the project.
CocoaPods
Add the following line to your Podfile:
pod 'PCKYCModule', :git => 'https://repo.paycontrol.org/git/ios/kyc.git'
Swift Package Manager
Select File
> Swift Packages
> Add Package Dependency...
and add a repository URL:
https://repo.paycontrol.org/git/ios/kyc.git
Carthage
Since Carthage does not support distribution of binary frameworks this integration way is not supported.
Usage
Classes overview
While using KYC Extension in your app, you are going to interact with the following objects:
PCKYCSession
- Struct which represents a separate session established with KYC Connector.PCKYCManager
- Struct which manages your sessions. The follwoing guide is primarily devoted to showing proper usage of this class.PCKYCError
- Enum which represents errors.
Step 1. Add logging
To receive logs from this framework you should set the PCKYCManager.externalLogger
parameter. See Logging section for the example of PCLoggerProtocol
realisation.
Step 2. Create a session
To start a session, you call PCKYCManager.startSession()
method.
PCKYCManager.startSession(
kycInfoJSON: jsonValue, // The JSON string with KYC connector's data
deviceToken: deviceToken, // Device token to receive push notifications
completion: { result in
switch result {
case let .success(newSession): ... // Successfuly created session
case let .failure(error): ... // Error
}
}
)
Step 3. Get required sources
The first thing to do with a just created session is to determine which types of sources the client will be asked to upload.
// You may get required sources from `session` instance
let requiredSources: Set<PCKYCMediaType> = session.requiredSources
// ... or calling the PCKYCManager's method
PCKYCManager.getRequiredSources(
session: session, // The session instance
completion: { result in
switch result {
case let .success(sources): ... // Sources
case let .failure(error): ... // Error
}
}
)
Then you should prepare required sources: capture videos, take photos, etc. See the list of available sources.
Step 4. Upload the collected sources
Once the media files are collected, they must be uploaded for analysis.
// Uploading media from url
PCKYCManager.uploadMedia(
mediaURL: url, // URL to media file (e.g. video)
type: mediaType, // The type of the uploading media
session: session, // The session instance
completion: { result in
switch result {
case .success: ... // Done
case let .failure(error): ... // Error
}
)
// Uploading media from data
PCKYCManager.uploadMedia(
data: data, // Binary data of media (e.g. photo)
extension: "jpg", // The extension of the media, e.g. "jpg"
type: mediaType, // The type of the uploading media
session: session, // The session instance
completion: { result in
switch result {
case .success: ... // Done
case let .failure(error): ... // Error
}
)
Step 5. Check the session status
In your app, you are supposed to check the session status from time to time so as that you are able to handle any changes with the session.
To learn about possible session statuses, refer to the API documentation on PCKYCSession​Status.​Status.
PCKYCManager.getSessionStatus(
session: session, // The session instance
completion: { result in
switch result {
case let .success(status): ... // Session status
case let .failure(error): ... // Error
}
)
Step 6. Download OCR results
After uploading required media files, the KYC connector will perform the analysis. Once, the analysis is successful, you will receive the status .ocrSuccess
which means, your passport has been scanned successfully. You are supposed to download scanning results and show it to a client so that they can confirm the correctness of the OCR results.
PCKYCManager.getOCRResults(
session: session, // The session instance
completion: { result in
switch result {
case let .success(orcResults): ... // OCR results [String: Any]
case let .failure(error): ... // Error
}
)
Normally, the result dictionary contains keys with data from the passport: name
, dateofbirth
, sex
, address
, number
, dateofissue
, placeofissue
, issuecode
.
Step 7. Approve OCR results
After the client has checked the OCR results, their validity must be approved by the application. To approve the OCR results, just call KYCManager.approveOCRResults(session:completion:)
.
In case the OCR results are invalid, you have to provide an opportunity for a client to notify the KYC Connector about the problem. Call KYCManager.declineOCRResults(session:completion:)
In some cases it is possible that the OCR fails (e.g., the quality of uploaded photo was poor). Then instead of .ocrSuccess
the session will come to .ocrFailed
. It is also possible that the client rejects OCR results and the session gets its .ocrRejectedByUser
status. Your application may behave the same way in both cases: it can restart an OCR procedure. To do this, you must call KYCManager.getRequiredSources(session:completion:)
to see which pages of the passport must be uploaded again. Then call KYCManager.uploadMedia(...)
to resend required photos.
Step 8. Verify documents validity
Once, the OCR results have been approved by the client, the session status turns to .ocrApprovedByUser
. The next step is to get documents verified by government authorities. The KYC Connector can support several ways of documents verification. To find out which ways can be applied, KYCManager.getVerifiers(session:completion:)
should be called. The method returns the list of available verifiers in a callback.
After getting the list of supported verifiers you should provide the opportunity to choose the most suitable verifier for your clients. Refer to documentation on KYC Connector to learn more about each verifier.
The following code snippet shows how to start documents verification with a particular verifier:
PCKYCManager.startAstralPlatformValidation(
session: session, // The session instance
completion: { result in
switch result {
case .success: ... // Validation started
case let .failure(error): ... // Error
}
)
Step 9. Obtain your keys
Once the documents verification has started you should wait until the session reaches status of .pcKeyReady
. This means, the PC symmetric keys have been issued and you can register them on a device. This is a final step. As a result, you receive PCUser
object and pass it to PCUsersManager
for further processing.
PCKYCManager.getPCUser(
session: session, // The session instance
completion: { result in
switch result {
case let .success(user): ... // User to register
case let .failure(error): ... // Error
}
)
See Registration to learn about further actions with PCUser
object.
Changelog
5.3.426
Version 5.3. External keys processors, new events, fixes and improvements
- Added methods to process multiple transactions at once:
PCTransactionManager.sign(transactions:user:completion)
andPCTransactionManager.decline(transactions:user:completion)
- Sync methods
PCTransactionManager.signOffline
andPCTransactionManager.declineOffline
have been marked as deprecated. Added new async methods. - Refactored internal architecture to support external keys processors via
KeysProcessor
protocol. PCKYCManager
has been extracted to the separate framework- Added new events (
password_correct
andpassword_changed
) - Removed deeplinks from sdk
- Updated dependencies
- Other minor fixes and improvements
5.2.414
Supporting of Server API v4 has been added:
- Operations have been added. Operation is generally a bunch of related transactions which can be processed altogether. Refer to documentation on PCOperationsManager and PCOperation for more details.
- eKYC module has been added. This module provides functionality for remote identification which can be used as a preliminary step before issuing the keys. Refer to documentation on PCKYCManager and PCKYCSession for more details.
- Key backups have been added. Now, the key can be backed up and restored later (provided that the server supports this functionality and backups are enabled). Refer to documentation on PCUserBackupData and PCUserRestore for more details.
- Calculation of signature has been extended for CMS, CSR and standard types
- Parameters
type
andcmsAuthenticatedAttributes
have been added toPCTransaction
PCUsersManager.getCertificateInfo
method has been added. The transaction type property has been added. Tests has been added.- A
snippet
parameter has been added toPCTransaction
- The
suggestedUserName
property has been added toPCUser
Other improvements:
- Now you can attach external logger to SDK using PCSDK.setLogger
method.
- Stream-based confirming, declining and autosigning have been implemented
- Downloading binary data to file has been implemented
- Errors list has been updated
- Target queue has been added to async methods
- Other internal optimisations, fixes and improvements have been added