10

When integrating ApplePay with my test app, I get the error:

This device cannot make payments

I have setup a card to use, and tested it at a Point of Sale terminal - works fine there.

The line of code that should be working (but doesn't) is:

PKPaymentAuthorizationViewController *auth = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:paymentRequest];
techraf
  • 64,883
  • 27
  • 193
  • 198
y2chaits
  • 755
  • 5
  • 17

4 Answers4

21

Apple's documentation is woefully inadequate in listing integration steps in detail.

Apple's Getting Started with Apple Pay document mentions these bullet points:

Prerequisites

In addition to implementing Apple Pay with the PassKit framework, you must:

  • Set up an account with a payment processor or gateway, if you don’t already have one
  • Register a Merchant Identifier via Certificates, Identifiers & Profiles
  • Submit a Certificate Signing Request to obtain Public and Private keys that will be used to encrypt and decrypt Payment Tokens
  • (missing step) Include the Cert in your KeyChain
  • Include an Apple Pay entitlement in your app.

In my case, I'd forgotten step 3. The fix is to submit a new CSR with the merchant ID created in step 2, and include the resulting certificate in your keychain.

Edit: But wait, there's more!

You also need to go to the AppIDs section of your Apple Member Center and edit the App ID for the app to include the merchant account id you just created. Otherwise your app will not be provisioned to use the merchant id. After that, go to Xcode preferences and refresh your provisioning profiles (or download and install them manually if you need to).

These steps should get you past the "This device cannot make payments" error.

y2chaits
  • 755
  • 5
  • 17
  • Hi. I'm also facing the same problem like you. I've finished 4 step of the process. But my app still does not work. Pls help me. Thanks. This is my video record: http://recordit.co/5N6tnRJdJy – haotang Oct 21 '14 at 09:54
  • @haotc92 Please see edit, I added some more steps. It also looks like your *authVC is nil when you are trying to present it. Try these things: 1. Make sure you are assigning authVC to a strong property so that it does not get released immediately after being created. 2. Set a breakpoint and make sure that authVC is not nil when it is being created. If it is nil, that may indicate a problem with the paymentRequest. – y2chaits Oct 21 '14 at 21:39
  • 1
    The authVC init method will return nil if the device is not able to make payments. The PKPaymentAuthorizationViewController canMakePayments should be used to check the capability prior to attempting to instantiate the view controller. – Crufty Nov 20 '14 at 23:24
  • I'm still having problems (in the UK) after following all of the above steps. None of the apps on my phone are showing options for Apple Pay :\ – James Billingham Jul 15 '15 at 17:20
  • How to include the cert in my keychain ? @y2chaits – sr116 Jan 29 '16 at 19:17
2

Make sure the Credit card you setup on Passbook is verified...otherwise, PKPaymentAuthorizationViewController will return nil.

Philip K. Adetiloye
  • 3,102
  • 4
  • 37
  • 63
1
request.supportedNetworks = [NSArray arrayWithObjects:PKPaymentNetworkAmex,PKPaymentNetworkDiscover,PKPaymentNetworkMasterCard,PKPaymentNetworkVisa,PKPaymentNetworkChinaUnionPay, nil];

sure your Card in those Object!

1

You might want to check if your cards are actually usable too. I encountered this issue when having three cards in my Wallet. Two debits (Interac-For Canada) and one Visa. I'd forgotten that the Visa in the wallet was expired, and that Interac is not yet supported for in-App Apple Pay, which forced Passkit to return a Nil PKPaymentAuthorizationControllerInstance. To solve this, i ran a check on the supported Payment Types within the iPhone's Wallet app like so:

func checkApplePayCapabilities() -> Dictionary<String, Any>? {
    var mar = Array<String>()
    var methods : Dictionary<String, String> = ["visa":"no","mastercard":"no","amex":"no","interac":"no","debit":"no"]
    let payload = Dictionary<String, Any>()
    guard PKPaymentAuthorizationViewController.canMakePayments() else {
        return nil
    }
    guard #available(iOS 10, *) else {
        return nil
    }
    if PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [PKPaymentNetwork.amex]) {
        print("can make amex")
        methods["amex"] = "yes"
        mar.insert("visa", at: mar.count)
    }
    if PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [PKPaymentNetwork.visa]) {
        print("can make visa")
        methods["visa"] = "yes"
        mar.insert("visa", at: mar.count)
    }
    if PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [PKPaymentNetwork.masterCard]) {
        print("can make mastercard")
        methods["mastercard"] = "yes"
        mar.insert("mastercard", at: mar.count)
    }
    if PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [PKPaymentNetwork.interac]) {
        print("can make interac")
        methods["interac"] = "yes"
        mar.insert("interac", at: mar.count)
    }
    guard mar.isEmpty else {
        return payload
    }
    return nil
}

It should only return cards which are usable in-App. And of course you can add any other payment method, or make an array of the methods you want and run through it with a for loop too.

jlmurph
  • 1,050
  • 8
  • 17