BTPaymentFlowDriver.m 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #import "BTPaymentFlowDriver_Internal.h"
  2. #import <SafariServices/SafariServices.h>
  3. #if __has_include(<Braintree/BraintreePaymentFlow.h>) // CocoaPods
  4. #import <Braintree/BTPaymentFlowRequest.h>
  5. #import <Braintree/BTPaymentFlowResult.h>
  6. #import <Braintree/BTLogger_Internal.h>
  7. #import <Braintree/BTAPIClient_Internal.h>
  8. #elif SWIFT_PACKAGE // SPM
  9. #import <BraintreePaymentFlow/BTPaymentFlowRequest.h>
  10. #import <BraintreePaymentFlow/BTPaymentFlowResult.h>
  11. #import "../BraintreeCore/BTLogger_Internal.h"
  12. #import "../BraintreeCore/BTAPIClient_Internal.h"
  13. #else // Carthage
  14. #import <BraintreePaymentFlow/BTPaymentFlowRequest.h>
  15. #import <BraintreePaymentFlow/BTPaymentFlowResult.h>
  16. #import <BraintreeCore/BTLogger_Internal.h>
  17. #import <BraintreeCore/BTAPIClient_Internal.h>
  18. #endif
  19. @interface BTPaymentFlowDriver () <SFSafariViewControllerDelegate>
  20. @property (nonatomic, copy) void (^paymentFlowCompletionBlock)(BTPaymentFlowResult *, NSError *);
  21. @property (nonatomic, strong, nullable) SFSafariViewController *safariViewController NS_AVAILABLE_IOS(9_0);
  22. @property (nonatomic, strong, nullable) id<BTPaymentFlowRequestDelegate> paymentFlowRequestDelegate;
  23. @property (nonatomic, copy, nonnull) NSString *returnURLScheme;
  24. @property (nonatomic, strong, nonnull) BTAPIClient *apiClient;
  25. @end
  26. NSString * const BTPaymentFlowDriverErrorDomain = @"com.braintreepayments.BTPaymentFlowDriverErrorDomain";
  27. @implementation BTPaymentFlowDriver
  28. static BTPaymentFlowDriver *paymentFlowDriver;
  29. + (void)load {
  30. if (self == [BTPaymentFlowDriver class]) {
  31. [[BTAppContextSwitcher sharedInstance] registerAppContextSwitchDriver:self];
  32. }
  33. }
  34. - (instancetype)initWithAPIClient:(BTAPIClient *)apiClient {
  35. if (self = [super init]) {
  36. _apiClient = apiClient;
  37. _returnURLScheme = [BTAppContextSwitcher sharedInstance].returnURLScheme;
  38. }
  39. return self;
  40. }
  41. - (instancetype)init {
  42. return nil;
  43. }
  44. - (void)startPaymentFlow:(BTPaymentFlowRequest<BTPaymentFlowRequestDelegate> *)request completion:(void (^)(BTPaymentFlowResult * _Nullable, NSError * _Nullable))completionBlock {
  45. [self setupPaymentFlow:request completion:completionBlock];
  46. [self.apiClient sendAnalyticsEvent:[NSString stringWithFormat:@"ios.%@.start-payment.selected", [self.paymentFlowRequestDelegate paymentFlowName]]];
  47. [self.paymentFlowRequestDelegate handleRequest:request client:self.apiClient paymentDriverDelegate:self];
  48. }
  49. - (void)setupPaymentFlow:(BTPaymentFlowRequest<BTPaymentFlowRequestDelegate> *)request completion:(void (^)(BTPaymentFlowResult * _Nullable, NSError * _Nullable))completionBlock {
  50. paymentFlowDriver = self;
  51. self.paymentFlowCompletionBlock = completionBlock;
  52. self.paymentFlowRequestDelegate = request;
  53. }
  54. - (void)performSwitchRequest:(NSURL *)appSwitchURL {
  55. [self informDelegatePresentingViewControllerRequestPresent:appSwitchURL];
  56. }
  57. - (void)informDelegatePresentingViewControllerRequestPresent:(NSURL *)appSwitchURL {
  58. if ([self.viewControllerPresentingDelegate respondsToSelector:@selector(paymentDriver:requestsPresentationOfViewController:)]) {
  59. self.safariViewController = [[SFSafariViewController alloc] initWithURL:appSwitchURL];
  60. self.safariViewController.delegate = self;
  61. self.safariViewController.dismissButtonStyle = SFSafariViewControllerDismissButtonStyleCancel;
  62. [self.viewControllerPresentingDelegate paymentDriver:self requestsPresentationOfViewController:self.safariViewController];
  63. } else {
  64. [[BTLogger sharedLogger] critical:@"Unable to display View Controller to continue payment flow. BTPaymentFlowDriver needs a viewControllerPresentingDelegate<BTViewControllerPresentingDelegate> to be set."];
  65. }
  66. }
  67. - (void)informDelegatePresentingViewControllerNeedsDismissal {
  68. if (self.viewControllerPresentingDelegate != nil && [self.viewControllerPresentingDelegate respondsToSelector:@selector(paymentDriver:requestsDismissalOfViewController:)]) {
  69. [self.viewControllerPresentingDelegate paymentDriver:self requestsDismissalOfViewController:self.safariViewController];
  70. self.safariViewController = nil;
  71. } else {
  72. [[BTLogger sharedLogger] critical:@"Unable to dismiss View Controller to end payment flow. BTPaymentFlowDriver needs a viewControllerPresentingDelegate<BTViewControllerPresentingDelegate> to be set."];
  73. }
  74. }
  75. #pragma mark - App switch
  76. + (void)handleReturnURL:(NSURL *)url {
  77. [paymentFlowDriver handleOpenURL:url];
  78. }
  79. + (BOOL)canHandleReturnURL:(NSURL *)url {
  80. return [paymentFlowDriver.paymentFlowRequestDelegate canHandleAppSwitchReturnURL:url];
  81. }
  82. - (void)handleOpenURL:(NSURL *)url {
  83. [self.apiClient sendAnalyticsEvent:[NSString stringWithFormat:@"ios.%@.webswitch.succeeded", [self.paymentFlowRequestDelegate paymentFlowName]]];
  84. if (self.safariViewController) {
  85. [self informDelegatePresentingViewControllerNeedsDismissal];
  86. }
  87. [self.paymentFlowRequestDelegate handleOpenURL:url];
  88. }
  89. - (void)safariViewControllerDidFinish:(__unused SFSafariViewController *)controller {
  90. [self onPaymentCancel];
  91. }
  92. #pragma mark - BTPaymentFlowDriverDelegate protocol
  93. - (void)onPaymentWithURL:(NSURL *)url error:(NSError *)error {
  94. if (error) {
  95. [self.apiClient sendAnalyticsEvent:[NSString stringWithFormat:@"ios.%@.start-payment.failed", [self.paymentFlowRequestDelegate paymentFlowName]]];
  96. [self onPaymentComplete:nil error:error];
  97. return;
  98. }
  99. [self.apiClient sendAnalyticsEvent:[NSString stringWithFormat:@"ios.%@.webswitch.initiate.succeeded", [self.paymentFlowRequestDelegate paymentFlowName]]];
  100. [self performSwitchRequest:url];
  101. }
  102. - (void)onPaymentCancel {
  103. [self.apiClient sendAnalyticsEvent:[NSString stringWithFormat:@"ios.%@.webswitch.canceled", [self.paymentFlowRequestDelegate paymentFlowName]]];
  104. NSError *error = [NSError errorWithDomain:BTPaymentFlowDriverErrorDomain
  105. code:BTPaymentFlowDriverErrorTypeCanceled
  106. userInfo:@{NSLocalizedDescriptionKey: @"Payment flow was canceled by the user."}];
  107. self.paymentFlowCompletionBlock(nil, error);
  108. paymentFlowDriver = nil;
  109. }
  110. - (void)onPaymentComplete:(BTPaymentFlowResult *)result error:(NSError *)error {
  111. self.paymentFlowCompletionBlock(result, error);
  112. paymentFlowDriver = nil;
  113. }
  114. @end