银联开放平台: https://open.unionpay.com/ajweb/product/detail?id=3
添加依赖库 3 个
libz
CFNetwork
SystemConfiguration
拖入需要文件
UPPaymentControl.h
libPayMentControl.a
RSA.h
RSA.m
修改配置
1 URL Types - URL Schemes
2 info plist 添加
LSApplicationQueriesSchemes <NSArray>
value - uppaysdk uppaywallet uppayx1 uppayx2 uppayx3
3 other link 添加路径
-force_load $(PROJECT_DIR)/upppay/libPaymentControl.a
4 将使用UPPay 的 VC,修改为 .mm
基本上就 ok 了。
Appdelegate 复制代码
#import "UPPaymentControl.h"
#import "RSA.h"
#import <CommonCrypto/CommonDigest.h>
- (NSString *) readPublicKey:(NSString *) keyName{
if (keyName == nil || [keyName isEqualToString:@""]) return nil;
NSMutableArray *filenameChunks = [[keyName componentsSeparatedByString:@"."] mutableCopy];
NSString *extension = filenameChunks[[filenameChunks count] - 1];
[filenameChunks removeLastObject]; // remove the extension
NSString *filename = [filenameChunks componentsJoinedByString:@"."]; // reconstruct the filename with no extension
NSString *keyPath = [[NSBundle mainBundle] pathForResource:filename ofType:extension];
NSString *keyStr = [NSString stringWithContentsOfFile:keyPath encoding:NSUTF8StringEncoding error:nil];
return keyStr;
}
// 验证 签名
//-(BOOL) verify:(NSString *) resultStr {
//
// //验签证书同后台验签证书
// //此处的verify,商户需送去商户后台做验签
// return NO;
//}
// 验证 本地签名
-(BOOL) verifyLocal:(NSString *) resultStr {
//从NSString转化为NSDictionary
NSData *resultData = [resultStr dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:resultData options:0 error:nil];
//获取生成签名的数据
NSString *sign = data[@"sign"];
NSString *signElements = data[@"data"];
//NSString *pay_result = signElements[@"pay_result"];
//NSString *tn = signElements[@"tn"];
//转换服务器签名数据
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:sign options:0];
//生成本地签名数据,并生成摘要
// NSString *mySignBlock = [NSString stringWithFormat:@"pay_result=%@tn=%@",pay_result,tn];
NSData *dataOriginal = [[self sha1:signElements] dataUsingEncoding:NSUTF8StringEncoding];
//验证签名
#warning TODO:此处如果是正式环境需要换成public_product.key
NSString *pubkey =[self readPublicKey:@"public_test.key"];
OSStatus result=[RSA verifyData:dataOriginal sig:nsdataFromBase64String publicKey:pubkey];
//签名验证成功,商户app做后续处理
if(result == 0) {
//支付成功且验签成功,展示支付成功提示
return YES;
}
else {
//验签失败,交易结果数据被篡改,商户app后台查询交易结果
return NO;
}
return NO;
}
- (BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
[[UPPaymentControl defaultControl] handlePaymentResult:url completeBlock:^(NSString *code, NSDictionary *data) {
// 此处 可以 自己写个 代理
//结果code为成功时,先校验签名,校验成功后做后续处理
if([code isEqualToString:@"success"]) {
NSLog(@"开始交易");
//判断签名数据是否存在
if(data == nil){
//如果没有签名数据,建议商户app后台查询交易结果
NSLog(@"缺少签名");
return;
}
//数据从NSDictionary转换为NSString
NSData *signData = [NSJSONSerialization dataWithJSONObject:data
options:0
error:nil];
NSString *sign = [[NSString alloc] initWithData:signData encoding:NSUTF8StringEncoding];
//验签证书同后台验签证书
//此处的verify,商户需送去商户后台做验签
if([self verifyLocal:sign]) {
//支付成功且验签成功,展示支付成功提示
NSLog(@"支付成功");
}
else {
//验签失败,交易结果数据被篡改,商户app后台查询交易结果
NSLog(@"支付失败");
}
}
else if([code isEqualToString:@"fail"]) {
//交易失败
NSLog(@"交易失败");
}
else if([code isEqualToString:@"cancel"]) {
//交易取消
NSLog(@"取消交易");
}
}];
return YES;
}
// 本地签名
- (NSString*)sha1:(NSString *)string {
unsigned char digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_CTX context;
NSString *description;
CC_SHA1_Init(&context);
memset(digest, 0, sizeof(digest));
description = @"";
if (string == nil) {
return nil;
}
// Convert the given 'NSString *' to 'const char *'.
const char *str = [string cStringUsingEncoding:NSUTF8StringEncoding];
// Check if the conversion has succeeded.
if (str == NULL) {
return nil;
}
// Get the length of the C-string.
int len = (int)strlen(str);
if (len == 0) {
return nil;
}
if (str == NULL) {
return nil;
}
CC_SHA1_Update(&context, str, len);
CC_SHA1_Final(digest, &context);
description = [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[ 0], digest[ 1], digest[ 2], digest[ 3],
digest[ 4], digest[ 5], digest[ 6], digest[ 7],
digest[ 8], digest[ 9], digest[10], digest[11],
digest[12], digest[13], digest[14], digest[15],
digest[16], digest[17], digest[18], digest[19]];
return description;
}
VC Pay 举例
#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#import "UPPaymentControl.h"
#define kMode_Development @"01"
#define kURL_TN_Normal @"http://101.231.204.84:8091/sim/getacptn"
#define kURL_TN_Configure @"http://101.231.204.84:8091/sim/app.jsp?user=123456789"
@interface UppayViewController ()<UPPayPluginDelegate>{
NSMutableData* _responseData;
}
@property(nonatomic, copy)NSString *tnMode;
@end
@implementation UppayViewController
// 开始 支付
- (void)testPay{
NSLog(@"支付");
self.tnMode = kMode_Development;
[self startNetWithURL:[NSURL URLWithString:kURL_TN_Normal]];
}
#pragma mark UPPayPluginResult - 需要自己 写个 代理 回调 appdelegate 中的 处理。不写 是没有的。
- (void)UPPayPluginResult:(NSString *)result{
NSString* msg = [NSString stringWithFormat:@"支付结果:%@", result];
NSLog(@"%@",msg);
}
// 开始 网络请求
- (void)startNetWithURL:(NSURL *)url{
NSLog(@"等待请求");
NSURLRequest * urlRequest=[NSURLRequest requestWithURL:url];
NSURLConnection* urlConn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[urlConn start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response{
NSHTTPURLResponse* rsp = (NSHTTPURLResponse*)response;
NSInteger code = [rsp statusCode];
if (code != 200) {
NSLog(@"网络错误");
[connection cancel];
} else {
_responseData = [[NSMutableData alloc] init];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString* tn = [[NSMutableString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
if (tn != nil && tn.length > 0) {
NSLog(@"tn=%@",tn);
[[UPPaymentControl defaultControl] startPay:tn fromScheme:@"UPPayDemo" mode:self.tnMode viewController:self];
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"网络错误");
}
其他
商品 名称 什么的不能编辑。。?只能连接后台处理?
测试 支付
卡号: 6226 0900 0000 0048
验证码: 123456