feat(ios): updates after fixing in xcode

pull/2/merge
codinronan 5 years ago
parent 80914bdede
commit abc2950279

@ -54,20 +54,20 @@
</feature> </feature>
</config-file> </config-file>
<framework src="Stripe" type="podspec" spec="~> 15.0.0" /> <!-- <framework src="Stripe" type="podspec" spec="~> 15.0.0" />
<framework src="Alamofire" type="podspec" spec="~> 5.0.0-beta.3" /> <framework src="Alamofire" type="podspec" spec="~> 4.8.1" />
<framework src="CardIO" type="podspec" spec="~> 5.4.1" /> -->
<!-- https://github.com/cordova-develop/cordova-plugin-pods3/blob/master/plugin.xml --> <!-- https://github.com/cordova-develop/cordova-plugin-pods3/blob/master/plugin.xml -->
<!-- <pods use-frameworks="true"> <pods use-frameworks="true">
<pod name="Stripe" spec="" /> <pod name="Stripe" spec="~> 15.0.0" />
<pod name="Alamofire" spec="" /> <pod name="CardIO" spec="~> 5.4.1" />
</pods> --> <pod name="Alamofire" spec="~> 4.8.1" />
</pods>
<source-file src="src/ios/APIClient.swift" />
<source-file src="src/ios/AppDelegate.swift" /> <source-file src="src/ios/StripeAPIClient.swift" />
<source-file src="src/ios/PaymentOptions.swift" /> <source-file src="src/ios/StripePaymentOptions.swift" />
<source-file src="src/ios/PluginConfig.swift" /> <source-file src="src/ios/StripePaymentsPluginConfig.swift" />
<source-file src="src/ios/StripePaymentsPlugin.swift" /> <source-file src="src/ios/StripePaymentsPlugin.swift" />
<header-file type="BridgingHeader" src="src/ios/StripePaymentsPlugin-Bridging-Header.h" />
<!-- <framework src="Foundation.framework" /> --> <!-- <framework src="Foundation.framework" /> -->
</platform> </platform>

@ -1,6 +1,5 @@
import UIKit import UIKit
import Stripe
// For Cordova, we can create an AppDelegate extension: // For Cordova, we can create an AppDelegate extension:
// https://stackoverflow.com/a/29288792 // https://stackoverflow.com/a/29288792

@ -1,22 +0,0 @@
import Alamofire
public class StripePaymentsPluginConfig {
public var publishableKey: String? = nil
public var ephemeralKeyUrl: String? = nil
public var appleMerchantId: String? = nil
public var companyName: String? = nil
public var requestPaymentImmediately: Boolean? = true
public var extraHTTPHeaders: [HTTPHeader]? = []
// 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,
// meaning that the success/fail return value becomes meaningful.
// The extraHTTPHeaders now allows us to do that, to be done later..
// TODO need xcode for this
func parseExtraHeaders(dict: [String:String]) {
// extraHTTPHeaders.push(new HTTPHeader(dict[something]))
}
}
let PluginConfig = StripePaymentsPluginConfig()

