我在我的应用程序中使用cyberSource 集成Apple Pay 集成。我这样做是为了什么。
1- 我已经创建了商家 ID 2- 我已经在http://www.cybersource.com/
上创建了测试帐户
3- 我已经下载了适用于 iOS 的网络资源 SDK。
4-我已经设法运行使用 SDK 下载的演示应用程序。
5-当我运行演示应用程序时,我收到了这个错误。
"Transaction Details .Accepted: No .Auth Amount: (null) Error: Unknown error"
我已正确提供我的商家帐户。还有其他字段,我不确定如何获取这些值
static NSString* kMetadataEncodedValue = @"RklEPUNPTU1PTi5MRy5JTkFQUC5QQVlNRU5U";
static NSString* const kPaymentSolutionDefaultValue = @"001";
static NSString* const kEnvTest = @"test";
static NSString* const kEnvLive = @"live";
static NSString* const kKeyMerchantID = @"merchant_otm_eyebuy_acct";
static NSString* const kKeyMerchantExternalID = @"merchant_otm_eyebuy_acct";
static NSString* const kKeyTransactionKey = @"transactionKey";
static NSString* const kKeyEncryptedBlob = @"encryptedBlob";
static NSString* const kKeyEnv = @"env";
- (IBAction)payButtonTouchDown:(id)sender {
[self.amountTextField resignFirstResponder];
NSString* requestType = [self.requestTypeSelection titleForSegmentAtIndex:self.requestTypeSelection.selectedSegmentIndex];
[self updateStatusMessage:[NSString stringWithFormat:@"Submitting %@ request...", requestType]];
self.payButton.enabled = NO;
NSString *amountText = self.amountTextField.text;
NSDecimalNumber *amountValue = [NSDecimalNumber decimalNumberWithString:amountText];
BOOL isDecimal = amountValue!= nil;
if (isDecimal) {
// TODO: Pass in encrypted payment data from PassKit
[self performRequestWithEncryptedPaymentData:self.selectedAccountData[kKeyEncryptedBlob] withPaymentAmount:amountValue];
}
else {
self.payButton.enabled = YES;
self.statusText.text = @"Enter valid Amount";
}
}
- (IBAction)requestTypeSelectionValueChanged:(UISegmentedControl *)sender {
[self updateRequestSelection];
}
-(void) updateRequestSelection {
NSString* requestType = [self.requestTypeSelection titleForSegmentAtIndex:self.requestTypeSelection.selectedSegmentIndex];
[self updateStatusMessage:[NSString stringWithFormat:@"Tap '%@' to %@ request.", self.payButton.currentTitle, requestType]];
}
- (void) updateStatusMessage: (NSString*) message
{
self.statusText.text = message;
self.payButton.enabled = YES;
}
- (void)performRequestWithEncryptedPaymentData: (NSString*) encryptedPaymentData withPaymentAmount: (NSDecimalNumber*) paymentAmount
{
VMposItem *item = [[VMposItem alloc] init];
item.name = NSLocalizedString(@"Item no 1", nil);
item.price = paymentAmount;
VMposTransactionObject *transactionObject = [VMposTransactionObject createTransaction:VMPOS_TRANSACTION_PAYMENT];
[transactionObject addItem:item];
[transactionObject calculateTotals];
// TODO: Encrypted Payment is created by client application based
// on specification from SOAP API. The following values are just place holders
VMposEncryptedPayment* payment = [VMposEncryptedPayment new];
payment.encodedData = encryptedPaymentData;
payment.encodedMetadata = kMetadataEncodedValue;
payment.paymentSolution = kPaymentSolutionDefaultValue;
// Purchase details
VMposPurchaseDetails* purchaseDetails = [VMposPurchaseDetails new];
purchaseDetails.partialIndicator = NO;
// Sample Billing information
VMposAddress* billTo = [VMposAddress new];
billTo.firstName = @"John";
billTo.lastName = @"Doe";
billTo.email = @"john.doe@yahoo.com";
billTo.street1 = @"1234 Pine St.";
billTo.city = @"Redmond";
billTo.state = @"WA";
billTo.postalCode = @"98052";
billTo.country = @"US";
// Save transaction information
transactionObject.encryptedPayment = payment;
transactionObject.purchaseDetails = purchaseDetails;
transactionObject.purchaseDetails.commerceIndicator = @"internet";
transactionObject.transactionCode = @"ref_code_12345678";
transactionObject.billTo = billTo;
// Build fingerprint
//--WARNING!----------------
// Finger print generation requires the transaction key. This should
// be done at the server. It is shown here only for Demo purposes.
NSString* merchantID = self.selectedAccountData[kKeyMerchantID];
NSString* fingerprint = [self buildFingerprintWithTransaction:transactionObject withMerchantId:merchantID];
NSLog(@"Fingerprint: %@", fingerprint);
VMposGateway* gateway = [VMposGateway sharedInstance];
[gateway initSessionWithUserName:merchantID withMerchantId:merchantID withFingerprint: fingerprint withDelegate:self];
if (self.selectedAccountData[kKeyEnv] == kEnvLive) {
[VMposSettings sharedInstance].cybsEnvironment = ENV_LIVE;
}
else
{
[VMposSettings sharedInstance].cybsEnvironment = ENV_TEST;
}
if (self.requestTypeSelection.selectedSegmentIndex == 0)
{
[gateway performAuthorizationWithTransaction:transactionObject withDelegate:self];
}
else
{
[gateway performSaleWithTransaction:transactionObject withDelegate:self];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureAccounts];
[self updateStatusMessage:[NSString stringWithFormat:@"Tap '%@' to submit a test request.", self.payButton.currentTitle]];
self.amountTextField.keyboardType = UIKeyboardTypeDecimalPad;
self.amountTextField.text = @"1.09";
[self.requestTypeSelection setSelectedSegmentIndex:0];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return self.configuredAccounts.count;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSDictionary* rowData = self.configuredAccounts[row];
return [NSString stringWithFormat:@"%@ (%@)", rowData[kKeyMerchantID], rowData[kKeyEnv]];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.selectedAccountData = self.configuredAccounts[row];
}
//! Callback for user session initialization
- (void) didInitUserSession: (VMposUserSession*) paramUserSession withError:(VMposError*)paramError {
}
//! provides feedback from finished authorization transaction request
/*!
\param paramResponseData gateway data retrieved from server (contains information about transaction status)
\param paramError an error if request failed
*/
- (void) authorizationFinishedWithGatewayResponse:(VMposGatewayResponse *)paramResponseData
withError:(VMposError *)paramError {
self.authorized = YES;
[self updateStatusMessageWithResponse: (VMposGatewayResponse *)paramResponseData withError: paramError];
}
//! provides feedback from finished sale request
/*!
\param paramResponseData gateway data retrieved from server (contains information about transaction status)
\param paramError an error if request failed
*/
- (void) saleFinishedWithGatewayResponse:(VMposGatewayResponse *)paramResponseData
withError:(VMposError *)paramError
{
self.authorized = YES;
[self updateStatusMessageWithResponse: (VMposGatewayResponse *)paramResponseData withError: paramError];
}
- (void) updateStatusMessageWithResponse: (VMposGatewayResponse *)paramResponseData withError: (NSError*) paramError
{
NSMutableString* s = [NSMutableString new];
if (paramResponseData)
{
[s appendString: @"\nTransaction Details:"];
[s appendFormat: @"\n * Accepted: %@", paramResponseData.isAccepted ? @"Yes" : @"No"];
[s appendFormat: @"\n * Auth Amount: %@", paramResponseData.authorizedAmount.stringValue];
}
if (paramError)
{
[s appendFormat:@"\nError: %@", paramError.localizedDescription];
}
[self updateStatusMessage:s];
}
/*
----------WARNING!----------------
Finger print generation requires the transaction key. This should
be done at the server. It is shown here only for Demo purposes.
*/
-(NSString*) buildFingerprintWithTransaction: (VMposTransactionObject*) transactionObject withMerchantId: (NSString*) merchantId {
NSDate* dateNow = [NSDate date];
NSString* fingerprintDateString = [MPDemoViewController formatFingerprintDate:dateNow];
NSString* merchantTransKey = self.selectedAccountData[kKeyTransactionKey];
NSString* fgComponents = [NSString stringWithFormat:@"%@%@%@%@%@", [MPDemoViewController stringSha1:merchantTransKey], merchantId, transactionObject.transactionCode, [transactionObject.totalAmount gatewayPriceString], fingerprintDateString];
NSString* hashedFgComponents = [MPDemoViewController stringHmacSha256:fgComponents];
return [NSString stringWithFormat:@"%@#%@", hashedFgComponents, fingerprintDateString];
}
+(NSString*) formatFingerprintDate: (NSDate*) date {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSTimeZone* tz = [NSTimeZone timeZoneWithName:@"UTC"];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
[dateFormatter setTimeZone:tz];
return [dateFormatter stringFromDate:date];
}
+ (NSString *)stringSha1:(NSString *)value
{
const char *cstr = [value cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:value.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
// This is an iOS5-specific method.
// It takes in the data, how much data, and then output format, which in this case is an int array.
CC_SHA1(data.bytes, (uint)data.length, digest);
return [self stringHexEncode:digest withLength:CC_SHA1_DIGEST_LENGTH];
}
+ (NSString *)stringSha256:(NSString *)value
{
const char *cstr = [value cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:value.length];
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
// This is an iOS5-specific method.
// It takes in the data, how much data, and then output format, which in this case is an int array.
CC_SHA256(data.bytes, (uint)data.length, digest);
return [self stringHexEncode:digest withLength:CC_SHA256_DIGEST_LENGTH];
}
+ (NSString *)stringHmacSha256:(NSString *)value
{
CCHmacContext ctx;
const char* utf8ValueString = [value UTF8String];
uint8_t hmacData[CC_SHA256_DIGEST_LENGTH];
CCHmacInit(&ctx, kCCHmacAlgSHA256, utf8ValueString, strlen(utf8ValueString));
CCHmacUpdate(&ctx, utf8ValueString, strlen(utf8ValueString));
CCHmacFinal(&ctx, hmacData);
return [self stringHexEncode:hmacData withLength:CC_SHA256_DIGEST_LENGTH];
}
+(NSString*) stringHexEncode: (uint8_t*) data withLength: (NSInteger) dataLength {
NSMutableString* output = [NSMutableString stringWithCapacity:dataLength * 2];
// Parse through the CC_SHA256 results (stored inside of digest[]).
for(int i = 0; i < dataLength; i++) {
[output appendFormat:@"%02x", data[i]];
}
return output;
}
+ (NSString*)base64forData:(NSData*)theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] ;
}
我可以从哪里得到所有这些值。如果有人列出通过 CyberSource 进行 Apple 支付集成所涉及的所有步骤,我们将不胜感激。另外请不要将我推荐给苹果开发者,因为我已经在 Apple Developer 上阅读了有关 Apple Pay 的详细信息。