Apple took a big step into the world of mobile payments with the introduction of the iPhone 6 and Apple Pay. There are two ways you can use Apple Pay to purchase items: at the point of sale using Near Field Communication (NFC), or within an iOS app.
Since creating your own NFC payment system wouldn’t go over too well with Apple, this tutorial will instead look at how to integrate Apple Pay into your own iOS apps. This is different from in-app purchases for digital content — Apple Pay lets you sell goods to your users from within an app.
In this Apple Pay tutorial, you’ll learn how to write an app that lets users buy really cool RayWenderlich.com tutorials and gear using nothing but the convenience of their fingerprints!
Just in case you’re worried, you won’t incur any real charges on your account by working through the project in this tutorial — so feel free to go on a virtual shopping spree! :]
Getting Started
Download the starter project for this tutorial; it’s named ApplePaySwag.
Build and run to make sure the project works out of the box. You should see the startup screen as follows:
The app as it stands is a simple Master/Detail application that shows a list of RayWenderlich.com “swag” in the master view. Tap on any piece of swag to navigate to a detail view which shows a bigger picture of the swag as well as a more detailed description.
Here’s a quick overview of the classes and objects contained in the starter project:
- SwagListViewController: The master view controller that lists the swag available to purchase.
- BuySwagViewController: The detail view controller that shows details of the swag and lets you purchase the item.
- Swag: The primary swag model object.
- SwagCell: A
UITableViewCell
subclass that displays the list of swag inSwagListViewController
. - Main.storyboard: The sole storyboard in the app that contains both scenes.
Feel free to browse through the swag for a moment, but soon you’ll have to tear yourself away and hook this mini-store up to Apple Pay to allow your users to grab some cool gear. Before you jump into the code, there’s a bit of Apple Developer Portal setup work you’ll need to complete first.
Setting Up Your App for Apple Pay
Head over to http://developer.apple.com and log in to your developer account. Go to Member Center and click on Certificates, Identifiers & Profiles\Identifiers\App IDs.
Click on the + button to create a new App ID, name it Apple PaySwag and give it a Bundle ID of the format com.YOURDOMAIN.ApplePaySwag. Make sure that Explicit App ID is selected, as wildcard App IDs aren’t able to make payments with Apple Pay. Finally, check the Apple Pay checkbox under App Services, click Continue and then click Submit to complete the creation of your new App ID.
Next, click on Merchant IDs under Identifiers in the left navigation pane:
Click + to create a new merchant ID; use whatever description and merchant identifier you’d like. Generally, it’s recommended to create merchant identifiers in the reverse domain style that start with merchant
, similar to bundle IDs. Click Continue and then click Register to create your new merchant ID.
Now that your App ID and merchant ID are set up, head back to Xcode to get your project ready for Apple Pay.
Select the ApplePaySwag project in the left navigation bar, then select the ApplePaySwag target and change the Bundle Identifier to match the one you created above. Ensure that the Team selection box is pointing to the development team under which you created your App ID and merchant ID.
Next, click the Capabilities tab. Expand the Apple Pay section and ensure that the switch on the right is set to ON. Then push the refresh button below the merchant ID list; you should see the list populate with the merchant ID you added on the developer portal, if it wasn’t there already.
Finally, check the checkbox next to your merchant ID; your screen should look like the image below:
The three items in the Steps section should all have checkmarks next to them to indicate that you’ve satisfied all of the requirements for using Apply Pay in your app. If one isn’t checked, retrace your steps to make sure you’ve taken care of all the details.
You now have Apple Pay enabled in your app. Time to get to the fun part — the coding! :]
Adding the Apple Pay Button
Open Main.storyboard and take a look at the the Buy Swag scene:
This view has a larger and more prominent picture of the swag, the price, a detailed description of the swag and a basic button to buy the swag. This is where you’ll hook in the magic of Apple Pay!
You’ll want something more interesting than a simple out-of-the-box button to entice your users to buy. Apple has a very specific set of Apple Pay guidelines to adhere to, which extends to the buttons in your app. Take a few minutes to review these guidelines at the Apple Pay developer site https://developer.apple.com/apple-pay/.
Note: The Apple Pay Buttons and Resources link at the Apple Pay developer site above provides you with a zip file containing an extensive collection of approved button resources for Apple Pay.
The Apple Pay Guidelines provide explanations of the allowable modifications you can make to the provided buttons, as well as guidelines on what colors you may choose to provide the best amount of contrast between the button and your view’s background. In general, you are not allowed to create your own button artwork, but can “stretch” the provided artwork to be wider if necessary.
Since the purpose of this tutorial is not to test your Photoshop skills, you’ll find a set of Apple Pay images ready for use in the starter project’s Image.xcassets.
Head back to the Buy Swag scene in Interface Builder, select the Apple Pay button and change the image to ApplePaySwagButton. Give your button an empty title instead of the default “button” title. Your scene should now look as follows:
Now that you have an Apple Pay button hooked up to an action method, it’s time to invoke the Apple Pay APIs!
Creating a Payment Request
Open BuySwagViewController.swift and add the following import to the top of the file:
import PassKit |
The Apple Pay classes are actually part of PassKit, so you need that import to do anything useful.
Next, locate purchase(sender:)
; you execute this when the user attempts to purchase an item. To do this, you’ll need to create a PKPaymentRequest
and a PKPaymentAuthorizationViewController
.
Add the following code to the body of purchase(sender:)
:
let request = PKPaymentRequest() let applePayController = PKPaymentAuthorizationViewController(paymentRequest: request) self.presentViewController(applePayController, animated: true, completion: nil) |
This code creates a simple PKPaymentRequest
object that represents a single Apple Pay payment, as well as the creation of a PKPaymentAuthorizationViewController
constructed with the PKPaymentRequest
instance responsible for displaying the Apple Pay payment sheet. Finally, the BuySwagViewController
presents the PKPaymentAuthorizationViewController
.
You’ll need to populate the required elements of PKPaymentRequest
next to see your Apple Pay sheet in action.
Populating PKPaymentRequest
Add the following code just under the IBOutlet
properties of BuySwagViewController
:
let SupportedPaymentNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex] let ApplePaySwagMerchantID = "merchant.com.YOURDOMAIN.ApplePaySwag" // Fill in your merchant ID here! |
SupportedPaymentNetworks
defines an array of payment networks you are able to accept. You set these depending on your ability to process each of these payment networks; in this tutorial you’ll accept all three. ApplePaySwagMerchantID
is a string that matches the merchant ID you created on the developer portal and set in your app’s Capabilities.
It would be a good idea to hide the Apple Pay button if the user isn’t able to make payments for some reason, such as parental control settings or not having the right hardware. In that case, you’ll just let them window shop.
Add the following code to viewDidLoad()
:
applePayButton.hidden = !PKPaymentAuthorizationViewController.canMakePaymentsUsingNetworks(SupportedPaymentNetworks) |
canMakePaymentsUsingNetworks
returns a Boolean if the user can make payments, so you negate this value with !
to set whether the button should be hidden or not.
Add the following lines to purchase(sender:)
, below the point where you instantiate PKPaymentRequest
:
request.merchantIdentifier = ApplePaySwagMerchantID request.supportedNetworks = SupportedPaymentNetworks request.merchantCapabilities = PKMerchantCapability.Capability3DS request.countryCode = "US" request.currencyCode = "USD" |
These five fields tell the payment request about the capabilities of your transaction:
merchantIdentifier
is your merchant ID. This is used to decrypt the cryptogram on the backend.supportedNetworks
tells the request which networks you support. This affects which of your user’s cards show up in the Apple Pay sheet.merchantCapabilities
is the security standard you want to use. The details of this are outside the scope of this tutorial, but for now you’ll use 3DS which is the most popular standard in the US.countryCode
is the 2-character country code where your transaction takes place. For now, this is set to US as it is the only supported country at the time this tutorial was published; more countries will be available in the future.currencyCode
is the currency of your transaction; since you setcountryCode
to US, set this to USD.
Now you’ll add some code specific to the swag that will tell the customer the most important detail of this interaction — how much this swag is going to cost them! :]
Add the following code below the PKPaymentRequest
setup code you just added:
request.paymentSummaryItems = [ PKPaymentSummaryItem(label: swag.title, amount: swag.price), PKPaymentSummaryItem(label: "Razeware", amount: swag.price) ] |
Here, you create an array of PKPaymentSummaryItem
objects that provide the user with a breakdown the items they’re purchasing. You might notice that the same price is repeated with different labels. When creating arrays of PKPaymentSummaryItem
, the last summary item will be the amount charged and the label will be prepended with the text PAY TO.
Build and run your app on a physical device; select your swag of choice and press the Apple Pay button. You should see the Apple Pay sheet pop up on the screen like so:
It’s exciting to see that fingerprint icon on the screen! Scan your programmed-finger-of-choice on the touch ID sensor, and remember, your account won’t be charged. Instead, you’ll see the wait spinner spin forever; tap Cancel to exit out of this state.
Nothing happens here because there’s more interaction you’ll need to handle using a delegate on the PKPaymentAuthorizationViewController
named PKPaymentAuthorizationViewControllerDelegate
.
Implementing Delegates to Handle Payment Requests
In BuySwagViewController.swift, add the following extension to BuySwagViewController
that implements PKPaymentAuthorizationViewControllerDelegate
:
extension BuySwagViewController: PKPaymentAuthorizationViewControllerDelegate { func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didAuthorizePayment payment: PKPayment!, completion: ((PKPaymentAuthorizationStatus) -> Void)!) { completion(PKPaymentAuthorizationStatus.Success) } func paymentAuthorizationViewControllerDidFinish(controller: PKPaymentAuthorizationViewController!) { controller.dismissViewControllerAnimated(true, completion: nil) } } |
This implements the two required methods of PKPaymentAuthorizationViewControllerDelegate
:
paymentAuthorizationViewController(controller:didAuthorizePayment:completion:)
: This handles the user authorization to complete the purchase.paymentAuthorizationViewControllerDidFinish(controller:)
: This is called when the payment request completes.
The PKPayment
object holds the Apple Pay authorization token, as well as final shipping, billing, and contact information for the order, which you’ll handle later in this tutorial.
paymentAuthorizationViewController(controller:didAuthorizePayment:completion:)
is where you’ll eventually send the payment request to your backend for processing. This is also why you saw the spinner spin indefinitely. The Apple Pay sheet will remain in place until you invoke the completion handler; this gives you the amount of time you need to complete the transaction. For now though, you simply hardcode the parameter to the completion block with PKPaymentAuthorizationStatus.Success
.
The responsibility of paymentAuthorizationViewControllerDidFinish(controller:)
, for now, is simply to dismiss the view controller when finished.
Add the following line to purchase(sender:)
right after the creation of your PKPaymentAuthorizationViewController
to set its delegate
:
applePayController.delegate = self |
Build and run your project; select a piece of swag and tap the Apple Pay button one more time. Scan your finger on the Touch ID and… darn, an error alert!
You thought you had everything set up properly for Apple Pay — so why the error?
Your app is not currently permitted to use Apple Pay because you haven’t yet added a certificate from your payment provider — you’ll do that a bit later in the tutorial.
The Apple Pay sheet you present to the user is fairly simple; it only has a method to select which credit card to use to complete the payment. That’s sufficient for payment purposes — but not enough information for your shipping department to send the user the swag they just purchased! You’ll need to tell PKPaymentRequest
what kind of information you require from the user to complete the transaction.
Handling Shipping, Billing, and Contact Information
Add the following code to purchase(sender:)
just after the rest of your PKPaymentRequest
setup code:
request.requiredShippingAddressFields = PKAddressField.All |
Build and run your project; navigate to the Apple Pay sheet and take a look at all of the details filled out for you:
That looks pretty impressive, but part of being a good Apple Pay citizen is to only ask the user for the information that’s absolutely necessary to complete the order.
In your case, you’ll need the shipping address for any physical swag that needs to be shipped, and possibly a phone number in case something goes wrong with the shipping. For digital items, you’ll just need the email address where to send the product or download link once purchased. The PKAddressField
is a bitmask, so you can simply use bitwise OR (the |
operator) on the shipping flags you need.
Modify the code that sets requiredShippingAddressFields
as follows:
switch (swag.swagType) { case SwagType.Delivered: request.requiredShippingAddressFields = PKAddressField.PostalAddress | PKAddressField.Phone case SwagType.Electronic: request.requiredShippingAddressFields = PKAddressField.Email } |
Build and run your project; select a piece of swag and check out the new, lightweight Apple Pay sheet:
You’ll also need to add shipping costs to the order — in this case, a flat $5 to keep this part of the project simple.
Adding Shipping Costs
Open Swag.swift and add the following code below the property declarations:
let shippingPrice: NSDecimalNumber = NSDecimalNumber(string: "5.0") |
This sets your shipping price to a fixed nominal amount.
You now need to calculate the total price; this is the base price of the product plus the shipping cost for physical products only.
Add the following method to the class:
func total() -> NSDecimalNumber { if (swagType == SwagType.Delivered) { return price.decimalNumberByAdding(shippingPrice) } else { return price } } |
If this swag item need to be delivered, you add the shipping cost; otherwise, it’s an electronic product and the total price is just the price of the item.
Finally, go back to BuySwagViewController.swift and modify the creation of your paymentSummaryItems
to reflect your new summary item list:
var summaryItems = [PKPaymentSummaryItem]() summaryItems.append(PKPaymentSummaryItem(label: swag.title, amount: swag.price)) if (swag.swagType == .Delivered) { summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: swag.shippingPrice)) } summaryItems.append(PKPaymentSummaryItem(label: "Razeware", amount: swag.total())) request.paymentSummaryItems = summaryItems |
Build and run your app; select a physical product like a T-shirt and you should see all line items, including shipping, as well as the new calculated total at the bottom. For electronic purchases, such as PDF books, you should see only the price of the book and the total without any shipping costs applied. Leaving out the line item for “shipping” avoids confusing your user when they’re purchasing a downloadable product.
Now that shipping addresses show up in the Apple Pay sheet for delivered items, you’ll need to manage changes to the shipping address.
Responding to Changes in the Shipping Address
Add the following code to the BuySwagViewController
extension:
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didSelectShippingAddress address: ABRecord!, completion: ((status: PKPaymentAuthorizationStatus, shippingMethods: [AnyObject]!, summaryItems: [AnyObject]!) -> Void)!) { completion(status: PKPaymentAuthorizationStatus.Success, shippingMethods: nil, summaryItems: nil) } |
This delegate method works much like paymentAuthorizationViewController(controller:payment:completion:)
as it lets long-running tasks complete due to address or shipping changes made on the Apple Pay sheet. In real-world apps, you might make a service call to calculate sales tax, determine if you can ship to the new address, or if it is even a real address at all!
The callback has two additional parameters:
shippingMethods
: An updated list of shipping methods applicable to this address — you’ll deal with this a bit later in the tutorial.summaryItems
: An updated list of summary items based on the new address, such as appropriate tax amounts for the selected state.
You can pass nil
for any of these callback parameters, which results in no changes to that field. If the new address resulted in new shipping methods or additional tax, then you would pass those new values into the callback.
You’ll notice that the address supplied is an AddressBook of type ABAddress
. It will take a bit of work to convert this to something your app can use.
Create a new Swift file, name it Address.swift and add the following struct definition to the file:
struct Address { var Street: String? var City: String? var State: String? var Zip: String? var FirstName: String? var LastName: String? init() { } } |
This Address
struct will store your address information.
Head back to BuySwagViewController.swift and add the following method:
func createShippingAddressFromRef(address: ABRecord!) -> Address { var shippingAddress: Address = Address() shippingAddress.FirstName = ABRecordCopyValue(address, kABPersonFirstNameProperty)?.takeRetainedValue() as? String shippingAddress.LastName = ABRecordCopyValue(address, kABPersonLastNameProperty)?.takeRetainedValue() as? String let addressProperty : ABMultiValueRef = ABRecordCopyValue(address, kABPersonAddressProperty).takeUnretainedValue() as ABMultiValueRef if let dict : NSDictionary = ABMultiValueCopyValueAtIndex(addressProperty, 0).takeUnretainedValue() as? NSDictionary { shippingAddress.Street = dict[String(kABPersonAddressStreetKey)] as? String shippingAddress.City = dict[String(kABPersonAddressCityKey)] as? String shippingAddress.State = dict[String(kABPersonAddressStateKey)] as? String shippingAddress.Zip = dict[String(kABPersonAddressZIPKey)] as? String } return shippingAddress } |
This does the heavy lifting of moving data from an ABRecord
into the Address
struct. If you’re unfamiliar with AddressBook, check out the Address Book Tutorial in iOS on our site to help get you up to speed.
The Apple Pay address book is pretty relaxed in what information it requires for an address, so you’ll have to make sure you have all the information you need.
Find the empty implementation of paymentAuthorizationViewController(controller:didSelectShippingAddress:completion:)
you added earlier, and add the following code:
let shippingAddress = createShippingAddressFromRef(address) switch (shippingAddress.State, shippingAddress.City, shippingAddress.Zip) { case (.Some(let state), .Some(let city), .Some(let zip)): completion(status: PKPaymentAuthorizationStatus.Success, shippingMethods: nil, summaryItems: nil) default: completion(status: PKPaymentAuthorizationStatus.InvalidShippingPostalAddress, shippingMethods: nil, summaryItems: nil) } |
This tests whether the city, state and ZIP values are valid. If so, you call the completion handler with the .Success
status; otherwise, you use the .InvalidShippingPostalAddress
and Apple Pay will prompt the user to fix the invalid field.
Build and run your app; create a new address without a ZIP code in your Apple Pay address book and watch what happens when you invoke the InvalidShippingPostalAddress
callback:
The address field turns red which indicates to the user that they’ve missed a required detail in their shipping address.
Note: If you put a breakpoint after the call to createShippingAddressFromRef(address:)
, you’ll notice that even though the selected address might have all the information you asked for, only City
, State
, and Zip
are populated.
This is a privacy feature of Apple Pay; you only have access to all the user’s information after they authorize the payment. The basic information available to you before authorization should be sufficient to determine if you can ship to this location, and how much tax to apply.
Now you have a near-fully functional Apple Pay app! Although a flat-fee shipping makes the decision easier for your users, what if they want that cool shirt right now? You can be an awesome digital storekeeper and give them an option to get it delivered sooner.
Adding Variable Shipping Costs
Open Swag.swift and add the following struct to the top of the file:
struct ShippingMethod { let price: NSDecimalNumber let title: String let description: String init(price: NSDecimalNumber, title: String, description: String) { self.price = price self.title = title self.description = description } static let ShippingMethodOptions = [ ShippingMethod(price: NSDecimalNumber(string: "5.00"), title: "Carrier Pigeon", description: "You'll get it someday."), ShippingMethod(price: NSDecimalNumber(string: "100.00"), title: "Racecar", description: "Vrrrroom! Get it by tomorrow!"), ShippingMethod(price: NSDecimalNumber(string: "9000000.00"), title: "Rocket Ship", description: "Look out your window!"), ] } |
This creates a ShippingMethod
struct that includes the price
, title
, and a description
of the shipping method. It also defines the set of shipping methods you offer — unfortunately, your users now know why you are able to offer $5 shipping! :]
Modify the SwagType
enum as shown below:
enum SwagType { case Delivered(method: ShippingMethod) case Electronic } |
Your enum now includes an associated value of type ShippingMethod
with SwagType.Delivered
.
Now that you have a non-fixed shipping price and an associated value, delete the hardcoded shippingPrice
in the Swag
struct and modify the total()
method as shown below:
func total() -> NSDecimalNumber { switch (swagType) { case .Delivered(let swagType): return price.decimalNumberByAdding(swagType.method.price) case .Electronic: return price } } |
Now open up SwagListViewController.swift and initialize every SwagType.Delivered
enum in the swagList
declaration with the cheapest ShippingMode
value:
SwagType.Delivered(method: ShippingMethod.ShippingMethodOptions.first!) |
Open BuySwagViewController.swift and update the purchase(sender:)
method as follows:
switch (swag.swagType) { case .Delivered(let method): summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: method.method.price)) case .Electronic: break } |
This adds the shipping line item to reflect the new associated shipping values.
Finally, replace the switch statement in the same method that determines the requiredShippingAddressFields
with the following:
switch (swag.swagType) { case .Delivered(let method): var shippingMethods = [PKShippingMethod]() for shippingMethod in ShippingMethod.ShippingMethodOptions { let method = PKShippingMethod(label: shippingMethod.title, amount: shippingMethod.price) method.identifier = shippingMethod.title method.detail = shippingMethod.description shippingMethods.append(method) } request.shippingMethods = shippingMethods case .Electronic: break } |
This code iterates through the available shipping methods and creates an instance of PKShippingMethod
for each one. The title
, price
, and detail
will all be visible on the Apple Pay sheet, while the identifier
will be used later to reference the selected shipping method.
Notice that you only set the shippingMethods
property if you have PKShippingMethod
s to add to it. The Apple Pay APIs can be very finicky and fail if you don’t add anything to the shippingMethods
array.
Build and run your app; select a deliverable physical item to see your new shipping methods in action:
Each shipping method has an associated shipping cost, so you’ll want to update the line items and total price when the user selects a new shipping method. Fortunately, this is very similar to the way you handled the selection of shipping addresses earlier.
Responding to Changes in the Shipping Method
Add the following code to your BuySwagViewController
extension:
func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didSelectShippingMethod shippingMethod: PKShippingMethod!, completion: ((PKPaymentAuthorizationStatus, [AnyObject]!) -> Void)!) { let shippingMethod = ShippingMethod.ShippingMethodOptions.filter {(method) in method.title == shippingMethod.identifier}.first! swag.swagType = SwagType.Delivered(method: shippingMethod) completion(PKPaymentAuthorizationStatus.Success, nil) } |
In the above method, you determine which delivery method is selected by matching the title
with the identifier
. The SwagType
is set to Delivered
, which is associated with the newly selected ShippingMethod
.
For the time being, you invoke the callback with nil
. This means the shipping method will update, but the line items and total won’t update. For this to happen, you’ll need to re-calculate the summary items.
Break out the code from purchase(sender:)
that builds the summary items into a new method and call it calculateSummaryItemsFromSwag(swag:)
:
func calculateSummaryItemsFromSwag(swag: Swag) -> [PKPaymentSummaryItem] { var summaryItems = [PKPaymentSummaryItem]() summaryItems.append(PKPaymentSummaryItem(label: swag.title, amount: swag.price)) switch (swag.swagType) { case .Delivered(let method): summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: method.method.price)) case .Electronic: break } summaryItems.append(PKPaymentSummaryItem(label: "Razeware", amount: swag.total())) return summaryItems } |
Don’t forget to remove the old code, and modify purchase(sender:)
to call your new method as follows:
request.paymentSummaryItems = calculateSummaryItemsFromSwag(swag) |
Finally, replace the call to the completion handler at the end of paymentAuthorizationViewController(controller:, didSelectShippingMethod:, completion:)
with the following:
completion(PKPaymentAuthorizationStatus.Success, calculateSummaryItemsFromSwag(swag)) |
Here you simply pass the re-calculated totals as part of signalling a successful payment.
Build and run your app; tap any physical item to see your new shipping choices and totals in action. Now you can have your set of RayWenderlich.com stickers sent to your door via rocketship! Let’s hope you have a landing pad in your front yard! :]
Fulfilling Payment Transactions
Now that you have a fully functional Apple Pay sheet, you’ll want to request that these charges be fulfilled. Apple Pay, of course, doesn’t fulfill payment transactions; it only only authorizes transactions and creates tokens that allow payments to be processed.
To process transactions, you’ll use the online payment processor Stripe. One of the nice things about Stripe, besides being easy to set up, is that it comes with a built-in test payment environment so you can easily test purchases in your app without incurring real charges — which is important when selecting the “Rocket Ship” shipping method! :]
Note:This section is meant to demonstrate the server side of completing an Apple Pay transaction. To follow this portion of the tutorial, sign up for a free Stripe account at www.stripe.com.
Depending on your situation, your company may already process payments using existing systems other than Stripe. In that case, you can still follow along with this section, but you might have slightly different ways of managing Certificate Signing Requests and private keys.
Generating Apple Pay Certificates
The first things you’ll need to do after creating your Stripe account is to tell Stripe about your app and generate a certificate using a Certificate Signing Request, or CSR provided by Stripe.
Head to the Apple Pay section of your Stripe account at https://dashboard.stripe.com/account/apple_pay. Press Create New Certificate to download a .certSigningRequest file.
Now go to your developer portal and navigate to Member Center\Certificates, Identifiers & Profiles\Identifier\Merchant IDs. Select your app’s merchant ID and click Edit.
Navigate to Create Certificate\Continue\Choose File, select the .certSigningRequest you downloaded from Stripe and then click Generate. Click Download to receive your .cer file.
Go back to Stripe, in the Apple Pay section where you created the CSR and upload your new certificate file. Click on the API Keys section of your account; record the Test Secret Key and Test Publishable Key for use later in your app. These test keys will let you to make “fake” payments from Apple Pay — use the live ones at your own risk! :]
You’re all set to send payment requests with your merchant ID to Stripe to be decrypted and processed.
Right now your app isn’t doing anything other than invoking a successful completion handler in paymentAuthorizationViewController(controller:, didAuthorizePayment:, completion:)
when the user authorizes a payment.
Your task is to take the authorization token and send it to Stripe for processing. This consists of three steps:
- Send the authorization token via the
PKPayment
object to Stripe for decryption. If successful, Stripe returns their own “Stripe” token. - Send the Stripe token to a server of your own to let your backend know about the order and perform any necessary processing.
- Sending the Stripe token back to Stripe to trigger the charge.
Creating a Basic Order Management Server
For any app that uses Apple Pay, you’ll likely have a corresponding backend to handle the actual order fulfillment. For this tutorial, you’ll create a lightweight server to receive payment requests from your app and send them to Stripe for processing.
Stripe provides several libraries you can find on their website to help creating your payment request. For now, you’ll create a single-file Python server using the lightweight Python REST framework Flask along with the Stripe Python SDK.
First, you’ll need pip, which is a command-line utility for installing python packages. If you don’t have pip installed, you can install it by following the instructions found here.
Next, open Terminal and use pip to install Flask by entering the following command:
sudo pip install Flask |
Next, install the Python Stripe library with the following command:
sudo pip install --index-url https://code.stripe.com --upgrade stripe |
Next, use a text editor to create a file called ApplePaySwagServer.py. You can place this in the same directory as your Xcode project, if you like.
In your text editor of choice, add the following code:
import stripe from flask import Flask from flask import request from flask import json app = Flask(__name__) #1 @app.route('/pay', methods=['POST']) def pay(): #2 # Set this to your Stripe secret key (use your test key!) stripe.api_key = "sk_test_YOUR_TEST_KEY_HERE" #3 # Parse the request as JSON json = request.get_json(force=True) # Get the credit card details token = json['stripeToken'] amount = json['amount'] description = json['description'] # Create the charge on Stripe's servers - this will charge the user's card try: #4 charge = stripe.Charge.create( amount=amount, currency="usd", card=token, description=description ) except stripe.CardError, e: # The card has been declined pass #5 return "Success!" if __name__ == '__main__': # Set as 0.0.0.0 to be accessible outside your local machine app.run(debug=True, host= '0.0.0.0') |
Following the numbered comments above, here’s what the code does:
- Creates a “route” that accepts an HTTP POST at
/pay
. - Sets your Stripe Secret Key. Make sure you use your own Secret Key!
- Parses the JSON request.
- Creates a charge using the Stripe Python SDK. The
amount
is measured in cents. - Returns the string
Success
back to your app.
Start your the server by executing the Python script in Terminal:
python ApplePaySwagServer.py |
You’ll know it’s running when you see something like the following in your console:
* Running on http://0.0.0.0:5000/ * Restarting with reloader |
Of course, knowing the ins and outs of Python and Flask are not important to learning Apple Pay, but the mini-server you created above helps demonstrate the role your own backend server plays with Apple Pay. In your real-world app, you’d likely add the customer’s order, along with the requisite shipping address, product IDs, and other order information, to a database so the order could be fulfilled.
Integrating the Stripe Apple Pay SDK
Now that you have a lightweight server to accept payments, you just need to send them from your app!
Stripe provides an iOS framework available on GitHub that does most of the heavy lifting for you; the best way to manage this framework is through CocoaPods.
Create a file in the same directory as your .xcodeproj file and name it Podfile.
Open Podfile and add the following line to declare the Stripe Apple Pay library as a dependency:
pod 'Stripe/ApplePay' |
Next, open Terminal and navigate to the directory containing your Podfile.
Run the following command to bring in the Stripe SDK:
pod install |
As always with CocoaPods, ensure you close your project in Xcode and re-open it using .xcworspace instead of the .xcodeproj
You’ll also need to add a simple preprocessor symbol to your project to enable Apple Pay within the Stripe SDK.
In the project navigator, navigate to ApplePaySwag project\ApplePaySwag target\Build Settings and add the string STRIPE_ENABLE_APPLEPAY to both Debug and Release under Preprocessor Macros, as shown below:
Since the Stripe SDK is written in Objective-C, you’ll need to create a bridging header to use in your Swift code.
In the project navigator, right-click on the root ApplePaySwag folder and select New File. Select iOS\Source\Header File to create a bridging file and name it ApplePaySwag-Bridging-Header.h.
Under your project / target settings, set the path of the Objective-C Bridging Header to ApplePaySwag/ApplePaySwag-Bridging-Header.h
as shown below:
Now open ApplePaySwag-Bridging-Header.h and replace its contents with the following import:
#import <Stripe/Stripe.h> #import <Stripe/Stripe+ApplePay.h> |
The Stripe APIs will now be available to your Swift code.
Open BuySwagViewController.swift and replace the hardcoded PKPaymentAuthorizationStatus.Success
in paymentAuthorizationViewController(controller:,didAuthorizePayment:completion)
with the following code:
// 1 let shippingAddress = self.createShippingAddressFromRef(payment.shippingAddress) // 2 Stripe.setDefaultPublishableKey("pk_test_YOUR_API_KEY") // Replace With Your Own Key! // 3 Stripe.createTokenWithPayment(payment) { (token, error) -> Void in if (error != nil) { println(error) completion(PKPaymentAuthorizationStatus.Failure) return } // 4 let shippingAddress = self.createShippingAddressFromRef(payment.shippingAddress) // 5 let url = NSURL(string: "http://<your ip address>/pay") // Replace with computers local IP Address! let request = NSMutableURLRequest(URL: url!) request.HTTPMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Accept") // 6 let body = ["stripeToken": token.tokenId, "amount": self.swag!.total().decimalNumberByMultiplyingBy(NSDecimalNumber(string: "100")), "description": self.swag!.title, "shipping": [ "city": shippingAddress.City!, "state": shippingAddress.State!, "zip": shippingAddress.Zip!, "firstName": shippingAddress.FirstName!, "lastName": shippingAddress.LastName!] ] var error: NSError? request.HTTPBody = NSJSONSerialization.dataWithJSONObject(body, options: NSJSONWritingOptions(), error: &error) // 7 NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in if (error != nil) { completion(PKPaymentAuthorizationStatus.Failure) } else { completion(PKPaymentAuthorizationStatus.Success) } } } |
This modified authorization uses the Stripe SDK to convert a PKPayment
object into an STPToken
object by sending the PKPayment
to Stripe’s servers for decryption. You can then send the returned STPToken
object to your server.
If everything goes well, you invoke your completion block with PKPaymentAuthorizationStatus.Success
. If you encounter an issue such as a network error, you simply return PKPaymentAuthorizationStatus.Failure
.
Here’s a more detailed look at the code above, comment by comment:
- Grab and parse the final shipping address information from
PKPayment
. This will give you all the information from the selected address. - Set the publishable Stripe key for your app in the Stripe SDK. Make sure to replace the key above with your own publishable key.
- Invoke the Stripe API with the authorized Apple Pay token, which sends the token to Stripe. You invoke a completion block when this action completes; if successful, this returns an
STPToken
. - Create an
Address
struct from the finalshippingAddress
for the final payment amount. - Build an
NSMutableRequest
to invoke a POST call to the/pay
URL. Ensure you replace the IP above with your own server’s IP. This is your computer’s IP on your network, followed by the port listed from your Python server, such ashttp://192.168.1.18:5000/pay
. For this to work, your iOS device and your Mac need to be on the same network. - Construct the JSON for the request. This includes the
token
property ofSTPToken
to be sent to Stripe, the amount, and the description — in this case, the title of the ordered swag. In a real-life scenario, you might also include things such as product IDs in your app so your server knows which item or items were ordered. - Send the request to the server. You invoke the completion block with success or failure depending on the
error
result.
Build and run your app one last time; order all the swag you want and have it sent to your address via race car. The rocket ship option is certainly tempting, but it’s a bit of a spoiler that that the amount is over Stripe’s limit — and probably that of your credit card as well! :]
Finally, head to your Stripe dashboard at https://dashboard.stripe.com/test/dashboard and set the Live/Test switch to Test. You should now see all of your “fake” transactions in your dashboard:
W00t — look at all that money! Well, it’s fake money, but it still looks impressive. :]
Where to Go From Here?
You can download the final project source here.
You’ve successfully created a fully functional app — and server! — capable of making payments using Apple Pay. Along the way, you’ve learned a lot about the various frameworks, libraries and APIs involved in payment transactions.
If you’d like to read more in depth on Apple Pay, you can check out the developer site at https://developer.apple.com/apple-pay/. The site also has a list of the other payment platforms other than Stripe that support Apple Pay.
There are many other features of Apple Pay that you could challenge yourself to add to your app:
- Calculate sales tax on the server and update the tax amount in
summaryItems
. - Change the available shipping methods based on the ZIP code.
- Read the order information on the server and verify that the address is valid as a shipping destination.
- Store products, shipping methods, and prices for each product on the server instead of hardcoded into your app.
- Create your own customized Apple Pay button by following the Apple Pay guidelines.
I hope you enjoyed this tutorial; Apple Pay is one of the best new features of iOS 8 and you can bet it will be a popular way to perform online financial transactions. If you have any questions or comments on this tutorial or Apple Pay, feel free to join the discussion below!
Apple Pay Tutorial is a post from: Ray Wenderlich
The post Apple Pay Tutorial appeared first on Ray Wenderlich.