Search code examples
iosobjective-cviewcontrollerbraintree

Braintree Drop In UI view is not in the window hierarchy


Hi I am attempting to add in Braintrees drop In UI. I am following their guide on their website and have successfully added their cocoa pods to my project. I am now attempting to test out their Drop in UI. However when I attempt to execute the example code I get the following error.

Warning: Attempt to present <UINavigationController: 0x7dc09a00> 
on <CheckOutViewController: 0x7c26ca20>
whose view is not in the window hierarchy!

Here is my source code I'm using

#import "CheckOutViewController.h"
#import "BraintreeCore.h"
#import "BraintreeUI.h"

@interface CheckOutViewController ()<BTDropInViewControllerDelegate>
@property (nonatomic, strong) BTAPIClient *braintreeClient;
@end

 @implementation CheckOutViewController

 - (void)viewDidLoad {
[super viewDidLoad];


    // TODO: Switch this URL to your own authenticated API
  /*  NSURL *clientTokenURL = [NSURL URLWithString:@"https://braintree-sample-merchant.herokuapp.com/client_token"];
    NSMutableURLRequest *clientTokenRequest = [NSMutableURLRequest requestWithURL:clientTokenURL];
    [clientTokenRequest setValue:@"text/plain" forHTTPHeaderField:@"Accept"];

    [[[NSURLSession sharedSession] dataTaskWithRequest:clientTokenRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // TODO: Handle errors
   */
        NSString *clientToken = [[NSString alloc] init];
clientToken = @"eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiJiMzJlMDJmNmJkNjNkM2M5MzY2ZDg0YzEyNmI3ZDIyNmE0YTJjZDliYTQ1ZWNlYjk5ZGE5ZTY3NTlkOTAzYTgyfGNyZWF0ZWRfYXQ9MjAxNi0wMi0xOFQwNToxNDowOS44NzM0MDUzNTUrMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIn0sInRocmVlRFNlY3VyZUVuYWJsZWQiOnRydWUsInRocmVlRFNlY3VyZSI6eyJsb29rdXBVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi90aHJlZV9kX3NlY3VyZS9sb29rdXAifSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0=";

NSLog(@"here we go again");
    self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
        // As an example, you may wish to present our Drop-in UI at this point.
        // Continue to the next section to learn more...
   // }] resume];

NSLog(@"HMM");
[self here];

}
 -(void)here{
    BTDropInViewController *dropInViewController = [[BTDropInViewController alloc]
                                                initWithAPIClient:self.braintreeClient];
dropInViewController.delegate = self;

// This is where you might want to customize your view controller (see below)

// The way you present your BTDropInViewController instance is up to you.
// In this example, we wrap it in a new, modally-presented navigation controller:
UIBarButtonItem *item = [[UIBarButtonItem alloc]
                         initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
                         target:self
                         action:@selector(userDidCancelPayment)];
dropInViewController.navigationItem.leftBarButtonItem = item;
UINavigationController *navigationController = [[UINavigationController alloc]
                                                initWithRootViewController:dropInViewController];
[self presentViewController:navigationController animated:YES completion:nil];
}
- (void)userDidCancelPayment {
[self dismissViewControllerAnimated:YES completion:nil];
}

- (void)dropInViewController:(BTDropInViewController *)viewController
 didSucceedWithTokenization:(BTPaymentMethodNonce *)paymentMethodNonce {
// Send payment method nonce to your server for processing
[self postNonceToServer:paymentMethodNonce.nonce];
[self dismissViewControllerAnimated:YES completion:nil];
}

- (void)postNonceToServer:(NSString *)paymentMethodNonce {
// Update URL with your server
NSURL *paymentURL = [NSURL URLWithString:@"https://your-server.example.com/checkout"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:paymentURL];
request.HTTPBody = [[NSString stringWithFormat:@"payment_method_nonce=%@", paymentMethodNonce] dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";

[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    // TODO: Handle success and failure
}] resume];
}
@end

Can anyone help explain how I fix this problem?

Here is Braintrees documentation I am following

https://developers.braintreepayments.com/start/hello-client/ios/v4#present-drop-in-ui


Solution

  • The problem can be rectified by presenting the view controller outside the super viewDidLoad method

    Specifically viewDidAppear:

     override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            showDropIn(clientTokenOrTokenizationKey: clientToken)
        }