Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all articles
Browse latest Browse all 4370

Apple Pay Tutorial

$
0
0
Learn how to integrate Apple Pay into your application!

Learn how to integrate Apple Pay into your application!

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! :]

Note: You’ll need a paid active Apple developer account to complete this tutorial.

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:

ApplePaySwag startup screen.

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 in SwagListViewController.
  • 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:

Merchant ID Locations

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:

Merchant ID selected

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:

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:

Scene with Apple Pay Button

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:

  1. merchantIdentifier is your merchant ID. This is used to decrypt the cryptogram on the backend.
  2. supportedNetworks tells the request which networks you support. This affects which of your user’s cards show up in the Apple Pay sheet.
  3. 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.
  4. 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.
  5. currencyCode is the currency of your transaction; since you set countryCode 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:

ApplePay-Lite

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!

Not Available

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:

Add-shipping-info

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:

Only ask for the information you need.

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.

address-noaddress

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:

bad-address

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 PKShippingMethods 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:

full-shipping-with-method

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.

Uploaded Stripe certificate

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:

  1. Send the authorization token via the PKPayment object to Stripe for decryption. If successful, Stripe returns their own “Stripe” token.
  2. Send the Stripe token to a server of your own to let your backend know about the order and perform any necessary processing.
  3. 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:

  1. Creates a “route” that accepts an HTTP POST at /pay.
  2. Sets your Stripe Secret Key. Make sure you use your own Secret Key!
  3. Parses the JSON request.
  4. Creates a charge using the Stripe Python SDK. The amount is measured in cents.
  5. 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.

Note: If you aren’t familiar with CocoaPods, check out the Introduction to CocoaPods tutorial on our site for more information.

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:

Preprocessor macro for Stripe

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:

Bridging header.

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:

  1. Grab and parse the final shipping address information from PKPayment. This will give you all the information from the selected address.
  2. Set the publishable Stripe key for your app in the Stripe SDK. Make sure to replace the key above with your own publishable key.
  3. 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.
  4. Create an Address struct from the final shippingAddress for the final payment amount.
  5. 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 as http://192.168.1.18:5000/pay. For this to work, your iOS device and your Mac need to be on the same network.
  6. Construct the JSON for the request. This includes the token property of STPToken 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.
  7. 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, money!

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.


Viewing all articles
Browse latest Browse all 4370

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>