The PomeloCards iOS SDK makes it easy to build a card flows experience in your iOS App. This module provides powerfull customizable UI screens and flows that can be used by any client app to offer a complete cards flow to your customers.
- PomeloCards iOS SDK
- iOS 13+
- Xcode 11+
- Swift 5.1+
We support Cocoapods and Swift Package Manager. If you link the library manually, use a version from our releases page.
The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift
compiler.
To add the SDK in your project you just have to follow these steps:
-
In Xcode, select File > Swift Packages > Add Package Dependency and enter https://github.com/pomelo-la/cards-ios.git as the repository URL.
-
Select the latest version number from our releases page.
-
Add the PomeloCards product to the target of your app.
If you want to add the SDK as a dependency on your swift package follow the next steps:
Once you have your Swift package set up, adding PomeloCards as a dependency is as easy as adding it to the dependencies
value of your Package.swift
.
dependencies: [
.package(url: "git@github.com:pomelo-la/cards-ios.git", .upToNextMajor(from: "0.1.0"))
]
For details on the latest SDK release and past versions, see the Releases page on GitHub. To receive notifications when a new release is published, watch releases for the repository.
CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website.
To integrate PomeloCards into your Xcode project using CocoaPods you just have to:
-
If you haven’t already, install the latest version of Cocoapods.
-
Add our private spec repository to your CI/Local environment:
pod repo add pomelo-specs 'https://github.com/pomelo/Specs.git'
- If you don’t have an existing Podfile, run the following command to create one:
pod init
- Add our repo source at the top of your Podfile:
source 'https://github.com/pomelo/Specs.git'
- Last, just add the dependency to your app’s target.
target 'MyApp' do
pod 'PomeloCards', '~> 0.1.0'
end
- Don’t forget to use the .xcworkspace file to open your project in Xcode, instead of the .xcodeproj file, from here on out.
We recommend to use the opstimistic operator '~>' instead of not specify the version your going to use, to be sure that you are not going to update the version of our SDK to one that have a breaking change without testing it firts.
To initialize the SDK, first you have to setup the initial configuration on your SceneDelegate
.
let configuration = PomeloCardsConfiguration(environment: .development)
PomeloCards.initialize(with: configuration)
Parameters | |
---|---|
Environment: enum | Indicates the environment, which can be .development , staging or production |
You also have to setup the NSFaceIDUsageDescription
parametter on your Info.plist
. This is because we use the biometric prompt to be sure that the end users is actually the cardHolder.
Example:
<key>NSFaceIDUsageDescription</key>
<string>$(PRODUCT_NAME) uses Face ID to validate your identity</string>
You can use the message of your preference
Any company involved with the processing, transmission, or storage of card data, incluiding the primary account number (PAN), expiration date, and card verification value (CVV), must comply with the Payment Card Industry Data Security Standard (PCI DSS). Achieving PCI DSS certification is both time consuming and expensive.
Pomelo is fully PCI-Service Provider compliant and handles the unencrypted sensitive card data for you. Your servers never store, transmit, or process the card data.
The following process describes how Pomelo components work using the authorization service layer provided by your application to ensure that your end users have their sensitive data in a securely way.
Because of that you have to configure an authorization service injecting an AuthorizationService
that implements the protocol PomeloAuthorizationServiceProtocol
. On it you have to implement the logic to generate an end user token which is a short-lived JWT token that you have to provide to the SDK to be able to communicate with our secure data services.
We reccomend to encapsulate the logic of the end user token request on your back end services and only make a fetch to that service in your iOS native implementation of the
AuthorizationService
. For more information about the end user token, examples, and recomendations for backend implementation for it, please visit this page.
Once you have your AuthorizationService
fully developed you just have to configure it on your SceneDelegate
:
PomeloNetworkConfigurator.shared.configure(authorizationService: EndUserTokenAuthorizationService())
Go to this repo to see an example of an authorization service implemented on our demo app.
Having followed all the previous steps your SceneDelegate
configuration must be like:
import UIKit
import PomeloCards
import PomeloUI
import PomeloNetworking
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
setupPomeloCards()
}
private func setupPomeloCards() {
//Configure Cards SDK
PomeloCards.initialize(with: PomeloCardsConfiguration(environment: .develop))
//Configure authorization service on PomeloNetworkConfigurator
PomeloNetworkConfigurator.shared.configure(authorizationService: EndUserTokenAuthorizationService())
//Configure theme on PomeloUI
PomeloUIGateway.shared.configure(theme: YourTheme())
}
}
See the customizing section for more information about how to build your YourTheme
to customize the UI copmponents.
To use the SDK components and methos all you have to do is to add the import and you are ready to go.
import PomeloCards
// Put your implementation here!
Card image with sensitive data
class PomeloCardWidgetView: UIView
init(
cardholderName: String,
lastFourCardDigits: String,
imageFetcher: PomeloUIImageFetchable,
copyButtonIcon: UIImage? = UIImage(systemName: "doc.on.doc"),
fontTextColor: UIColor? = nil,
parentViewController: UIViewController? = nil
)
Initialize the widget with its content.
Parameters | |
---|---|
cardholderName: String | Card holder name. It will be shown as upper case. |
lastFourCardDigits: String | The last four digits of the card to be shown |
imageFetcher: UIImage? | (Optional) The background card image. The background is clear by default. |
copyButtonIcon: UIImage? | The copy data icon |
fontTextColor: UIColor? | (optional) the color of the font. You can select the font color but if you dont, the font its going to be white with dark background or black with lighter background automatically |
parentViewController: UIVIewController? | (Optional) The parent view controller that contains the cardView. If it is provided it will be used to display an alert with retry logic in case the service fails. |
func showSensitiveData(
cardId: String,
onPanCopy: (() -> Void)?,
completionHandler: @escaping (Result<Void, PomeloError>) -> Void
)
Reveals the hidden sensitive data from the card after passing successfully a biometric prompt.
Parameters | |
---|---|
cardId: String | The id of the card. Example _crd-ABCD1234_e |
onPanCopy: (() -> Void)? | Callback called when the user copied the card PAN number to the Pasteboard. It can be used to show an alert on your app |
completionHandler: @escaping (Result<Void, PomeloError>) -> Void | Callback called after Pomelo services request, it returns an error in case of fauilure, otherwise it succeded. |
List with sensitive data from the card.
class PomeloCardWidgetDetailViewController
You can display the card informations as a list and embed in your view just using the ViewController initializer as follows:
let widgetDetailViewController = PomeloCardWidgetDetailViewController()
Also can display the list as a bottomsheet using the extension displayViewControllerAsBottomSheet
from your parent view controller:
let widgetDetailViewController = PomeloCardWidgetDetailViewController()
yourParentViewController.displayViewControllerAsBottomSheet(widgetDetailViewController)
func showSensitiveData(
cardId: String,
onPanCopy: (() -> Void)?,
completionHandler: @escaping (Result<Void, PomeloError>) -> Void
)
Reveals the hidden sensitive data from the card after passing successfully a biometric prompt.
Parameters | |
---|---|
cardId: String | The id of the card. Example _crd-ABCD1234_e |
onPanCopy: (() -> Void)? | Callback called when the user copied the card PAN number to the Pasteboard. It can be used to show an alert on your app |
completionHandler: @escaping (Result<Void, PomeloError>) -> Void | Callback called after Pomelo services request, it returns an error in case of fauilure, otherwise it succeded. |
Activates a new card after completing the PAN and PIN.
init(completionHandler: @escaping (Result<String?, PomeloError>) -> Void)
Initialize the widget with its content.
Parameters | |
---|---|
completionHandler: @escaping (Result<String?, PomeloError>) -> Void | Callback called after the activation, it returns the card id if succeeded or an error in case of failure. |
Updates the PIN number.
init(
cardId: String,
completionHandler: @escaping (Result<Void, PomeloError>) -> Void
)
Initialize the widget with its content.
Parameters | |
---|---|
cardId: String | The id of the card to activate |
completionHandler: @escaping (Result<Void, PomeloError>) -> Void | Callback called after the change pin request, it returns an error in case of failure otherwise it succeded |
You can customize the appearance of the UI components by using the PomeloTheme object. This object allows you to change colors, button styles, fonts, feedback icons and cards background images.
We show you a custom PomeloTheme bellow:
class YourTheme: PomeloThemeable {
var colors: PomeloColors = PomeloColors(primary: .primaryColor,
secondary: .secondaryColor,
background: .backgroundColor)
var buttons: PomeloButtonsStyle = PomeloButtonsStyle(
primary: .init(
cornerRadius: 10,
enabledStyle: .init(backgroundColor: .primaryColor, foregroundColor: .white),
disabledStyle: .init(backgroundColor: .systemGray6, foregroundColor: .systemGray3)
),
secondary: .init(
cornerRadius: 10,
enabledStyle: .init(backgroundColor: .secondaryColor, foregroundColor: .primaryColor),
disabledStyle: .init(backgroundColor: .systemGray6, foregroundColor: .systemGray3)
),
tertiary: .init(
cornerRadius: 10,
enabledStyle: .init(backgroundColor: .clear, foregroundColor: .primaryColor),
disabledStyle: .init(backgroundColor: .clear, foregroundColor: .systemGray3)
),
link: .init(
cornerRadius: 10,
enabledStyle: .init(backgroundColor: .clear, foregroundColor: .primaryColor),
disabledStyle: .init(backgroundColor: .clear, foregroundColor: .systemGray3)
)
)
var feedbacks: PomeloFeedback?
var text: PomeloTextStyle? = .init(textColor: .label,
font: nil)
}
private extension UIColor {
static var primaryColor: UIColor {
return UIColor{ (traitCollection) -> UIColor in
return traitCollection.userInterfaceStyle == .light ? UIColor(red: 0.30, green: 0.21, blue: 0.46, alpha: 1.00) : UIColor(red: 0.30, green: 0.21, blue: 0.46, alpha: 0.75)
}
}
static var secondaryColor: UIColor {
return UIColor{ (traitCollection) -> UIColor in
return traitCollection.userInterfaceStyle == .light ? UIColor(red: 0.47, green: 0.35, blue: 0.65, alpha: 1.00) : UIColor(red: 0.47, green: 0.35, blue: 0.65, alpha: 0.75)
}
}
static var backgroundColor: UIColor {
.systemBackground
}
static var buttonBackgroundColor: UIColor {
.primaryColor
}
static var butttonForegroundColor: UIColor {
.white
}
static var disabledButtonBackgroundColor: UIColor {
.systemGray6
}
static var disabledButtonForegroundColor: UIColor {
.systemGray3
}
}
With this theme your componets will looks like this card activation widget:
Dark mode: Every component of the SDK supports darkmode, you only have to set UIColors that support thios feature to build your custom
PomeloTheme
and every component will change it's color when the device configuration change.
For more information about how to use these component customization features you can go to Pomelo UI iOS docs.
Now the SDK supports Spanish, Portuguese and English as preferred lanmguages. The user just have to select their preference language and the componebnts will show all the content in that language.