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:
- Integrate the Braintree iOS SDK into your app
- Create, verify, and link your PayPal account in the Braintree Control Panel
Setup for app switch
To handle workflows that involve switching to another app or SFSafariViewController
for authentication, you must register a URL type and configure your app to handle return URLs.
Register a URL type
- In Xcode, click on your project in the Project Navigator and navigate to App Target > Info > URL Types
- Click [+] to add a new URL type
- 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 becom.your-company.your-app.payments
.
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.
Set your return URL
In your AppDelegate's application:didFinishLaunchingWithOptions:
implementation, use setReturnURLScheme:
with the value you set above.
For example:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[BTAppSwitch setReturnURLScheme:@"com.your-company.your-app.payments"];
return YES;
}
Handle app switch
Then pass the payment authorization URL to Braintree for finalization.
If you're using UISceneDelegate
(introduced in iOS 13), call BTAppSwitch
's handleOpenURLContext
method from within the scene:openURLContexts
scene delegate method.
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
for (UIOpenURLContext *urlContext in URLContexts) {
NSURL *url = [urlContext URL];
if ([url.scheme localizedCaseInsensitiveCompare:@"com.my-app.your-app.payments"] == NSOrderedSame) {
[BTAppSwitch handleOpenURLContext:urlContext];
}
}
}
Otherwise, if you aren't using UISceneDelegate
, call BTAppSwitch
's handleOpenURL
method from within the application:openURL:options
app delegate method.
- (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;
}
Showing a PayPal button
Using our Drop-in UI
If you plan to use the Vault flow, you can use our Drop-in UI. This UI will show a PayPal payment option 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.
#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 anSFSafariViewController
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:
#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:
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:
// 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.
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.