feat(ios): updates after fixing in xcode
This commit is contained in:
parent
80914bdede
commit
abc2950279
22
plugin.xml
22
plugin.xml
@ -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/StripeAPIClient.swift" />
|
||||||
<source-file src="src/ios/AppDelegate.swift" />
|
<source-file src="src/ios/StripePaymentOptions.swift" />
|
||||||
<source-file src="src/ios/PaymentOptions.swift" />
|
<source-file src="src/ios/StripePaymentsPluginConfig.swift" />
|
||||||
<source-file src="src/ios/PluginConfig.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"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1 +0,0 @@
|
|||||||
#import <Cordova/CDV.h>
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
27
src/ios/StripePaymentsPluginConfig.swift
Normal file
27
src/ios/StripePaymentsPluginConfig.swift
Normal file
@ -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…
x
Reference in New Issue
Block a user