Accepting Credit Cards In Your iOS App Using Stripe
In this tutorial, you will to learn how to accept credit cards in iOS using Stripe, a pain-free, developer-centric way to handle purchases in your apps. By Lorenzo Boaro.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Accepting Credit Cards In Your iOS App Using Stripe
25 mins
Time To Earn Your Stripes
The sequence of steps leading to a successful credit card charge looks like this:
Sending additional information, such as the card’s CVC number and billing address, is not required but is highly recommended. This extra information helps reduce fraudulent transactions that the merchant (that means you or your client) have to cover.
- The app sends your customer’s credit card information to Stripe using a secure HTTPS POST request. The only required bits of information you need to send to Stripe are the credit card number, the expiration month and the expiration year. Not even the owner’s name is required!
Sending additional information, such as the card’s CVC number and billing address, is not required but is highly recommended. This extra information helps reduce fraudulent transactions that the merchant (that means you or your client) have to cover.
- Stripe processes the credit card information and returns a one-time token to your app. Getting this token from Stripe does not mean that your customer’s card was charged. The actual charge is initiated later from your server.
- Assuming the previous step was successful, your app posts the one-time token to your server for the grand finale.
- Server-side, you must contact Stripe again using Stripe’s API. Luckily for you, the fine folks at Stripe have provided official libraries in several popular languages that wrap around their underlying HTTP API. You’ll be using Sinatra-based web application for this tutorial.
- Stripe’s servers attempt to charge the credit card and send the result, success or failure, back to your server.
- In the last step of what seems to be an endless game of telephone, your server notifies your iOS app of the transaction’s final result.
Note: In theory, you could implement everything on the phone without a back end, but for security reasons this is not recommended. Doing so requires you to put both public and private keys in your app – a requirement to submit a charge to Stripe. This means anyone with access to your app could reverse-engineer both keys and would be able to do anything with your Stripe account – ouch!
Note: In theory, you could implement everything on the phone without a back end, but for security reasons this is not recommended. Doing so requires you to put both public and private keys in your app – a requirement to submit a charge to Stripe. This means anyone with access to your app could reverse-engineer both keys and would be able to do anything with your Stripe account – ouch!
Getting Acquainted With Stripe’s iOS Library
There are different ways to add Stripe’s library. According to Stripe’s iOS Integration documentation, they support CocoaPods, Carthage, both Static and Dynamic Frameworks, as well as Fabric.
The starter project uses CocoaPods. In order to not lose the focus of this tutorial, all the dependencies have been set up for you. You don’t need to run any CocoaPod commands!
Note: If you haven’t used CocoaPods before, I encourage you to read CocoaPods Tutorial for Swift: Getting Started tutorial by Joshua Greene. It’s a real time-saver.
Note: If you haven’t used CocoaPods before, I encourage you to read CocoaPods Tutorial for Swift: Getting Started tutorial by Joshua Greene. It’s a real time-saver.
Now it’s time to start coding! You start by implementing the code for steps 1 and 2 above: submitting the credit card information to Stripe and getting a token.
Open Constants.swift. You will find an enum
with a few constants. The first one is for the publishable API key that you got from Stripe when you signed up for an account.
Replace the value of publishableKey
with your Test Publishable Key. It should be a random string of numbers and letters that starts with pk_test.
Note: If you accidentally use your secret key instead of your publishable key, the Stripe API methods that you access later will throw exceptions indicating you’ve made an error. Remember to use your test keys, not your live keys at this stage.
Note: If you accidentally use your secret key instead of your publishable key, the Stripe API methods that you access later will throw exceptions indicating you’ve made an error. Remember to use your test keys, not your live keys at this stage.
Ignore the baseURLString
for now. You’ll get to that later.
Open AppDelegate.swift and at the top of the file, add the import below:
import Stripe
Next, replace the existing definition of application(_:didFinishLaunchingWithOptions:)
with this:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)
-> Bool {
STPPaymentConfiguration.shared().publishableKey = Constants.publishableKey
return true
}
Here you are configuring Stripe with your publishable key.
Now, your next step is to collect credit card details from the user.
Accepting Credit Cards
At the moment, tapping on the Continue button on the checkout view controller does nothing. Open CheckoutViewController.swift and add this import just below the existing UIKit import at the top:
import Stripe
Then, complete the definition of continueDidTap(_:)
Interface Builder action with this:
// 1
guard CheckoutCart.shared.canPay else {
let alertController = UIAlertController(title: "Warning",
message: "Your cart is empty",
preferredStyle: .alert)
let alertAction = UIAlertAction(title: "OK", style: .default)
alertController.addAction(alertAction)
present(alertController, animated: true)
return
}
// 2
let addCardViewController = STPAddCardViewController()
addCardViewController.delegate = self
navigationController?.pushViewController(addCardViewController, animated: true)
If you build at this point, you’ll find a compilation error. Don’t worry about it; you’ll solve it in the next step.
Here’s what happening in the code above:
- Ensure the user has placed at least one puppy in the checkout cart. If not, show a warning message and return.
- Create an instance of
STPAddCardViewController
, set its delegate and present it to the user.
STPAddCardViewController
is a view controller class included in Stripe’s framework. It handles both collecting and tokenizing the user’s payment information. Once presented, the user will see a screen to input the credit card details like the number, expiration date and CVC.
Since our checkout view controller has been set as a delegate of STPAddCardViewController
, you must implement the required methods. In CheckoutViewController.swift, add the following code at the end of the file:
extension CheckoutViewController: STPAddCardViewControllerDelegate {
func addCardViewControllerDidCancel(_ addCardViewController: STPAddCardViewController) {
navigationController?.popViewController(animated: true)
}
func addCardViewController(_ addCardViewController: STPAddCardViewController,
didCreateToken token: STPToken,
completion: @escaping STPErrorBlock) {
}
}
You’ve added two different methods.
-
addCardViewControllerDidCancel(_:)
is called when the user cancels adding a card. -
addCardViewController(_:didCreateToken:completion:)
is called when the user successfully adds a card and your app receives a token from Stripe.
Next, it’s time to finish the StripeClient
component. It’s a singleton class that interacts with your back end.
Open StripeClient.swift. As usual, import Stripe module at the top of the file:
import Stripe
Now, add the following method:
func completeCharge(with token: STPToken, amount: Int, completion: @escaping (Result) -> Void) {
// 1
let url = baseURL.appendingPathComponent("charge")
// 2
let params: [String: Any] = [
"token": token.tokenId,
"amount": amount,
"currency": Constants.defaultCurrency,
"description": Constants.defaultDescription
]
// 3
Alamofire.request(url, method: .post, parameters: params)
.validate(statusCode: 200..<300)
.responseString { response in
switch response.result {
case .success:
completion(Result.success)
case .failure(let error):
completion(Result.failure(error))
}
}
}
Here's the breakdown of the above code:
Next, build a dictionary containing the parameters needed for the charge API. token
, amount
and currency
are mandatory fields.
The amount is an Int
since Stripe API deals only with cents. When displaying amount values, your iOS app uses a currency number formatter.
- First, append the charge method path to the
baseURL
, in order to invoke the charge API available in your back end. You will implement this API shortly. -
Next, build a dictionary containing the parameters needed for the charge API.
token
,amount
andcurrency
are mandatory fields.The amount is an
Int
since Stripe API deals only with cents. When displaying amount values, your iOS app uses a currency number formatter. - Finally, make a network request using Alamofire to perform the charge. When the request completes, it invokes a completion closure with the result of the request.
Open CheckoutViewController.swift and locate addCardViewController(_:didCreateToken:completion:)
. Add the following code to it:
StripeClient.shared.completeCharge(with: token, amount: CheckoutCart.shared.total) { result in
switch result {
// 1
case .success:
completion(nil)
let alertController = UIAlertController(title: "Congrats",
message: "Your payment was successful!",
preferredStyle: .alert)
let alertAction = UIAlertAction(title: "OK", style: .default, handler: { _ in
self.navigationController?.popViewController(animated: true)
})
alertController.addAction(alertAction)
self.present(alertController, animated: true)
// 2
case .failure(let error):
completion(error)
}
}
This code calls completeCharge(with:amount:completion:)
and when it receives the result:
- If the Stripe client returns with a success result, it calls
completion(nil)
to informSTPAddCardViewController
the request was successful and then presents a message to the user. - If the Stripe client returns with a failure result, it simply calls
completion(error)
lettingSTPAddCardViewController
handle the error since it has internal logic for this.
Build what you've got so far to make sure everything’s implemented correctly.
Note: If you see compiler warnings do not worry since Stripe SDK supports iOS versions back to iOS 8 while in this tutorial you are working with iOS 11.
Note: If you see compiler warnings do not worry since Stripe SDK supports iOS versions back to iOS 8 while in this tutorial you are working with iOS 11.
Well done! Now it's time to set up the back-end script that is going to complete the credit card payment.