@ -1,9 +1,9 @@
import Alamofire import Alamofire
import Stripe import Stripe
class APIClient: NSObject, STPCustomerEphemeralKeyProvider { class StripeAPIClient: NSObject, STPCustomerEphemeralKeyProvider {
static let shared = APIClient() static let shared = StripeAPIClient()
var ephemeralKeyUrl = "" var ephemeralKeyUrl = ""

@ -1,15 +1,15 @@
public struct PaymentOptions { public struct StripePaymentOptions {
// must be in smallest unit e.g. 1000 for $10.00 // must be in smallest unit e.g. 1000 for $10.00
public var price: UInt32 = 0 public var price: Int = 0
// 'USD', 'MXN', 'JPY', 'GBP' etc. uppercase. // 'USD', 'MXN', 'JPY', 'GBP' etc. uppercase.
public var currency: String = "USD" public var currency: String = "USD"
// 'US', 'PH', the ISO 2-letter code, uppercase. // 'US', 'PH', the ISO 2-letter code, uppercase.
public var country: String = "US" public var country: String = "US"
init(dict: [String:Any]) { init(dict: [String:Any]) {
price = dict["price"] as? UInt32 ?? 0 price = dict["price"] as? Int ?? 0
currency = dict["currency"] as? String ?? "USD" currency = dict["currency"] as? String ?? "USD"
country = dict["country"] as? String ?? "US" country = dict["country"] as? String ?? "US"
} }
} }

@ -12,9 +12,9 @@ import Stripe
@objc(StripePaymentsPlugin) class StripePaymentsPlugin: CDVPlugin, STPPaymentContextDelegate { @objc(StripePaymentsPlugin) class StripePaymentsPlugin: CDVPlugin, STPPaymentContextDelegate {
private var paymentStatusCallback: String? = nil private var paymentStatusCallback: String = ""
private let customerContext: STPCustomerContext private var customerContext: STPCustomerContext!
private let paymentContext: STPPaymentContext private var paymentContext: STPPaymentContext!
override func pluginInitialize() { override func pluginInitialize() {
super.pluginInitialize() super.pluginInitialize()
@ -27,8 +27,8 @@ import Stripe
// MARK: Init Method // MARK: Init Method
@objc(init:) @objc(beginStripe:)
public func init(command: CDVInvokedUrlCommand) { public func beginStripe(command: CDVInvokedUrlCommand) {
let error = "The Stripe Publishable Key and ephemeral key generation URL are required" let error = "The Stripe Publishable Key and ephemeral key generation URL are required"
guard let dict = command.arguments[0] as? [String:Any] ?? nil else { guard let dict = command.arguments[0] as? [String:Any] ?? nil else {
@ -43,10 +43,10 @@ import Stripe
PluginConfig.ephemeralKeyUrl = dict["ephemeralKeyUrl"] as? String ?? "" PluginConfig.ephemeralKeyUrl = dict["ephemeralKeyUrl"] as? String ?? ""
PluginConfig.appleMerchantId = dict["appleMerchantId"] as? String ?? "" PluginConfig.appleMerchantId = dict["appleMerchantId"] as? String ?? ""
PluginConfig.companyName = dict["companyName"] as? String ?? "" PluginConfig.companyName = dict["companyName"] as? String ?? ""
PluginConfig.requestPaymentImmediately = dict["requestPaymentImmediately"] as? Boolean ?? true PluginConfig.requestPaymentImmediately = dict["requestPaymentImmediately"] as? Bool ?? true
if headersDict = dict["extraHTTPHeaders"] as? [String:String] { if let headersDict = dict["extraHTTPHeaders"] as? [String:String] {
PluginConfig.parseExtraHeaders(headersDict) PluginConfig.parseExtraHeaders(dict: headersDict)
} }
if !self.verifyConfig() { if !self.verifyConfig() {
@ -54,7 +54,7 @@ import Stripe
return return
} }
APIClient.shared.ephemeralKeyUrl = PluginConfig.ephemeralKeyUrl StripeAPIClient.shared.ephemeralKeyUrl = PluginConfig.ephemeralKeyUrl
STPPaymentConfiguration.shared().companyName = PluginConfig.companyName STPPaymentConfiguration.shared().companyName = PluginConfig.companyName
STPPaymentConfiguration.shared().publishableKey = PluginConfig.publishableKey STPPaymentConfiguration.shared().publishableKey = PluginConfig.publishableKey
@ -62,7 +62,7 @@ import Stripe
STPPaymentConfiguration.shared().appleMerchantIdentifier = PluginConfig.appleMerchantId STPPaymentConfiguration.shared().appleMerchantIdentifier = PluginConfig.appleMerchantId
} }
customerContext = STPCustomerContext(keyProvider: APIClient.shared) customerContext = STPCustomerContext(keyProvider: StripeAPIClient.shared)
paymentContext = STPPaymentContext(customerContext: customerContext) paymentContext = STPPaymentContext(customerContext: customerContext)
paymentContext.delegate = self paymentContext.delegate = self
@ -90,18 +90,24 @@ import Stripe
return return
} }
let paymentOptions = PaymentOptions(options) let paymentOptions = PaymentOptions(dict: options)
paymentContext.paymentAmount = paymentOptions.price paymentContext.paymentAmount = paymentOptions.price
paymentContext.paymentCurrency = paymentOptions.currency paymentContext.paymentCurrency = paymentOptions.currency
paymentContext.paymentCountry = paymentOptions.country 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)
}
// This dialog collects a payment method from the user. When they close it, you get a context // 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 // 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 // has been created from the payment method. All that has happened is the user entered
// payment data and clicked 'ok'. That's all. // payment data and clicked 'ok'. That's all.
// After that dialog closes - after paymentContextDidChange is called with // After that dialog closes - after paymentContextDidChange is called with
// a selectedPaymentMethod - THEN you want to call requestPayment. // a selectedPaymentMethod - THEN you want to call requestPayment.
paymentContext.presentPaymentMethodsViewController() paymentContext.presentPaymentOptionsViewController()
successCallback(command.callbackId, [ "status": "PAYMENT_DIALOG_SHOWN" ]) successCallback(command.callbackId, [ "status": "PAYMENT_DIALOG_SHOWN" ])
} }
@ -126,57 +132,58 @@ import Stripe
// MARK: STPPaymentContextDelegate // MARK: STPPaymentContextDelegate
func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) { func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
let alertController = UIAlertController( var message = error.localizedDescription
preferredStyle: .alert,
retryHandler: { (action) in
// Retry payment context loading
paymentContext.retryLoading()
}
)
var message = error?.localizedDescription ?? ""
var callbackMessage: String = "" var callbackMessage: String = ""
if let customerKeyError = error as? APIClient.CustomerKeyError { if let customerKeyError = error as? StripeAPIClient.CustomerKeyError {
switch customerKeyError { switch customerKeyError {
case .ephemeralKeyUrl: case .ephemeralKeyUrl:
// Fail silently until base url string is set // Fail silently until base url string is set
callbackMessage = "[ERROR]: Please assign a value to `APIClient.shared.ephemeralKeyUrl` before continuing. See `StripePaymentsPlugin.swift`." callbackMessage = "[ERROR]: Please assign a value to `StripeAPIClient.shared.ephemeralKeyUrl` before continuing. See `StripePaymentsPlugin.swift`."
case .invalidResponse: case .invalidResponse:
// Use customer key specific error message // Use customer key specific error message
callbackMessage = "[ERROR]: Missing or malformed response when attempting to call `APIClient.shared.createCustomerKey`. Please check internet connection and backend response." callbackMessage = "[ERROR]: Missing or malformed response when attempting to call `StripeAPIClient.shared.createCustomerKey`. Please check internet connection and backend response."
message = "Could not retrieve customer information" message = "Could not retrieve customer information"
} }
} }
else { else {
// Use generic error message // Use generic error message
callbackMessage = "[ERROR]: Unrecognized error while loading payment context: \(error)" callbackMessage = "[ERROR]: Unrecognized error while loading payment context: \(error.localizedDescription)"
message = error.localizedDescription ?? "Could not retrieve payment information" message = "Could not retrieve payment information"
} }
print(callbackMessage) print(callbackMessage)
errorCallback(paymentStatusCallback, ["error": callbackMessage], keepCallback: true) errorCallback(paymentStatusCallback, ["error": callbackMessage], keepCallback: true)
alertController.setMessage(message) // ?? 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) self.viewController.present(alertController, animated: true, completion: nil)
} }
func paymentContextDidChange(_ paymentContext: STPPaymentContext) { func paymentContextDidChange(_ paymentContext: STPPaymentContext) {
var isLoading = paymentContext.isLoading let isLoading = paymentContext.loading
var isPaymentReady = paymentContext.selectedPaymentMethod != nil let isPaymentReady = paymentContext.selectedPaymentOption != nil
var label = "" var label = ""
var image = "" var image = ""
// https://stackoverflow.com/questions/11592313/how-do-i-save-a-uiimage-to-a-file // https://stackoverflow.com/questions/11592313/how-do-i-save-a-uiimage-to-a-file
if selectedPaymentMethod = paymentContext.selectedPaymentMethod { if let selectedPaymentOption = paymentContext.selectedPaymentOption {
label = selectedPaymentMethod.label label = selectedPaymentOption.label
image = "" image = ""
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let filePath = paths.first?.appendingPathComponent("StripePaymentMethod.jpg") { if let filePath = paths.first?.appendingPathComponent("StripePaymentMethod.jpg") {
// Save image. // Save image.
do { do {
try UIImageJPEGRepresentation(selectedPaymentMethod.image, 1)?.write(to: filePath, options: .atomic) try selectedPaymentOption.image.jpegData(compressionQuality: 1)?.write(to: filePath, options: .atomic)
image = filePath image = filePath.absoluteString
} }
catch { } catch { }
} }
@ -230,11 +237,9 @@ import Stripe
case .error: case .error:
// Use generic error message // Use generic error message
print("[ERROR]: Unrecognized error while finishing payment: \(String(describing: error))"); print("[ERROR]: Unrecognized error while finishing payment: \(String(describing: error))");
self.viewController.present(UIAlertController(message: "Could not complete payment"), animated: true)
resultMsg = [ resultMsg = [
"status": "PAYMENT_COMPLETED_ERROR", "status": "PAYMENT_COMPLETED_ERROR",
error: "[ERROR]: Unrecognized error while finishing payment: \(String(describing: error))" "error": "[ERROR]: Unrecognized error while finishing payment: \(String(describing: error))"
] ]
errorCallback(paymentStatusCallback, resultMsg, keepCallback: true) errorCallback(paymentStatusCallback, resultMsg, keepCallback: true)
@ -247,26 +252,25 @@ import Stripe
} }
func successCallback(_ callbackId: String, _ data: [String:Any?], keepCallback: Bool = false) { func successCallback(_ callbackId: String, _ data: [String:Any?], keepCallback: Bool = false) {
var pluginResult = CDVPluginResult( let pluginResult = CDVPluginResult(
status: .ok, status: .ok,
messageAs: data messageAs: data as [AnyHashable : Any]
) )
pluginResult?.setKeepCallbackAs(keepCallback) pluginResult?.setKeepCallbackAs(keepCallback)
self.commandDelegate!.send(pluginResult, callbackId: callbackId) self.commandDelegate!.send(pluginResult, callbackId: callbackId)
} }
func errorCallback(_ callbackId: String, _ data: [String:Any?], keepCallback: Bool = false) { func errorCallback(_ callbackId: String, _ data: [String:Any?], keepCallback: Bool = false) {
var pluginResult = CDVPluginResult( let pluginResult = CDVPluginResult(
status: .error, status: .error,
messageAs: data messageAs: data as [AnyHashable : Any]
) )
pluginResult?.setKeepCallbackAs(keepCallback) pluginResult?.setKeepCallbackAs(keepCallback)
self.commandDelegate!.send(pluginResult, callbackId: callbackId) self.commandDelegate!.send(pluginResult, callbackId: callbackId)
} }
func verifyConfig() -> Bool { func verifyConfig() -> Bool {
return PluginConfig.publishableKey != nil && !PluginConfig.publishableKey!.isEmpty return !PluginConfig.publishableKey.isEmpty && !PluginConfig.ephemeralKeyUrl.isEmpty
&& PluginConfig.ephemeralKeyUrl != nil && !PluginConfig.ephemeralKeyUrl!.isEmpty
} }
} }

@ -0,0 +1,27 @@
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,
// meaning that the success/fail return value becomes meaningful.
// The extraHTTPHeaders now allows us to do that, to be done later..
public class StripePaymentsPluginConfig {
public var publishableKey: String = ""
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.
}
}
let PluginConfig = StripePaymentsPluginConfig()

@ -19,7 +19,7 @@ var paymentStatusCallbackProcessor = function (state) {
* @param {object} config {publishableKey, ephemeralKeyUrl, appleMerchantId, companyName} * @param {object} config {publishableKey, ephemeralKeyUrl, appleMerchantId, companyName}
*/ */
StripePaymentsPlugin.prototype.init = function (config, successCallback, errorCallback) { StripePaymentsPlugin.prototype.init = function (config, successCallback, errorCallback) {
exec(successCallback, errorCallback, 'StripePaymentsPlugin', 'init', [config]); exec(successCallback, errorCallback, 'StripePaymentsPlugin', 'beginStripe', [config]);
}; };
/** /**

Loading…
Cancel
Save