diff --git a/plugin.xml b/plugin.xml index 06e4c46..b8989a3 100644 --- a/plugin.xml +++ b/plugin.xml @@ -54,22 +54,25 @@ - + - - - - - + - - diff --git a/src/ios/StripeAPIClient.swift b/src/ios/StripeAPIClient.swift index fef1ba0..4622a14 100644 --- a/src/ios/StripeAPIClient.swift +++ b/src/ios/StripeAPIClient.swift @@ -22,20 +22,26 @@ class StripeAPIClient: NSObject, STPCustomerEphemeralKeyProvider { } let parameters: [String: Any] = ["api_version": apiVersion] - let headers: HTTPHeaders = [ + var headers: HTTPHeaders = [ // "Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", "Accept": "application/json" ] - // TODO need xcode for this. + // Assign any extra headers we've been provided. We COULD use Alamofire's custom auth header types, + // but that would require tracking & strongly typing the headers we pass from the app. Too much + // work that is not really necessary. if PluginConfig.extraHTTPHeaders.count > 0 { - // for each HTTPHeader in extraHTTPHeaders - // headers.add(header) + for key: String in PluginConfig.extraHTTPHeaders.keys { + headers[key] = PluginConfig.extraHTTPHeaders[key] + } } + print("[StripePaymentsPlugin](StripeAPIClient).createCustomerKey: requesting key from \(url) with headers: \(headers)") + Alamofire.request(url, method: .post, parameters: parameters, headers: headers) .validate(statusCode: 200..<300) .responseJSON { responseJSON in + print("[StripePaymentsPlugin](StripeAPIClient).createCustomerKey: got server result: \(responseJSON)") switch responseJSON.result { case .success(let json): guard let data = json as? [String: AnyObject] else { @@ -54,5 +60,4 @@ class StripeAPIClient: NSObject, STPCustomerEphemeralKeyProvider { // completion(json, nil) } } - } diff --git a/src/ios/StripePaymentsPlugin.swift b/src/ios/StripePaymentsPlugin.swift index 319cfad..acda3cb 100644 --- a/src/ios/StripePaymentsPlugin.swift +++ b/src/ios/StripePaymentsPlugin.swift @@ -15,6 +15,7 @@ import Stripe private var paymentStatusCallback: String = "" private var customerContext: STPCustomerContext! private var paymentContext: STPPaymentContext! + private var keyRetries: Int = 0 override func pluginInitialize() { super.pluginInitialize() @@ -23,6 +24,11 @@ import Stripe @objc(addPaymentStatusObserver:) func addPaymentStatusObserver(command: CDVInvokedUrlCommand) { paymentStatusCallback = command.callbackId + + let resultMsg = [ + "status": "LISTENER_ADDED" + ] + successCallback(paymentStatusCallback, resultMsg, keepCallback: true) } // MARK: Init Method @@ -43,10 +49,10 @@ import Stripe PluginConfig.ephemeralKeyUrl = dict["ephemeralKeyUrl"] as? String ?? "" PluginConfig.appleMerchantId = dict["appleMerchantId"] as? String ?? "" PluginConfig.companyName = dict["companyName"] as? String ?? "" - PluginConfig.requestPaymentImmediately = dict["requestPaymentImmediately"] as? Bool ?? true + PluginConfig.maximumKeyRetries = dict["maximumKeyRetries"] as? Int ?? 0 if let headersDict = dict["extraHTTPHeaders"] as? [String:String] { - PluginConfig.parseExtraHeaders(dict: headersDict) + PluginConfig.extraHTTPHeaders = headersDict } if !self.verifyConfig() { @@ -62,13 +68,19 @@ import Stripe STPPaymentConfiguration.shared().appleMerchantIdentifier = PluginConfig.appleMerchantId } - customerContext = STPCustomerContext(keyProvider: StripeAPIClient.shared) - paymentContext = STPPaymentContext(customerContext: customerContext) + successCallback(command.callbackId, [ "status": "INIT_SUCCESS" ]) + } - paymentContext.delegate = self - paymentContext.hostViewController = self.viewController + func createPaymentContext() { + if (customerContext == nil || paymentContext == nil) { + customerContext = STPCustomerContext(keyProvider: StripeAPIClient.shared) + paymentContext = STPPaymentContext(customerContext: customerContext) - successCallback(command.callbackId, [ "status": "INIT_SUCCESS" ]) + paymentContext.delegate = self + paymentContext.hostViewController = self.viewController + } + + customerContext.clearCachedCustomer() } @@ -90,17 +102,18 @@ import Stripe return } - let paymentOptions = PaymentOptions(dict: options) - paymentContext.paymentAmount = paymentOptions.price - paymentContext.paymentCurrency = paymentOptions.currency - paymentContext.paymentCountry = paymentOptions.country - // Allow these to be overridden - PluginConfig.requestPaymentImmediately = options["requestPaymentImmediately"] as? Bool ?? PluginConfig.requestPaymentImmediately if let headersDict = options["extraHTTPHeaders"] as? [String:String] { - PluginConfig.parseExtraHeaders(dict: headersDict) + PluginConfig.extraHTTPHeaders = headersDict } + createPaymentContext() + + let paymentOptions = StripePaymentOptions(dict: options) + paymentContext.paymentAmount = paymentOptions.price + paymentContext.paymentCurrency = paymentOptions.currency + paymentContext.paymentCountry = paymentOptions.country + // This dialog collects a payment method from the user. When they close it, you get a context // change event with the payment info. NO charge has been created at that point, NO source // has been created from the payment method. All that has happened is the user entered @@ -120,12 +133,19 @@ import Stripe return } + if (paymentContext == nil || customerContext == nil) { + let error = "[CONFIG]: Config is not set, init() must be called before using plugin" + errorCallback(command.callbackId, [ "status": "REQUEST_PAYMENT_ERROR", "error": error ]) + return + } + doRequestPayment(command.callbackId) } func doRequestPayment(_ callbackId: String) { + keyRetries = 0 + successCallback(callbackId, [ "status": "REQUEST_PAYMENT_STARTED" ], keepCallback: true) paymentContext.requestPayment() - successCallback(callbackId, [ "status": "REQUEST_PAYMENT_STARTED" ]) } @@ -153,19 +173,24 @@ import Stripe } print(callbackMessage) - errorCallback(paymentStatusCallback, ["error": callbackMessage], keepCallback: true) - let alertController = UIAlertController( - title: "", - message: message, - preferredStyle: .alert - ) - let retry = UIAlertAction(title: "Retry", style: .default, handler: { (action) in - // Retry payment context loading - self.paymentContext.retryLoading() - }) - alertController.addAction(retry) - self.viewController.present(alertController, animated: true, completion: nil) + if (keyRetries < PluginConfig.maximumKeyRetries) { + keyRetries += 1 + + let alertController = UIAlertController( + title: "", + message: message, + preferredStyle: .alert + ) + let retry = UIAlertAction(title: "Retry", style: .default, handler: { (action) in + // Retry payment context loading + self.paymentContext.retryLoading() + }) + alertController.addAction(retry) + self.viewController.present(alertController, animated: true, completion: nil) + } else { + errorCallback(paymentStatusCallback, ["error": callbackMessage], keepCallback: true) + } } func paymentContextDidChange(_ paymentContext: STPPaymentContext) { @@ -197,11 +222,8 @@ import Stripe "image": image ] + print("[StripePaymentsPlugin].paymentContextDidChange: \(resultMsg)") successCallback(paymentStatusCallback, resultMsg, keepCallback: true) - - if isPaymentReady && PluginConfig.requestPaymentImmediately { - doRequestPayment(paymentStatusCallback) - } } // This callback is triggered when requestPayment() completes successfully to create a Source. @@ -213,6 +235,7 @@ import Stripe "source": paymentResult.source.stripeID ] + print("[StripePaymentsPlugin].paymentContext.didCreatePaymentResult: \(resultMsg)") successCallback(paymentStatusCallback, resultMsg, keepCallback: true) completion(nil) } @@ -242,12 +265,14 @@ import Stripe "error": "[ERROR]: Unrecognized error while finishing payment: \(String(describing: error))" ] + print("[StripePaymentsPlugin].didFinishWith: \(resultMsg)") errorCallback(paymentStatusCallback, resultMsg, keepCallback: true) return case .userCancellation: resultMsg = [ "status": "PAYMENT_CANCELED" ] } + print("[StripePaymentsPlugin].didFinishWith: \(resultMsg)") successCallback(paymentStatusCallback, resultMsg, keepCallback: true) } @@ -257,6 +282,8 @@ import Stripe messageAs: data as [AnyHashable : Any] ) pluginResult?.setKeepCallbackAs(keepCallback) + + print("[StripePaymentsPlugin](successCallback) sending result to \(callbackId), result: \(String(describing: pluginResult))") self.commandDelegate!.send(pluginResult, callbackId: callbackId) } @@ -266,6 +293,8 @@ import Stripe messageAs: data as [AnyHashable : Any] ) pluginResult?.setKeepCallbackAs(keepCallback) + + print("[StripePaymentsPlugin](errorCallback) sending result to \(callbackId), result: \(data)") self.commandDelegate!.send(pluginResult, callbackId: callbackId) } diff --git a/src/ios/StripePaymentsPluginConfig.swift b/src/ios/StripePaymentsPluginConfig.swift index 3641b54..6825907 100644 --- a/src/ios/StripePaymentsPluginConfig.swift +++ b/src/ios/StripePaymentsPluginConfig.swift @@ -1,5 +1,3 @@ -import Alamofire - // TODO: // We can add an option to execute the charge API-side, in which case // the developer would also need to provide their 'charge' endpoint, @@ -11,17 +9,8 @@ public class StripePaymentsPluginConfig { public var ephemeralKeyUrl: String = "" public var appleMerchantId: String = "" public var companyName: String = "" - public var requestPaymentImmediately: Bool = true - public var extraHTTPHeaders: HTTPHeaders = [:] - - // TODO need xcode for this - func parseExtraHeaders(dict: [String:String]) { - // extraHTTPHeaders.push(new HTTPHeader(dict[something])) - // this actually needs to replace them..dunno. I mean they'll just have - // duplicates and HTTPHeaders should be able to resolve them by updating the header - // if they're already there, using the latest value (later index in array). - // must confirm that works. - } + public var maximumKeyRetries: Int = 0 + public var extraHTTPHeaders: [String:String] = [:] } let PluginConfig = StripePaymentsPluginConfig() diff --git a/www/StripePaymentsPlugin.js b/www/StripePaymentsPlugin.js index c748629..d5641de 100644 --- a/www/StripePaymentsPlugin.js +++ b/www/StripePaymentsPlugin.js @@ -5,8 +5,9 @@ var StripePaymentsPlugin = function () { }; StripePaymentsPlugin._paymentStatusObserverList = []; StripePaymentsPlugin._processFunctionList = function (array, param) { - for (var i = 0; i < array.length; i++) + for (var i = 0; i < array.length; i++) { array[i](param); + } }; var paymentStatusCallbackProcessor = function (state) { @@ -60,15 +61,16 @@ StripePaymentsPlugin.prototype.requestPayment = function (successCallback, error //------------------------------------------------------------------- +var instance = new StripePaymentsPlugin(); if (!window.plugins) { window.plugins = {}; } if (!window.plugins.StripePaymentsPlugin) { - window.plugins.StripePaymentsPlugin = new StripePaymentsPlugin(); + window.plugins.StripePaymentsPlugin = instance; } if (typeof module != 'undefined' && module.exports) { - module.exports = StripePaymentsPlugin; + module.exports = instance; }