我正在使用Xcode 8,Swift 3,NodeJS和Atom
关注Stripe的Standard iOS Integration Guide
https://stripe.com/docs/mobile/ios/standard我在调用paymentContextDidChange
时收到一个简单的本地化错误。
当用户准备选择付款时调用此方法,这反过来允许我调用Stripe的预建UI STPPaymentMethodsViewController
。但我无法调用该功能。相反,我调用的方法didFailToLoadWithError
通常在网络连接错误时发生,或者连接到我的后端时出现问题。
这是我在Xcode中的客户端代码:
// MARK: - STPPaymentContextDelegate
func paymentContextDidChange(_ paymentContext: STPPaymentContext) {
if let paymentMethod = paymentContext.selectedPaymentMethod {
self.paymentRow.detail = paymentMethod.label
}
else {
self.paymentRow.detail = "Select Payment"
}
self.totalRow.detail = self.numberFormatter.string(from: NSNumber(value: Float(self.paymentContext.paymentAmount)/100))!
}
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPErrorBlock) {
MyAPIClient.sharedClient.completeCharge(paymentResult, amount: paymentContext.paymentAmount, completion: completion)
}
func paymentContext(_ paymentContext: STPPaymentContext, didFinishWith status: STPPaymentStatus, error: Error?) {
let title: String
let message: String
switch status {
case .error:
title = "Error ⚠️"
message = error?.localizedDescription ?? "☹️"
case .success:
title = "Success "
message = "You Have Successfully Made a Charge "
case .userCancellation:
return
}
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "Heard", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
let alertController = UIAlertController(
title: "Error ⚠️",
message: error.localizedDescription,
preferredStyle: .alert
)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
_ = self.navigationController?.popViewController(animated: true)
})
let retry = UIAlertAction(title: "Retry", style: .default, handler: { action in
self.paymentContext.retryLoading()
})
alertController.addAction(cancel)
alertController.addAction(retry)
self.present(alertController, animated: true, completion: nil)
}
这是我在XCode中的API适配器
class MyAPIClient: NSObject, STPBackendAPIAdapter {
static let sharedClient = MyAPIClient()
let session: URLSession
var baseURLString: String? = nil
var defaultSource: STPCard? = nil
var sources: [STPCard] = []
override init() {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 5
self.session = URLSession(configuration: configuration)
super.init()
}
func decodeResponse(_ response: URLResponse?, error: NSError?) -> NSError? {
if let httpResponse = response as? HTTPURLResponse
, httpResponse.statusCode != 200 {
return error ?? NSError.networkingError(httpResponse.statusCode)
}
return error
}
func retrieveCustomer(_ completion: @escaping STPCustomerCompletionBlock) {
let userInfo = "Could Not Retrieve Stripe Customer"
guard let key = Stripe.defaultPublishableKey(), !key.contains("#")
else {
let error = NSError(domain: StripeDomain, code: 50, userInfo: [NSLocalizedDescriptionKey: "\(userInfo)"])
completion(nil, error)
print("\(userInfo)")
return
}
guard let baseURLString = baseURLString, let baseURL = URL(string: baseURLString)
else {return}
let path = "/customer"
let url = baseURL.appendingPathComponent(path)
let request = URLRequest.request(url, method: .GET, params: [:])
let task = self.session.dataTask(with: request) { (data, urlResponse, error) in
DispatchQueue.main.async {
let deserializer = STPCustomerDeserializer(data: data, urlResponse: urlResponse, error: error)
if let error = deserializer.error {
completion(nil, error)
return
} else if let customer = deserializer.customer {
completion(customer, nil)
}
}
}
task.resume()
}
func attachSource(toCustomer source: STPSource, completion: @escaping STPErrorBlock) {
guard let baseURLString = baseURLString, let baseURL = URL(string: baseURLString)
else {
if let token = source as? STPToken, let card = token.card {
self.sources.append(card)
self.defaultSource = card
}
completion(nil)
return
}
let path = "/customer/sources"
let url = baseURL.appendingPathComponent(path)
let params = ["source": source.stripeID]
let request = URLRequest.request(url, method: .POST, params: params as [String : AnyObject])
let task = self.session.dataTask(with: request) { (data, urlResponse, error) in
DispatchQueue.main.async {
if let error = self.decodeResponse(urlResponse, error: error as NSError?) {
completion(error)
return
}
completion(nil)
}
}
task.resume()
}
func selectDefaultCustomerSource(_ source: STPSource, completion: @escaping STPErrorBlock) {
guard let baseURLString = baseURLString, let baseURL = URL(string: baseURLString)
else {
if let token = source as? STPToken {
self.defaultSource = token.card
}
completion(nil)
return
}
let path = "/customer/default_source"
let url = baseURL.appendingPathComponent(path)
let params = ["source": source.stripeID]
let request = URLRequest.request(url, method: .POST, params: params as [String : AnyObject])
let task = self.session.dataTask(with: request) { (data, urlResponse, error) in
DispatchQueue.main.async {
if let error = self.decodeResponse(urlResponse, error: error as NSError?) {
completion(error)
return
}
completion(nil)
}
}
task.resume()
}
// MARK: - Complete Charge
func completeCharge(_ result: STPPaymentResult, amount: Int, completion: @escaping STPErrorBlock) {
let userInfo = "Could Not Complete Stripe Customer Charge"
guard let baseURLString = baseURLString, let baseURL = URL(string: baseURLString)
else {
let error = NSError(domain: StripeDomain, code: 50, userInfo: [NSLocalizedDescriptionKey: "\(userInfo)"])
completion(error)
return
}
let path = "charge"
let url = baseURL.appendingPathComponent(path)
let params: [String: Any] = ["source": result.source.stripeID as Any, "amount": amount as Any]
let request = URLRequest.request(url, method: .POST, params: params as [String : AnyObject])
let task = self.session.dataTask(with: request) { (data, urlResponse, error) in
DispatchQueue.main.async {
if let error = self.decodeResponse(urlResponse, error: error as NSError?) {
completion(error)
return
}
completion(nil)
}
}
task.resume()
}
}
这是我在NodeJS中的后端代码
const stripe = require('stripe')('sk_test_....');
const express = require('express');
const app = express();
// Request Token API
const token = request.body.stripeToken;
// Retrieve Customer API
app.get('/customer', function(request, response) {
var customerId = 'cus_...';
stripe.customers.retrieve(customerId, function(err, customer) {
if (err) {
response.status(402).send('Error retrieving customer.');
console.log('Could not retrieve customer');
} else {
response.json(customer);
console.log('Success retrieving customer');
}
})
});
// Attach a new payment source API
app.post('/customer/sources', function(request, response) {
var customerId = 'cus_...';
stripe.customers.createSource(customerId, {
source: request.body.source
}, function(err, source) {
if (err) {
response.status(402).send('Error attaching source.');
console.log('Could not attach new payment source');
} else {
response.status(200).end();
console.log('Success attaching new payment source');
}
});
});
// Select a new default payment source API
app.post('/customer/default_source', function(request, response) {
var customerId = 'cus_...';
stripe.customers.update(customerId, {
default_source: request.body.defaultSource
}, function(err, customer) {
if (err) {
response.status(402).send('Error setting default source.');
console.log('Could not select default payment source');
} else {
response.status(200).end();
console.log('Success selecting default payment source');
}
});
});
非常感谢任何帮助。