PingOneVerify iOS SDK provides a secure interface for an iOS app to use the PingOne Verify service for validating a user's identity. The SDK also parses the responses received from the service for different operations and forwards the same to the app via callbacks.
- Xcode 12 or greater
- iOS 13 or greater
The sample app cannot run on a simulator and works only on a device, because the app requires the camera to capture a selfie and the related user ID documents.
-
Ensure your Xcode is set up with a provisioning profile and a signing certificate to be able to install the app on a device. See the Apple Xcode document Run an app on a device for more information.
-
Clone or download the PingOne Verify SDK for iOS sample code to your computer and open
PingOneVerify.xcodeprojlocated in thePingOneVerify_iOSdirectory.
You will find all other XCFramework dependencies required for PingOne Verify in the PingOneVerify_iOS/common directory.
Also all common dependencies required for PingOne Verify in the PingOneVerify_iOS/common directory.
- To run the sample app, select the scheme
PingOneVerify_iOS--> , and click Run.
PingOneVerify iOS SDK provides a secure interface for an iOS app to use the PingOne Verify service for validating a user's identity. The SDK also parses the responses received from the service for different operations and forwards the same to the app via callbacks.
Add the dependencies needed for your application.
The PingOne Verify iOS SDK relies on XCFramework components. You'll need to add these to Xcode for use by your application.
-
Drag and drop the following components from the
SDK/Verifyfolder to the sectionFrameworks,Libraries, andEmbedded Contentin Xcode:-
PingOneVerify.xcframework
-
BlinkID.xcframework
-
NeoInterfaces.xcframework
-
LanguagePackProvider.xcframework
-
IDLiveFaceIAD.xcframework
-
IDLiveFaceDetection.xcframework
-
IDLiveFaceCamera.xcframework
-
GeoLocationProvider.xcframework
-
-
Right click from your project folder and select Add Files to (your project name).
When integrating both the Wallet SDK and Verify SDK into a single application, note that they share common dependencies located in the SDK/Common directory. These shared modules contain utilities and components required by both SDKs.
- If using only the Wallet SDK → include
Wallet/SDK/Common - If using only the Verify SDK → include
Verify/SDK/Common - If using both Wallet and Verify → include inly once instance of
SDK/Common(preferably fromWallet/SDK/Common)
** Wallet/SDK/Common & Verify/SDK/Common in your project**
Including multiple copies of SDK/Common can result in:
- Build time errors (e.g. duplicate symbols)
- Runtime crashes due to conflicting modules
- Increased binary size due to unnecessary duplication
- Add
import PingOneVerifyto the top of the Swift file where the SDK is initialized
- Import
PingOneVerify_iOSin your desired ViewController (It must extend UIViewController)
import PingOneVerify_iOS
- Extend DocumentSubmissionListener protocol and its functions
class YourViewController: UIViewController, DocumentSubmissionListener {
func onDocumentSubmitted(response: DocumentSubmissionResponse) {
// Callback when document is successfully submitted
}
func onSubmissionComplete(status: DocumentSubmissionStatus) {
// Callback when verification transaction is completed
}
func onSubmissionError(error: DocumentSubmissionError) {
// Callback when there is an error during submission
}
}
- Extend BackActionListener protocol and its functions
class YourViewController: UIViewController, BackActionListener {
func onBackAction(exitFlow: @escaping (Bool) -> Void) {
// Callback when user taps on back button
// Show alert if needed to confirm exit
// exitFlow(true) to exit the flow
// exitFlow(false) to stay in the flow
}
}
- Instantiate a
PingOneVerifyClient.Builderand set itslistener,BackActionHandlerandrootViewController(Required)
PingOneVerifyClient.Builder()
.setListener(self)
.setRootViewController(self)
.setBackActionHandler(self)
- Optionally, you can set an explicit qrString using the
PingOneVerifyClient.Builder
PingOneVerifyClient.Builder()
.setListener(self)
.setBackActionHandler(self)
.setRootViewController(self)
.setQrString(qrString: "https://api.pingone.com...")
- Start Verification Process
PingOneVerifyClient.Builder()
.setListener(self)
.setRootViewController(self)
.setBackActionHandler(self)
.startVerification { pingOneVerifyClient, clientBuilderError in
if let pingOneVerifyClient = pingOneVerifyClient {
// Handle pingOneVerifyClient
} else if let clientBuilderError = clientBuilderError {
// Handle builderError
}
}
-
onDocumentSubmitted(response: DocumentSubmissionResponse)- Called whenever a document is successfully submitted.
- Appropriate DocumentSubmissionResponse is returned
func onDocumentSubmitted(response: DocumentSubmissionResponse) {
print("The document status is \(response.documentStatus)")
print("The document submission status is \(response.documentSubmissionStatus)")
guard let documents = response.document else { return }
for (key, value) in documents {
print("\(key): \(value)")
}
}
-
onSubmissionComplete(status: DocumentSubmissionStatus)- Called when all required documents have been submitted for a transaction.
- DocumentSubmissionStatus will always be
.completed
func onSubmissionComplete(status: DocumentSubmissionStatus) {
// present a basic alert to indicate completion
let alertController = UIAlertController(title: "Document Submission Complete", message: "All documents have been successfully submitted", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default))
DispatchQueue.main.async {
self.present(alertController, animated: true)
}
}
-
onSubmissionError(error: DocumentSubmissionError)- Called when error occurs during SDK flow.
- Appropriate DocumentSubmissionError is returned
func onSubmissionError(error: DocumentSubmissionError) {
print(error.localizedDescription)
}
-
onBackAction(exitFlow: @escaping (Bool) -> Void)- Called whenever a user taps back.
- Return the exitFlow completion handler with
trueto exit the flow orfalseto stay in the flow.
func onBackAction(exitFlow: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: "Cancel Transaction", message: "Do you want to cancel this transaction?", preferredStyle: .alert)
let yesAction = UIAlertAction(title: "Yes", style: .destructive) { _ in
exitFlow(true)
}
let noAction = UIAlertAction(title: "No", style: .cancel) { _ in
exitFlow(false)
}
alertController.addAction(noAction)
alertController.addAction(yesAction)
self.presentedViewController?.present(alertController, animated: true)
}
}
DocumentSubmissionResponse object holds information pertaining to the document that was successfully submitted to the ID Verification service.
@objc public class DocumentSubmissionResponse: NSObject, Codable {
public var documentStatus: [String: DocumentStatus]
public var documentSubmissionStatus: DocumentSubmissionStatus
public var document: [String: String]
public var createdAt: String // Timestamp of when transaction was created
public var updatedAt: String // Timestamp of when transaction was last updated
public var expiresAt: String // Timestamp of when transaction expires
public func getDocumentStatus() -> [String: DocumentStatus]
public func getDocumentSubmissionStatus() -> DocumentSubmissionStatus
public func getDocument() -> [String: String]
public func getCreatedAt() -> String
public func getUpdatedAt() -> String
public func getExpiresAt() -> String
}
documentStatus dictionary shows the status of each document requested. For example, if the requested documents for a certain transaction are the following:
-
Email
-
Phone
-
Selfie
and the callback onDocumentSubmitted(response: DocumentSubmissionResponse was fired after submitting Email, the documentStatus property will look like this:
["Email": .PROCESSED, "Phone": .REQUIRED, "Selfie", .REQUIRED]
The list of DocumentStatus states can be found in DocumentStatus
documentSubmissionStatus property shows the status of the entire verification transaction. Detailed information regarding DocumentSubmissionStatus can be found in DocumentSubmissionStatus
document dictionary holds information about the document that was just submitted to the ID Verification service. Only applicable keys are populated in the document dictionary
Data model of document
| Key | Description |
|---|---|
frontImage |
Base64 encoded string of the front image of a document |
backImage |
Base64 encoded string of the back image of a document |
barcode |
Barcode Data found on the document |
mrzData |
MRZData found on passport and other relevant document |
firstName |
User's first name as shown on the document |
middleName |
User's middle name as shown on the document |
lastName |
User's last name as shown on the document |
fullName |
User's full name |
additionalNameInfo |
Additional name info about the user |
addressStreet |
User's street address as shown on the document |
addressCity |
User's residence city as shown on the document |
addressState |
User's residence state as shown on the document |
addressZip |
User's ZIP Code as shown on the document |
country |
User's residence country as shown on the document |
sex |
User's sex as shown on the document |
dateOfBirth |
User's date of birth as shown on the document |
placeOfBirth |
User's place of birth as shown on the document |
nationality |
User's nationality as shown on the document |
maritalStatus |
User's marital status as shown on the document |
race |
User's race as shown on the document |
religion |
User's religion as shown on the document |
residentialStatus |
User's residential status as shown on the document |
documentNumber |
Document number as shown on the document |
documentAdditionalNumber |
Additional document number as shown on the document |
personalIdNumber |
Personal Id number as shown on the document |
dateOfIssue |
Date of issuance of the document |
dateOfExpiry |
Date of expiration of the document |
issuingAuthority |
Issuing authority of the document |
employer |
Employer as shown on the document |
profession |
Profession as shown on the document |
An enum describing the status of a particular document
@objc public enum DocumentStatus {
case REQUIRED // document is required
case OPTIONAL // document is optional; user may choose to skip
case COLLECTED // document has been collected
case PROCESSED // document has been processed
case SKIPPED // document is skipped by user's choice
}
An enum describing the status of the verification transaction
@objc public enum DocumentSubmissionStatus {
case not_started // transaction has not been initiated
case started // transaction has been initiated, but not completed
case process // transcation is being processed
case completed // transaction has been processed and is completed
}
A configurable object to customize selfie capture experience
@objc public class SelfieCaptureSettings {
public let captureTime: TimeInterval // selfie capture time (default is 45 seconds)
public let shouldCaptureAfterTimeout: Bool // whether user should be able to capture selfie after timeout (default is true)
public var optional: Bool // whether user can decide to skip selfie capture (default is false)
}
ClientBuilderError is returned when PingOneVerify SDK is initialized incorrectly. It subclasses BuilderError and QRError and is returned during Builder.startVerification()
| Error | Description |
|---|---|
.missingRootViewController |
RootViewController was not set using .setRootViewController(viewController: UIViewController) in the builder |
.missingDocumentSubmissionListener |
DocumentSubmissionListener was not set using .setDocumentSubmissionListener(listener: DocumentSubmissionListener) in the builder |
| Error | Description |
|---|---|
.invalidQR |
Not a valid PingOne QR Code |
.unableToParse |
Unable to parse QR Code |
.missingQueryItems |
QR Code is missing important query items required to start transaction |
.missingVerificationCode |
QR Code is missing verification code |
.missingTransactionId |
QR Code is missing transactionId |
| Error | Description |
|---|---|
.initiateDocumentTransactionError |
Error when initiating a transaction |
.submissionError |
Error when submitting a document |
.noDocumentToSubmitError |
No more documents to submit |
.missingDocumentType |
Document type is missing |
.invalidKeyMap |
A valid key map for the document does not exist |
.documentCaptureError |
Error when capturing the data |
.documentSubmissionTimeoutError |
Document Submission has expired |
.missingOTPDestination |
OTP Destination is missing |
.failedOTP |
OTP failed with invalid code |
UIAppearanceSettings instance allows you to customize the SDK's user interface during run time.
@objc public class UIAppearanceSettings: NSObject {
private var logoImage: UIImage?
private var backgroundColor: UIColor?
private var bodyTextColor: UIColor?
private var headingTextColor: UIColor?
private var navigationBarColor: UIColor?
private var navigationBarTextColor: UIColor?
private var iconTintColor: UIColor?
private var solidButtonAppearance: ButtonAppearance?
private var borderedButtonAppearance: ButtonAppearance?
}| Method | Description |
|---|---|
setLogoImage(_ image: UIImage) -> UIAppearanceSetting |
Set logo image that is shown at the center of the navigation bar |
setBackgroundColor(_ color: UIColor) -> UIAppearanceSetting |
Set application background color |
setBodyTextColor(_ color: UIColor) -> UIAppearanceSetting |
Set body text color |
setHeadingTextColor(_ color: UIColor) -> UIAppearanceSetting |
Set heading text color |
setNavigationBarColor(_ color: UIColor) -> UIAppearanceSetting |
Set navigation bar background color |
setNavigationBarTextColor(_ color: UIColor) -> UIAppearanceSetting |
Set navigation bar text color |
setIconTintColor(_ color: UIColor) -> UIAppearanceSetting |
Set icon tint color |
setSolidButtonAppearance(_ buttonAppearance: ButtonAppearance) -> UIAppearanceSettings |
Set solid button appearance |
setBorderedButtonAppearance(_ buttonAppearance: ButtonAppearance) -> UIAppearanceSettings |
Set bordered button appearance |
setAttributedStrings(_ attributedStrings: [String: NSAttributedString]) -> UIAppearanceSettings |
Set attributed text for the app texts and customize it as per need. |
showSessionExpiresTimer(_ isTimerShown: Bool) -> UIAppearanceSettings |
Set visibility for session expiration timer |
setNavigationTitle(_ text: NSAttributedString) -> UIAppearanceSettings |
Set navigation bar title text |
Example usage:
private func getUiAppearanceSettings() -> UIAppearanceSettings {
let solidButtonAppearance = ButtonAppearance(backgroundColor: .red, textColor: .white, borderColor: .red)
let borderedButtonAppearance = ButtonAppearance(backgroundColor: .clear, textColor: .red, borderColor: .red)
let text = "Identity Verification"
let identityString = NSMutableAttributedString(
string: text,
attributes: [.font: UIFont.systemFont(ofSize: 18),
.foregroundColor: UIColor.purple]
)
var attributedStringDict: [String : NSAttributedString] = [:]
let clearText = "Is It Readable?"
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let clearAttributedString = NSMutableAttributedString(
string: clearText,
attributes: [.paragraphStyle: paragraphStyle,
.font: UIFont.systemFont(ofSize: 25),
.backgroundColor: UIColor.lightGray]
)
attributedStringDict["idv_data_check_clear"] = clearAttributedString
return UIAppearanceSettings()
.setSolidButtonAppearance(solidButtonAppearance)
.setBorderedButtonAppearance(borderedButtonAppearance)
.setAttributedStrings(attributedStringDict)
.showSessionExpiresTimer(false)
.setNavigationTitle(identityString)
}
override func viewDidLoad() {
super.viewDidLoad()
let uiAppearanceSetting = self.getUiAppearanceSettings()
PingOneVerifyClient.Builder(isOverridingAssets: false)
.setListener(self)
.setRootViewController(self)
.setUIAppearanceSetting(uiAppearanceSetting)
.startVerification { pingOneVerifyClient, clientBuilderError in
if let pingOneVerifyClient = pingOneVerifyClient {
// Handle pingOneVerifyClient
} else if let clientBuilderError = clientBuilderError {
// Handle builderError
}
}
}If using custom image resources, set PingOneVerifyClient.Builder(isOverridingAssets: Bool) to true. When the isOverridingAssets flag is true, the icon tint color is not applied to the custom images.
If PingOneVerifyClient.Builder(isOverridingAssets: Bool) is set to false, the icon tint color is automatically applied to all the icon images.
You can customize these images:
| Asset Name | Description |
|---|---|
| idv_logo | Logo image that appears at the center of the navigation bar |
| idv_gov_id | Image that is shown when government id is requested |
| idv_selfie | Image that is shown when selfie is requested |
| idv_phone | Image that is shown when phone number verification is requestede |
| idv_email | Image that is shown when email verification is requested |
| idv_cancel | mage that is used for cancel button at top left of the navigation bar |
To customize an image resource:
- Include your custom image with the same name in the app asset folder
You can customize the following color resources:
- navigation color
- button color
- button background color
- button text color
- button border color
- application background color
- heading text color
- body text color
To customize:
-
Pass a custom UIAppearanceSettings instance in the
PingOneVerifyClient.Builder. -
Use Branding from the PingOne platform API.
-
Use Branding & Themes tab found in PingOne Admin Console -> Experiences -> Branding & Themes as described in Branding and themes.
UIAppearanceSettings always has higher priority than Branding and themes.
Thus, if both UIAppearanceSettings and Branding and themes are used, the configuaration specified in UIAppearanceSettings is shown.
For localization and messages, you can replace the values found in PingOneVerifyLocalizable.strings.
You can customize items such as:
- logo
- navigation color
- button color
- button background
- button text
- application background
- heading text
- body text
To customize:
- Use Branding from the PingOne platform API.
- Use Branding & Themes tab found in PingOne Admin Console -> Experiences -> Branding & Themes as described in Branding and themes.
For Localization, use the Localizable.strings file to modify.
PingOne Verify Native SDK utilizes Verify Policies. You can apply policies two ways:
-
Use Verify Policies from the PingOne platform API.
-
Use Policies tab found in PingOne Admin Console -> PingOne Verify -> Policies to customize verify policy for a particular environment.