The PayPal authorization flow includes PayPal One Touch™, which allows customers to pay by switching to the PayPal website. After account authentication and payment authorization, customers are returned back to your app.

Setup

Before you can add PayPal:

  1. Integrate the Braintree iOS SDK into your app
  2. Create, verify, and link your PayPal account in the Braintree Control Panel

Setup for app switch

To handle payments that involve switching to another app or SFSafariViewController for authentication, you must register a URL type and configure your app to return from app switches.

Register a URL type

  1. In Xcode, click on your project in the Project Navigator and navigate to App Target > Info > URL Types
  2. Click [+] to add a new URL type
  3. Under URL Schemes, enter your app switch return URL scheme. This scheme must start with your app's Bundle ID and be dedicated to Braintree app switch returns. For example, if the app bundle ID is com.your-company.Your-App, then your URL scheme could be com.your-company.Your-App.payments.
important

If you have multiple app targets, be sure to add the return URL type for all of the targets.

Testing the URL type

You can test out your new URL scheme by opening up a URL that starts with it (e.g. com.your-company.Your-App.payments://test) in Mobile Safari on your iOS Device or Simulator.

In addition, always test your app switching on a real device.

Update your application delegate

In your AppDelegate's application:didFinishLaunchingWithOptions: implementation, use setReturnURLScheme: with the value you set above.

For example:

Objective-C Swift
Click to copy
Copied
#import "AppDelegate.h"
#import "BraintreeCore.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [BTAppSwitch setReturnURLScheme:@"com.your-company.Your-App.payments"];
    return YES;
}

Then in your application delegate, pass the payment authorization URL to Braintree for finalization:

Objective-C Swift
Click to copy
Copied
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.payments"] == NSOrderedSame) {
        return [BTAppSwitch handleOpenURL:url options:options];
    }
    return NO;
}

// If you support iOS 7 or 8, add the following method.
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.payments"] == NSOrderedSame) {
        return [BTAppSwitch handleOpenURL:url sourceApplication:sourceApplication];
    }
    return NO;
}

Showing a PayPal button

Using our Drop-in UI

If you plan to use the Vault flow, you can use our boilerplate UI and code for accepting payments from PayPal. This UI will show a PayPal button alongside any other payment methods you've enabled.

For more details, see the Drop-in UI guide.

Using a custom UI

You can implement a custom UI, such as your own PayPal button.

Objective-C Swift
Click to copy
Copied
#import "BraintreePayPal.h"

- (void)viewDidLoad {
    [super viewDidLoad];

    self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:@"<#CLIENT_AUTHORIZATION#>"];

    UIButton *customPayPalButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 120)];
    [customPayPalButton addTarget:self
                           action:@selector(customPayPalButtonTapped:)
                 forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:customPayPalButton];
}

- (IBAction)customPayPalButtonTapped:(id)sender {
    BTPayPalDriver *payPalDriver = [[BTPayPalDriver alloc] initWithAPIClient:self.braintreeClient];
    payPalDriver.viewControllerPresentingDelegate = self;
    payPalDriver.appSwitchDelegate = self; // Optional

    // Start the Vault flow, or...
    [payPalDriver authorizeAccountWithCompletion:^(BTPayPalAccountNonce *tokenizedPayPalAccount, NSError *error) {
        ...
    }];

    // ...start the Checkout flow
    BTPayPalRequest *request = [[BTPayPalRequest alloc] initWithAmount:@"1.00"];
    [payPalDriver requestOneTimePayment:request
                            completion:^(BTPayPalAccountNonce *tokenizedPayPalAccount, NSError *error) {
        ...
    }];
}

Implementing delegate protocols

BTPayPalDriver has two delegates:

  • viewControllerPresentingDelegate: a required delegate that is responsible for presenting and dismissing an SFSafariViewController on iOS 9+ devices.
  • appSwitchDelegate: an optional delegate that receives messages when switching to the PayPal website via Mobile Safari. This can be used to present/dismiss a loading activity indicator.

Here is an example:

Objective-C Swift
Click to copy
Copied
#pragma mark - BTViewControllerPresentingDelegate

// Required
- (void)paymentDriver:(id)paymentDriver
requestsPresentationOfViewController:(UIViewController *)viewController {
    [self presentViewController:viewController animated:YES completion:nil];
}

