Search code examples
iosswiftpaypalbraintreeapplepay

Braintree - Drop-in UI - Apple Pay - Swift 3


I am integrating Braintree Drop-in UI for credit card, paypal and apple pay payments. I have followed the basic steps of credit card payments. Everything works fine in sandbox.

Now I am implementing apple pay.

I have completed its configuration as mentioned here, successfully : https://developers.braintreepayments.com/guides/apple-pay/configuration/ios/v4

This is how it looks in simulator as of now :

enter image description here

I have written the following code to implement the credit card payment:

import UIKit
import BraintreeDropIn
import Braintree

class DonationPaymentViewController: UIViewController {

let toKinizationKey = "my_tokenization_key"
@IBOutlet weak var amountTextField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func sendRequestPaymentToServer(nonce: String, amount: String) {
    let paymentURL = URL(string: "my_api_url")!
    var request = URLRequest(url: paymentURL)
    print("paymentMethodNonce=\(nonce)&amount=\(amount)")
    //request.httpBody = "paymentMethodNonce=\(nonce)&amount=\(amount)".data(using: String.Encoding.utf8)
    request.httpMethod = "POST"

    let token = UserDefaults.standard.object(forKey: "Token") as! String

    let params = ["paymentMethodNonce":"\(nonce)", "amount":amount] as [String : Any]

    let prettyPrinted:Bool = false
    let options = prettyPrinted ?
        JSONSerialization.WritingOptions.prettyPrinted : JSONSerialization.WritingOptions(rawValue: 0)

    request.httpBody = try! JSONSerialization.data(withJSONObject: params, options: options)
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    request.addValue(token, forHTTPHeaderField: "X-API-KEY")

    URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) -> Void in
        guard let data = data else {
            self?.show(message: (error?.localizedDescription)!)
            return
        }

        guard let result = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let success = result?["success"] as? Bool, success == true else {
            self?.show(message: "Transaction failed. Please try again.")
            return
        }

        self?.show(message: "Successfully charged. Thanks So Much :)")
        }.resume()
}

@IBAction func pay(_ sender: Any) {
    let request =  BTDropInRequest()
    let dropIn = BTDropInController(authorization: toKinizationKey, request: request)
    { [unowned self] (controller, result, error) in

        if let error = error {
            self.show(message: error.localizedDescription)


        } else if (result?.isCancelled == true) {
            self.show(message: "Transaction Cancelled")

        } else if let nonce = result?.paymentMethod?.nonce, let amount = self.amountTextField.text {
            self.sendRequestPaymentToServer(nonce: nonce, amount: amount)
        }
        controller.dismiss(animated: true, completion: nil)
    }
    self.present(dropIn!, animated: true, completion: nil)
}

func show(message: String) {
    DispatchQueue.main.async {
        //self.activityIndicator.stopAnimating()

        let alertController = UIAlertController(title: message, message: "", preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
        self.present(alertController, animated: true, completion: nil)
    }
}

}

I need help in coding for apple pay. Braintree docs do not provide proper info on Braintree Drop-in UI for Apple Pay using Swift 3. This is the link I am supposed to follow : https://developers.braintreepayments.com/guides/apple-pay/client-side/ios/v4 But it doesn't seem to be for Drop-in UI. Any help on Braintree drop-in UI for apple pay and paypal would be highly appreciated.


Solution

  • Check code below i write comment as i can , when user select apple pay you have to configure paymentRequest let paymentRequest = PKPaymentRequest() then handle PKPaymentAuthorizationViewControllerDelegate to Get nonce

    func showDropIn(clientTokenOrTokenizationKey: String) {
        let request =  BTDropInRequest()
        request.applePayDisabled = false // Make sure that  applePayDisabled i sfalse
    
        let dropIn = BTDropInController.init(authorization: clientTokenOrTokenizationKey, request: request) { (controller, result, error) in
    
            if (error != nil) {
                print("ERROR")
            } else if (result?.isCancelled == true) {
                print("CANCELLED")
    
            } else if let result = result{
    
                switch result.paymentOptionType {
                case .applePay ,.payPal,.masterCard,.discover,.visa:
                     // Here Result success  check paymentMethod not nil if nil then user select applePay
                    if let paymentMethod = result.paymentMethod{
                        //paymentMethod.nonce  You can use  nonce now
                 controller.dismiss(animated: true, completion: nil)
                    }else{
    
                        controller.dismiss(animated: true, completion: {
    
                            self.braintreeClient = BTAPIClient(authorization: clientTokenOrTokenizationKey)
    
                            // call apple pay
                            let paymentRequest = self.paymentRequest()
    
                            // Example: Promote PKPaymentAuthorizationViewController to optional so that we can verify
                            // that our paymentRequest is valid. Otherwise, an invalid paymentRequest would crash our app.
    
                            if let vc = PKPaymentAuthorizationViewController(paymentRequest: paymentRequest)
                                as PKPaymentAuthorizationViewController?
                            {
                                vc.delegate = self
                                self.present(vc, animated: true, completion: nil)
                            } else {
                                print("Error: Payment request is invalid.")
                            }
    
                        })
    
    
    
    
                    }
                default:
                    print("error")
                    controller.dismiss(animated: true, completion: nil)
                }
    
                // Use the BTDropInResult properties to update your UI
                // result.paymentOptionType
                // result.paymentMethod
                // result.paymentIcon
                // result.paymentDescription
            }
    
    
        }
    
        self.present(dropIn!, animated: true, completion: nil)
    
    }
    
    
    
    extension ViewController : PKPaymentAuthorizationViewControllerDelegate{
    
        func paymentRequest() -> PKPaymentRequest {
            let paymentRequest = PKPaymentRequest()
            paymentRequest.merchantIdentifier = "merchant.com.Demo.example";
            paymentRequest.supportedNetworks = [PKPaymentNetwork.amex, PKPaymentNetwork.visa, PKPaymentNetwork.masterCard];
            paymentRequest.merchantCapabilities = PKMerchantCapability.capability3DS;
            paymentRequest.countryCode = "US"; // e.g. US
            paymentRequest.currencyCode = "USD"; // e.g. USD
            paymentRequest.paymentSummaryItems = [
                PKPaymentSummaryItem(label: "Dish", amount: NSDecimalNumber(string: "\(MyOrdersViewController.totalOrderPrice)")),
    
            ]
            return paymentRequest
        }
    
    
    
    
    
        public func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: @escaping (PKPaymentAuthorizationStatus) -> Swift.Void){
    
            // Example: Tokenize the Apple Pay payment
            let applePayClient = BTApplePayClient(apiClient: braintreeClient!)
            applePayClient.tokenizeApplePay(payment) {
                (tokenizedApplePayPayment, error) in
                guard let tokenizedApplePayPayment = tokenizedApplePayPayment else {
                    // Tokenization failed. Check `error` for the cause of the failure.
    
                    // Indicate failure via completion callback.
                    completion(PKPaymentAuthorizationStatus.failure)
    
                    return
                }
    
                // Received a tokenized Apple Pay payment from Braintree.
                // If applicable, address information is accessible in `payment`.
    
                // Send the nonce to your server for processing.
                print("nonce = \(tokenizedApplePayPayment.nonce)")
    
                //  self.postNonceToServer(paymentMethodNonce: tokenizedApplePayPayment.nonce)
                // Then indicate success or failure via the completion callback, e.g.
                completion(PKPaymentAuthorizationStatus.success)
            }
        }
    
        func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
            dismiss(animated: true, completion: nil)
        }
    
    
    }