FramesIos alternatives and similar libraries
Based on the "Payments" category.
Alternatively, view FramesIos alternatives based on common mentions on social networks and blogs.
-
SwiftyStoreKit
Lightweight In App Purchases Swift framework for iOS 8.0+, tvOS 9.0+ and macOS 10.10+ ⛺ -
RevenueCat
In-app purchases and subscriptions made easy. Support for iOS, watchOS, tvOS, macOS, and visionOS. -
CreditCardForm-iOS
CreditCardForm is iOS framework that allows developers to create the UI which replicates an actual Credit Card. -
monza
Ruby Gem for Rails - Easy iTunes In-App Purchase Receipt validation, including auto-renewable subscriptions -
Glassfy
DISCONTINUED. Open source SDK to quickly integrate subscriptions, stop worring about code maintenance, and getting advanced real-time data. Full support for iOS, iPadOS, WatchOS, MacOS
InfluxDB - Purpose built for real-time analytics at any scale.
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of FramesIos or a related project?
README
Frames iOS
Requirements
- iOS 12.0+
- Xcode 12.4+
- Swift 5.3+
Documentation
Frames for iOS tokenises consumer data for use within Checkout.com's payment infrastructure. We want to abstract all the complexity in taking payments and building a payment screen from your Mobile Application and allow you to focus on your core business.
Integration: a guide for consuming our SDK in your iOS app
Demo projects: We've created projects showcasing the range of functionality available in our SDKs while testing each distribution method offered
Get started: Start testing what you can achieve by presenting inside your Applications UI
Make it your own: Customising the UI to become a part of your app
Other features: How we help with Apple Pay & 3D Secure Challenges
Migrating: If you have used 3.5.x version before
Complete information will be found in the Checkout Docs.
You can find the Frames API reference on our Jazzy docs.
Integration
We've done our best to support the most common distribution methods on iOS for you. We are in strong favour of SPM (Swift Package Manager) but if for any reason this doesn't work for you, we're also supporting Cocoapods and Carthage.
Swift Package Manager
Swift Package Manager integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies. It should work out of the box on latest Xcode projects since Xcode 11 and has had a lot of community support, seeing huge adoption over the recent years. This makes it our favourite distribution method and the easiest one to integrate, keep updated and build around.
If you've never used it before, get started with Apple's step by step guide into adding package dependencies to your app and we'll boost your project in no time! Just use this repository's URL (https://github.com/checkout/frames-ios) when adding dependency.
CocoaPods
CocoaPods is the traditional dependency manager for Apple projects. Still supported but not always able to validate all its peculiar ways.
Make sure cocoapods is installed on your machine by running
$ pod --version
Any version newer than 1.10.0 is a good sign. If not installed, or unsupported, follow Cocoapods Getting Started
Once Cocoapods of a valid version is on your machine, to integrate Frames into your Xcode project, update your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
use_frameworks!
target '<Your Target Name>' do
pod 'Frames', '~> 4'
end
Then, run the following command in terminal:
$ pod install
To update your existing Cocoapod dependencies, use:
$ pod update
Carthage
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
If you haven't already, install Carthage
To integrate Frames into your Xcode project using Carthage, specify it in your Cartfile
:
github "checkout/frames-ios" ~> 4.0
Run carthage update --use-xcframeworks
to build the framework and drag the built Frames
into your Xcode project.
Demo projects
We've worked with Product and Design to create simple demo applications that showcase our SDKs, that you'll be able to run locally as soon as you clone the repository (whether directly via git or with suggested integration methods).
Our demo apps also test the supported integration methods (SPM, Cocoapods, Carthage), so if you're having any problems there, they should offer a working example. You will find them in the root of the repository, inside respective folders:
- iOS Example Frame (Using Cocoapods distribution)
- iOS Example Frame SPM (SPM distribution)
- iOS Example Frame Carthage (Carthage distribution)
Once running, you will find the home screen with a number of design options. We have tried to make them pretty contrasting to give your UI/UX teammates an idea of what can be achieved. We've also tried to write the code in the simplest way to track and understand how each UI flavour was created. Just start from HomeViewController.swift
and follow the button actions in code (@IBAction
) for some examples on how we achieve those UIs.
Get started
If you got here, we'll either assume you've completed Integration or you're just curious. If none, then please complete Integration first.
1. Import Frames
If unsure where to do it, the ViewController that will be presenting the journey is a good start
import Frames
2. Prepare your object responsible for the Frames configuration
This is the logical configuration:
- ensuring you receive access for the request
- enable us to prevalidate supported schemes at input stage
- prefill user information (Optional but may go a long way with User Experience if able to provide)
/**
This is optional and can use nil instead of this property.
But if you can provide these details for your user you can
- make their checkout experience easier by prefilling fields they may need to do
- improve acceptance success for card tokenisation
*/
let country = Country(iso3166Alpha2: "GB")
let address = Address(
addressLine1: "221B Baker Street",
addressLine2: "Marylebone",
city: "London",
state: "London",
zip: "NW1 6XE",
country: country)
let phone = Phone(number: "+44 2072243688",
country: country)
let billingFormData = BillingForm(
name: "Amazing Customer",
address: address,
phone: phone)
let configuration = PaymentFormConfiguration(
apiKey: "<Your Public Key>",
environment: .sandbox,
supportedSchemes: [.visa, .maestro, .mastercard],
billingFormData: billingFormData)
3. Prepare the Styling for the UI
We will cover Make it your own later, for now we'll use Default Style
// Style applied on Card input screen (Payment Form)
let paymentFormStyle = DefaultPaymentFormStyle()
// Style applied on Billing input screen (Billing Form)
let billingFormStyle = DefaultBillingFormStyle()
// Frames Style
let style = PaymentStyle(
paymentFormStyle: paymentFormStyle,
billingFormStyle: billingFormStyle)
4. Prepare your response from the flow completion
If the user completes flow without cancelling, the completion handler will be called, with a card token if successful, or with an error if failed
let completion: ((Result<TokenDetails, TokenRequestError>) -> Void) = { result in
switch result {
case .failure(let error):
print("Failed, received error", error.localizedDescription)
case .success(let tokenDetails):
print("Success, received token", tokenDetails.token)
}
}
5. Use our PaymentFormFactory
to generate the ViewController
Using properties from Steps 2, 3 & 4, lets now create the ViewController
let framesViewController = PaymentFormFactory.buildViewController(
configuration: configuration, // Step 2
style: style, // Step 3
completionHandler: completion // Step 4
)
6. Present the ViewController to your user
We now have created the ViewController needed to enable full tokenisation for your user. Let's present it.
/**
We are assuming you started the Walkthrough from the presenting ViewController
and that a Navigation Controller is available
You will need to make minor adjustments otherwise.
For the best experience we recommend embedding the presenting ViewController inside an UINavigationController
*/
navigationController?.pushViewController(framesViewController, animated: true)
Make it your own
!!! Any customisation needs to be done before creating the ViewController. Once style is submitted to the factory, any changes done on it will not be reflected in the UI !!!
We have been working hard to provide a selection of ways to make it your own. In order of complexity we'll start with:
Modify Default
In our Get started example we have used Default Style to get something working quickly. If that was mostly what you were looking for, then you'll be happy to know that each component is mutable and you should easily be able to customise individual properties. This is also used as example in our demo projects inside Factory.swift
, in the method getDefaultPaymentViewController
.
Example:
var paymentFormStyle = DefaultPaymentFormStyle()
// Change background of page
paymentFormStyle.backgroundColor = UIColor.darkGray
// Change card number input placeholder value
paymentFormStyle.expiryDate.textfield.placeholder = "00 / 00"
// Change Payment button text
paymentFormStyle.payButton.text = "Pay £54.63"
We wouldn't recommend this approach if you're looking to override many values, since you would need to individually identify and change every property. But it can work for small tweaks.
Use Theme
In our Demo projects we also demo this approach in ThemeDemo.swift
. With the Theme, we are aiming to give you a design system that you can use to create the full UI style by providing a small number of properties that we will share across to sub components. Since you might not fully agree with our mapping, you can still individually change each component afterwards (as in the Modify Default example).
// Declare the theme object with the minimum required properties
var theme = Theme(
primaryFontColor: UIColor(red: 0 / 255, green: 204 / 255, blue: 45 / 255, alpha: 1),
secondaryFontColor: UIColor(red: 177 / 255, green: 177 / 255, blue: 177 / 255, alpha: 1),
buttonFontColor: .green,
errorFontColor: .red,
backgroundColor: UIColor(red: 23 / 255, green: 32 / 255, blue: 30 / 255, alpha: 1),
errorBorderColor: .red)
// Add border and corner radius around text inputs
theme.textInputBackgroundColor = UIColor(red: 36 / 255.0, green: 48 / 255.0, blue: 45 / 255.0, alpha: 1.0)
theme.textInputBorderRadius = 4
// Build complete payment form by providing only texts
var paymentFormStyle = theme.buildPaymentForm(
headerView: theme.buildPaymentHeader(title: "Payment details",
subtitle: "Accepting your favourite payment methods"),
addBillingButton: theme.buildAddBillingSectionButton(text: "Add billing details",
isBillingAddressMandatory: false,
titleText: "Billing details"),
billingSummary: theme.buildBillingSummary(buttonText: "Change billing details",
titleText: "Billing details"),
cardNumber: theme.buildPaymentInput(isTextFieldNumericInput: true,
titleText: "Card number",
errorText: "Please enter valid card number"),
expiryDate: theme.buildPaymentInput(textFieldPlaceholder: "__ / __",
isTextFieldNumericInput: false,
titleText: "Expiry date",
errorText: "Please enter valid expiry date"),
securityCode: theme.buildPaymentInput(isTextFieldNumericInput: true,
titleText: "CVV date",
errorText: "Please enter valid security code"),
payButton: heme.buildPayButton(text: "Pay now"))
// Override a custom property from the resulting payment form style
paymentFormStyle.payButton.disabledTextColor = UIColor.lightGray
let billingFormStyle = theme.buildBillingForm(
header: theme.buildBillingHeader(title: "Billing information",
cancelButtonTitle: "Cancel",
doneButtonTitle: "Done"),
cells: [.fullName(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: false, title: "Your name")),
.addressLine1(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: true, title: "Address")),
.city(theme.buildBillingInput(text: "", isNumericInput: false, isMandatory: true, title: "City")),
.country(theme.buildBillingCountryInput(buttonText: "Select your country", title: "Country")),
.phoneNumber(theme.buildBillingInput(text: "", isNumericInput: true, isMandatory: true, title: "Phone number"))])
We think this approach should hit a good balance between great control of UI & simple, concise code. The font sizes even use preferredFont(forTextStyle: ...).pointSize
to give you font sizes that match your users device preferences. However if you still find the mapping to need excessive customisation, our final approach may be more to your liking.
Declare all components
This is by no means the easy way, but it is absolutely the way to fully customise every property, and discover the full extent of customisability as you navigate through. You will find inside the Demo projects the files Style.swift
and CustomStyle1.swift
which follow this approach.
If deciding to do this, try to:
let compiler help. Xcode's autocomplete should come in handy to help navigate from highest level into the lowest customisation option
let style = PaymentStyle(paymentFormStyle: <#T##PaymentFormStyle#>, billingFormStyle: <#T##BillingFormStyle#>)
protocols are the keyword. Starting from code above, the arguments will be protocol objects until the lowest level.
// You will need to prepare your objects that conform to the required protocols struct MyPaymentFormStyle: PaymentFormStyle { var backgroundColor: UIColor = ... var headerView: PaymentHeaderCellStyle = ... var editBillingSummary: BillingSummaryViewStyle? = ... var addBillingSummary: CellButtonStyle? = ... var cardholderInput: CellTextFieldStyle? = ... var cardNumber: CellTextFieldStyle = ... var expiryDate: CellTextFieldStyle = ... var securityCode: CellTextFieldStyle? = ... var payButton: ElementButtonStyle = ... }
// Then feed them to your end PaymentStyle let style = PaymentStyle(paymentFormStyle: MyPaymentFormStyle(), billingFormStyle: <#T##BillingFormStyle#>)
# Other features
### Handle 3D Secure
When you send a 3D secure charge request from your server you will get back a 3D Secure URL. This is available from `_links.redirect.href` within the JSON response. You can then pass the 3D Secure URL to a `ThreedsWebViewController` in order to handle the verification.
The redirection URLs (`success_url` and `failure_url`) are set in the Checkout.com Hub, but they can be overwritten in the charge request sent from your server. It is important to provide the correct URLs to ensure a successful payment flow.
Lets imagine we are now working inside `YourViewController.swift` and we are handling the 3DS challenge:
```swift
// Ensure you know the fail & success URLs
private enum Constants {
static let successURL = URL(string: "http://example.com/success")!
static let failureURL = URL(string: "http://example.com/failure")
}
// Prepare the service
let checkoutAPIService = CheckoutAPIService(publicKey: "<Your Public Key>", environment: .sandbox)
// Create the ThreedsWebViewController
let threeDSWebViewController = ThreedsWebViewController(
checkoutAPIService: checkoutAPIService,
// If the payment response provided new success_url or failure_url, use those. Otherwise default to Checkout provided values as documented previously
successUrl: serverOverridenSuccessURL ?? Constants.successURL,
failUrl: serverOverridenFailureURL ?? Constants.failureURL)
threeDSWebViewController.delegate = self
threeDSWebViewController.authURL = challengeURL // This is coming from the payment response
// Present threeDSWebViewController
present(threeDSWebViewController, animated: true, completion: nil)
Previously we have added the line threeDSWebViewController.delegate = self
. This will raise compiler error as we now need to have YourViewController
conform to the required protocol. Doing this, we are able to find the outcome of the challenge and react accordingly
extension YourViewController: ThreedsWebViewControllerDelegate {
func threeDSWebViewControllerAuthenticationDidSucceed(_ threeDSWebViewController: ThreedsWebViewController, token: String?) {
// Congratulations, the Challenge was successful !
threeDSWebViewController.dismiss(animated: true, completion: nil)
}
func threeDSWebViewControllerAuthenticationDidFail(_ threeDSWebViewController: ThreedsWebViewController) {
// Oooops, the payment failed !
threeDSWebViewController.dismiss(animated: true, completion: nil)
}
}
Using Apple Pay
We are able to handle PKPayment
token data from Apple Pay.
// Prepare the service
let checkoutAPIService = CheckoutAPIService(publicKey: "<Your Public Key>", environment: .sandbox)
func handle(payment: PKPayment) {
// Get the data containing the encrypted payment information.
let paymentData = payment.token.paymentData
// Request an Apple Pay token.
checkoutAPIService.createToken(.applePay(ApplePay(paymentData))) { result in
switch result {
case .success(let tokenDetails):
// Congratulations, payment token is available
case .failure(let error):
// Ooooops, an error ocurred. Check `error.localizedDescription` for hint to what went wrong
}
}
}
Migrating
3DS and Apple Pay processing remain unaffected so using them should still work the same.
If you're using Frames iOS from versions prior to v4 (we would strongly recommend using the latest release), this update will bring breaking changes that'll require a little development time.
Because of our efforts to greatly improve the UI of the Frames and enabling you to customise it to such extents, the approach required is very different. This will require you to:
- remove usage of Frames older version from your code base. This may be an opportunity to remove a screen as well, or a few other objects that were created only to support older Frames integration!
- Get started
We would like to point out the great benefits that we think v4+ brings to our SDK, like:
- customisable UI focussed on enabling your users to seamlessly transition through the payment flow
- updated and improved validation logic, in line with our supported card payment methods
- using our updated UIs provides added security benefits to your customers
License
Frames iOS is released under the MIT license. See LICENSE for details.
*Note that all licence references and agreements mentioned in the FramesIos README section above
are relevant to that project's source code only.