Chapter    13

Pay with Apple Pay

As an iOS developer, you have probably heard of Apple Pay. Apple Pay lets iPhone users pay for purchases by using their iPhones. There are some great benefits in store for a developer to integrate Apple Pay in his or her app. For example, your customers don’t need to enter a credit card number, expiration date, and CVC numbers; or in some cases, shipping address and billing address before making a purchase. All of this means a faster and more convenient checkout process. Another benefit is that it’s supposed to be a much secure way to handling credit card charges. In this chapter, I will show how to implement the feature of Pay with Apple Pay and Stripe.

Overview of Apple Pay

As a matter of fact, Apple Pay only handles part of the whole charge process. Namely, Apple Pay has completed the following things:

  1. Authenticated a user, the iPhone owner, or a credit card holder.
  2. Used a user interface to show what he or she is buying.
  3. Provided you, the developer, with the shipping and billing addresses of the user.
  4. Provided you, the developer, with a token so you can exchange it with a real payment processor, such as Stripe.

Note  To understand more about how Apple Pay works, please refer to https://developer.apple.com/apple-pay/Getting-Started-with-Apple-Pay.pdf.

Apple Pay and Stripe

Note  In order to use Apple Pay, you’ll need to add the “Apple Pay” capability to your app in Xcode. This requires creating, first, a merchant ID with Apple. You can read more about that process from the tutorial https://stripe.com/docs/mobile/apple-pay.

In Chapter 12, I have shown how to add Stripe/ApplePay CocoaPod to your project. After you have the merchant ID and “Apple Pay” capability set up, you can take full advantage of what the Stripe Apple Pay SDK has to offer. These are the steps:

  1. Generate a PKPaymentRequest to submit to Apple.
  2. Set the paymentSummaryItems property to an NSArray of PKPaymentSummaryItems. These are analogous to line items on a receipt and are used to explain our charges to the user.
  3. After creating the request, query the device to see if Apple Pay is available (i.e., whether the app is running on the latest hardware and the user has added a valid credit card).
  4. Create and display the payment request view controller.
  5. After the payment request controller has returned a PKPayment, you can turn it into a single-use Stripe token with a simple method call.
  6. Once you receive the Stripe token, call the Parse Cloud Function to make a real charge. The real charge will be handled by our back end, as we have done with Pay with Credit Card.

As you can see, the difference between Pay with Credit Card and Pay with Apple Pay is that you don’t need to create an EMABPayment instance and save it while dealing with Pay with Apple Pay—Apple Pay on a user’s device has the credit card information stored. Another benefit is that you don’t need to ask for the user’s shipping address; you can get it from the payment request.

Here is how to implement it, assuming you have registered a merchant ID through Apple Developer portal.

Write down your merchant ID with our EMABConstants class and name it kAppleMerchantID. Next, create a property to keep track of the PKPaymentRequest.

@property (nonatomic, strong) PKPaymentRequest *paymentRequest;

As mentioned before, you will need to use Apple’s PKPaymentAuthorizationViewController. This view controller has some delegate methods you need to implement, so declare it:

@interface EMABBagTableViewController()<PKPaymentAuthorizationViewControllerDelegate>

Also, in order to show the items the user is purchasing, you need to set up the item list confirming PKPaymentAuthorizationViewController API PKPaymentSummaryItem. In other words, you need to transfer our EMABOrderItem to PKPaymentSummaryItem. Here is the helper method for that:

- (NSArray *)summaryItemsForShippingMethod:(PKShippingMethod *)shippingMethod {
    NSMutableArray *purchasedItems = [NSMutableArray arrayWithCapacity:[self.order.items count]];
    for (EMABOrderItem *item in self.order.items) {
        double total = item.quantity * item.product.unitPrice;
        NSString *readable = [NSString stringWithFormat:@"%.2f",total];
        NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:readable];
        PKPaymentSummaryItem *purchasedItem = [PKPaymentSummaryItem
summaryItemWithLabel:item.product.name amount:price];

        [purchasedItems addObject:purchasedItem];
    }

    return [NSArray arrayWithArray:purchasedItems];
}

Basically, you create a mutable array, iterate EMABOrderItem, and instantiate PKPaymentSummaryItem based on an instance of EMABOrderItem. In the end, you return an immutable copy of the container array.

Take a close look at the following two lines of code:

NSString *readable = [NSString stringWithFormat:@"%.2f",total];
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:readable];

This is definitely not the best way to represent the currency amount because normally you only have a two-digit mantissa for the currency amount. The recommended way by Apple Pay API is this:

NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithMantissa:total exponent:-2 isNegative:NO];

Before you can initialize PKPaymentRequest, you need to know whether the user’s iPhone is configured to Pay with Apple Pay. Luckily, Stripe has a convenient method for you: -(BOOL) canSubmitPaymentRequest. If yes, proceed ahead. If no, you need to gracefully report it to the user.

You also need to have the user’s shipping address so you can mail the package. PKPaymentRequest has a method and setRequiredShippingAddressFields:PKAddressFieldPostalAddress for that.

Here is the code:

-(IBAction)onApplePay:(id)sender{
    NSString *merchantId = kAppleMerchantID;
    self.paymentRequest = [Stripe paymentRequestWithMerchantIdentifier:merchantId];
    if ([Stripe canSubmitPaymentRequest:self.paymentRequest]) {
        [self.paymentRequest setRequiredShippingAddressFields:PKAddressFieldPostalAddress];
        [self.paymentRequest setRequiredBillingAddressFields:PKAddressFieldPostalAddress];
        self.paymentRequest.paymentSummaryItems = [self summaryItemsForShippingMethod:nil];
        PKPaymentAuthorizationViewController *auth = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:self.paymentRequest];
        auth.delegate = self;
        if (auth) {
            [self presentViewController:auth animated:YES completion:nil];
        } else
            [SVProgressHUD showErrorWithStatus:NSLocalizedString(@"Something Wrong", @"Something Wrong")];

    } else {
        [SVProgressHUD showErrorWithStatus:NSLocalizedString(@"Apple Pay is not enabled.
        Please enable your Apple Pay or Pay with Credit Card.", @"")];

    }

}

Next, present the PKPaymentAuthorizationViewController. The user taps to pay. What happens after the tap? Here’s how to implement the view controller’s delegate method:

-(void)paymentAuthorizationViewController:(nonnull PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(nonnull PKPayment *)payment completion:(nonnull void (^)(PKPaymentAuthorizationStatus))completion{
    [self handlePaymentAuthorizationWithPayment:payment completion:nil];

}

Create the helper method handlePaymentAuthorizationWithPayment, then implement this method in “Creating a single-use token.” Note that you have also been given a block that takes a PKPaymentAuthorizationStatus. Call this function with either PKPaymentAuthorizationStatusSuccess or PKPaymentAuthorizationStatusFailure after all of your asynchronous code is finished executing. This is how the PKPaymentAuthorizationViewController knows when and how to update its UI.

- (void)handlePaymentAuthorizationWithPayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {

    [[STPAPIClient sharedClient] createTokenWithPayment:payment
                           completion:^(STPToken *token, NSError *error) {
                              if (error) {
                                 completion(PKPaymentAuthorizationStatusFailure);
                                 return;
                              }
                              [self createBackendChargeWithToken:token completion:completion];
                           }];

}

Once you receive the charge token, call the Parse Cloud function to make a real charge:

- (void)createBackendChargeWithToken:(STPToken *)token
                          completion:(void (^)(PKPaymentAuthorizationStatus))completion {
    [self chargeWithToken:token.tokenId];
}

Here is how to call the Cloud function:

-(void)chargeWithToken:(NSString *)tokenId{
    [self.order saveInBackgroundWithBlock:^(BOOL success, NSError *error){
        if (!error) {
            __weak typeof(self) weakSelf = self;
            NSDictionary *params = @{@"chargeToken":tokenId, @"orderId":weakSelf.order.
objectId};

            [PFCloud callFunctionInBackground:@"ChargeToken" withParameters:params
block:^(NSString *message, NSError *error){

                if (!error) {
                    [weakSelf queryForUnfinishedOrder];
                }
            }];
        }
    }];

}

By all means, you want to save the current order first. After the save action is finished, pass the Stripe token and the order ID to the back end. It’s a much safer practice. Once the charge is successfully run through, you make another API call to check whether the order status has been changed; also update your UI.

Summary

In this chapter, I briefly summarized how Apply Pay works and how you can implement the Pay with Apple Pay feature with Stripe’s Apple Pay library.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.66.156