3

I'm trying to get a shipping address extracted from the ABRecordRef provided by Apple. I have the following but my street is always returning as nil:

ABMultiValueRef addresses = ABRecordCopyValue(abRecordRef, kABPersonAddressProperty);

for (CFIndex index = 0; index < ABMultiValueGetCount(addresses); index++)
{
    CFDictionaryRef properties = ABMultiValueCopyValueAtIndex(addresses, index);
    NSString *street = [(__bridge NSString *)(CFDictionaryGetValue(properties, kABPersonAddressStreetKey)) copy];
    NSLog(@"street: %@", street);
}

What am I doing wrong?

Even when debugging with the following:

- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                  didSelectShippingAddress:(ABRecordRef)customShippingAddress
                                completion:(void (^)(PKPaymentAuthorizationStatus status, NSArray *methods, NSArray *items))completion
{
    NSLog(@"%@", ABRecordCopyValue(customShippingAddress, kABPersonAddressProperty);
    completion(PKPaymentAuthorizationStatusSuccess, ..., ...);
}

I get this with no street:

ABMultiValueRef 0x17227fbc0 with 1 value(s)
    0: Shipping (0x17227fa00) - {
    City = "Marina del Rey";
    Country = "United States";
    State = California;
    ZIP = 90292;
} (0x172447440)

Edit:

I'm also experiencing issues with accessing names and phone attributes:

NSString *name = (__bridge_transfer NSString *)(ABRecordCopyCompositeName(abRecordRef));

NSString *fname = (__bridge_transfer NSString *)ABRecordCopyValue(abRecordRef, kABPersonFirstNameProperty);
NSString *lname = (__bridge_transfer NSString *)ABRecordCopyValue(abRecordRef, kABPersonFirstNameProperty);

if (!name && fname && lname) name = [NSString stringWithFormat:@"%@ %@", fname, lname]; 
NSLog(@"name: %@", name); // nil

This is how the PKPaymentRequest is being created:

PKPaymentRequest *pr = [[PKPaymentRequest alloc] init];    
[pr setMerchantIdentifier:@"********"];
[pr setCountryCode:@"US"];
[pr setCurrencyCode:@"USD"];
[pr setMerchantCapabilities:PKMerchantCapability3DS];
[pr setSupportedNetworks:@[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard]];

[pr setPaymentSummaryItems:[self paymentSummaryItems]];

[pr setRequiredBillingAddressFields:PKAddressFieldAll];
[pr setRequiredShippingAddressFields:PKAddressFieldAll];

[pr setShippingMethods:[self supportedShippingMethods]];
Mohsin Khubaib Ahmed
  • 1,008
  • 16
  • 32
Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232

1 Answers1

8

Turns out Apple's docs on this weren't that great but the issue is that in the delegate callback for paymentAuthorizationViewController:didSelectShippingAddress:completion: a partial address is always returned. The fix is to also set it in the callback from:

- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                       didAuthorizePayment:(PKPayment *)payment
                                completion:(void (^)(PKPaymentAuthorizationStatus))completion
{
    // Use this instead.
    [payment shippingAddress];
}

I also removed a call to setting the required billing addresses (maybe a separate bug).

Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232
  • 1
    Correct. For security purposes, only partial addresses are returned, which is enough to calculate shipping rates to display before the user authenticates a payment. Once authenticated, the user has basically approved access to the full address they provided, otherwise shipping would be impossible. – runmad Nov 07 '15 at 10:13
  • 1
    One thing to keep in mind that Canadian and UK postal codes are not returned as full postal codes (only partial), which may make it harder to calculate shipping rates for these countries with certain carriers. – runmad Nov 07 '15 at 10:14