获取ZFB的发票,ZFB文档很详细文档,这里总结一下过程
需要平台账号 这里
-
在平台注册你的app
按照官方文档上的流程去做,很详细
注意1,提交完app信息需要在能力列表选择报销助手
注意2,ZFB要求必须设置接口加签方式,不然不能提交审核
加签方式 文档说明
这里选择的模式是公钥方式,加签方式SHA256withRSA
你自己生成一对密钥,把公钥发给支付宝,支付宝也会生成一对密钥,提交后支付宝会把公钥发给你
提交审核,通过后appID就可以用了
应用的appID需要和PID绑定。
调用授权类接口,需要绑定PID详细点这里查看推模式报销需要申请isvAppCode,这个只能找ZFB客服,或者发邮件
推模式报销:可以获取到ZFB报销管家里的所有发票
拉模式报销:只能获取商家抬头的发票
以上步骤都完成,准备工作就完了
- 获取报销授权令牌
建议让后台去做,接入ZFB SDK自动签名 过程很省事。这里演示iOS手动签名获取令牌的过程,比较麻烦~
获取令牌的文档
生成密钥请求签名
(1). 生成待签名字符串
添加文档上必传的参数,按照ASCII排序生成字符串
///返回待加密字符串
-(NSString *)signatureStringWith:(NSDictionary*)parameters{
NSMutableString *contentString = [NSMutableString string];
NSArray *allKeys = [parameters allKeys];
NSArray *sortedKeyArray = [allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
for (NSString *key in sortedKeyArray) {
[contentString appendFormat:@"%@=%@&",key,[parameters valueForKey:key]];
}
NSString *signatureStr = [NSString stringWithString:[contentString substringWithRange:NSMakeRange(0, [contentString length] - 1)]];
return signatureStr;
}
(2). 加密字符串,签名
sha256加密,需要导入头文件:
#import <CommonCrypto/CommonDigest.h>
//SHA2加密
- (NSData *) sha256:(NSString *)str {
const char *s = [str cStringUsingEncoding:NSUTF8StringEncoding];
NSData *strData = [NSData dataWithBytes:s length:strlen(s)];
uint8_t digest [CC_SHA256_DIGEST_LENGTH] = {0};
CC_SHA256(strData.bytes, (CC_LONG)strData.length, digest);
NSData *data = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
return data;
}
RSA2 加密,什么是RAS2可以自行百度,这里Objective-C-RSA实现了RSA2的签名,验签
(3)用生成的密钥中的私钥对加密结果进行签名
密钥一般是从后台获得,这里需要把获得的密钥字符串转换成SecKeyRef密钥类型:
这里Objective-C-RSA开源库实现了字符串转SecKeyRef密钥类型,以及RSA2加密,解密,签名,验签的过程
/// 加密,密钥签名
- (NSString *) sign:(NSString *)storString{
// 使用哈希算法获取字符串摘要
// sha256加密
NSData *outData = [self sha256:storString];
SecKeyRef pKey = [RSA addPrivateKey:[self getPrivateKey]];
size_t siglen = SecKeyGetBlockSize(pKey);
uint8_t* signedHashBytes = malloc(siglen);
memset(signedHashBytes, 0x0, siglen);
SecKeyRawSign(pKey,
kSecPaddingPKCS1SHA256,
outData.bytes,
outData.length,
signedHashBytes,
&siglen);
NSData* signedHash = [NSData dataWithBytes:signedHashBytes length:(NSUInteger)siglen];
NSString *signString = [signedHash base64EncodedStringWithOptions:NSUTF8StringEncoding];
NSLog(@"=1===== %@",signString);
if (!signString) {
return @"";
}
return signString;
}
RSA 是开源库中的工具类,实现了密钥字符串转换成SecKeyRef密钥类型
这样就完成了签名过程
(4) 调用ZFB接口,获取令牌
网络请求用到AFNetworking
-(void)getAliPayToken {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSString *timeStr = [dateFormatter stringFromDate:NSDate.date];
//参数字典
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:timeStr forKey:@"timestamp"];
[parameters setObject:@"alipay.ebpp.invoice.isvtoken.reim.apply" forKey:@"method"];
[parameters setObject:APPID forKey:@"app_id"];
[parameters setObject:@"RSA2" forKey:@"sign_type"];
[parameters setObject:@"1.0" forKey:@"version"];
[parameters setObject:@"utf-8" forKey:@"charset"];
[parameters setObject:@"{\"isv_app_code\":\"ekuaibao_tinyapp\"}" forKey:@"biz_content"];
//生成签名字符串
NSString *signatureStr = [self signatureStringWith:parameters];
[parameters setObject:[self sign:signatureStr] forKey:@"sign"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/plain", @"text/javascript", @"text/json", @"text/html", nil];
NSString *postUrl = @"https://openapi.alipay.com/gateway.do?";
[manager POST:postUrl parameters:parameters headers:nil progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//do ......
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
}
- 跳转到ZFB,获取发票信息
跳转方式和其他的app一样,按照ZFB文档说明替换相应参数就可以
获取到发票信息,ZFB会通过UniversalLink回掉你的app,并且携带发票信息
alipays://platformapi/startapp?appId=2021001125620243&ap_framework_sceneId=1300&thirdPartSchema=#testapp://#&page=pages/package-detail/index?isv_app_code%3D#appCode#%26isv_token%3D#token#%26isv_serial_no%3D#serialNo#%26isv_register_no%3D#registerNo#%26options%3D#options#
- (void)popToAliPayApp{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.urlStr]];
// NOTE: ------ 对alipays:相关的scheme处理 -------
// NOTE: 若遇到ZFB相关scheme,则跳转到本地ZFB App
NSString* reqUrl = request.URL.absoluteString;
if ([reqUrl hasPrefix:@"alipays://"] || [reqUrl hasPrefix:@"alipay://"]) {
// NOTE: 跳转ZFB App
BOOL bSucc = [[UIApplication sharedApplication] openURL:request.URL];
// NOTE: 如果跳转失败,则跳转itune下载ZFB App
if (!bSucc) {
NSLog(@"跳转失败");
}
}
}
- ZFB 回掉,系统会在appDelegate中回掉continueUserActivity
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{
//这里就能看到从ZFB 获取到的发票信息了
NSLog(@"%@",userActivity.webpageURL.absoluteString);
return YES;
}
- 发票信息解密
调用ZFB API解密
以上就是获取ZFB 发票流程,文档说的很详细,在此记录一下;强烈建议后台通过ZFB SDK获取令牌以及后续的解密过程会舒适很多