// Required
- (void)paymentDriver:(id)paymentDriver
requestsDismissalOfViewController:(UIViewController *)viewController {
    [viewController dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - BTAppSwitchDelegate

// Optional - display and hide loading indicator UI
- (void)appSwitcherWillPerformAppSwitch:(id)appSwitcher {
    [self showLoadingUI];

    // You may also want to subscribe to UIApplicationDidBecomeActiveNotification
    // to dismiss the UI when a customer manually switches back to your app since
    // the payment button completion block will not be invoked in that case (e.g.
    // customer switches back via iOS Task Manager)
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(hideLoadingUI:)
                                              name:UIApplicationDidBecomeActiveNotification
                                             object:nil];
}

- (void)appSwitcherWillProcessPaymentInfo:(id)appSwitcher {
    [self hideLoadingUI:nil];
}

#pragma mark - Private methods

- (void)showLoadingUI {
    ...
}

- (void)hideLoadingUI:(NSNotification *)notification {
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIApplicationDidBecomeActiveNotification
                                                  object:nil];
    ....
}

Collecting additional data

You can gather additional data about your customers as they complete the payment process.

Billing address

To collect billing addresses you will need to enable the PayPal Billing Address Request feature in your PayPal account. To enable this feature, contact PayPal.

When using the Checkout flow, you will receive the billing address via BTPayPalAccountNonce's billingAddress property:

Objective-C Swift
Click to copy
Copied
BTPayPalDriver *payPalDriver = [[BTPayPalDriver alloc] initWithAPIClient:self.braintreeClient];
payPalDriver.viewControllerPresentingDelegate = self;
payPalDriver.appSwitchDelegate = self; // Optional

BTPayPalRequest *request = [[BTPayPalRequest alloc] initWithAmount:@"1.00"];

[payPalDriver requestOneTimePayment:request completion:^(BTPayPalAccountNonce *tokenizedPayPalAccount, NSError *error) {
    if (tokenizedPayPalAccount) {
        NSLog(@"Got a nonce! %@", tokenizedPayPalAccount.nonce);
        BTPostalAddress *address = tokenizedPayPalAccount.billingAddress;
        NSLog(@"Billing address:\n%@\n%@\n%@ %@\n%@ %@", address.streetAddress, address.extendedAddress, address.locality, address.region, address.postalCode, address.countryCodeAlpha2);
    } else if (error) {
        // Handle error
    } else {
        // User canceled
    }
}];

If you are using the Vault flow, you can request the billing address by specifying the address scope during the account authorization flow. If a credit card is not the underlying funding source of the transaction, the billing address will not be returned; instead, the customer's primary account address will be returned via BTPayPalAccountNonce's shippingAddress property:

Objective-C Swift
Click to copy
Copied
// Initiate Vault flow
BTPayPalDriver *payPalDriver = [[BTPayPalDriver alloc] initWithAPIClient:self.braintreeClient];
payPalDriver.viewControllerPresentingDelegate = self;
payPalDriver.appSwitchDelegate = self; // Optional

[payPalDriver authorizeAccountWithAdditionalScopes:[NSSet setWithArray:@[@"address"]]
                                        completion:^(BTPayPalAccountNonce *tokenizedPayPalAccount, NSError *error) {
    if (tokenizedPayPalAccount) {
        BTPostalAddress *address = tokenizedPayPalAccount.billingAddress ?: tokenizedPayPalAccount.shippingAddress;
        NSLog(@"Address:\n%@\n%@\n%@ %@\n%@ %@", address.streetAddress, address.extendedAddress, address.locality,
              address.region, address.postalCode, address.countryCodeAlpha2);
    } else if (error) {
        // Handle error
    } else {
        // User canceled
    }
}];

If a credit card is not the underlying funding source of the transaction, the customer's primary account address will be returned instead.

note

See Braintree iOS Client SDK PayPal header files for in-depth documentation and additional custom PayPal integration options.

Next: Choose your integration

The rest of your configuration will be determined by how you'd like to use PayPal.

  • Want easy payments for repeat customers? Have a subscription model? Use our Vault.
  • Want a one-time payment checkout? Use Checkout with PayPal.

See a detailed comparison of Vault vs. Checkout.

Still have questions?

If you can’t find an answer, contact our Support team.