iOS 拉取支付宝电子发票——超详细

2021-04-04  本文已影响0人  你duck不必呀
配图.jpg

获取ZFB的发票,ZFB文档很详细文档,这里总结一下过程

  1. 需要平台账号 这里

  2. 在平台注册你的app


    image.png

按照官方文档上的流程去做,很详细
注意1,提交完app信息需要在能力列表选择报销助手

image.png

注意2,ZFB要求必须设置接口加签方式,不然不能提交审核


image.png

加签方式 文档说明

这里选择的模式是公钥方式,加签方式SHA256withRSA

你自己生成一对密钥,把公钥发给支付宝,支付宝也会生成一对密钥,提交后支付宝会把公钥发给你

提交审核,通过后appID就可以用了

  1. 应用的appID需要和PID绑定。
    调用授权类接口,需要绑定PID详细点这里查看

  2. 推模式报销需要申请isvAppCode,这个只能找ZFB客服,或者发邮件

image.png

报销模式文档

推模式报销:可以获取到ZFB报销管家里的所有发票
拉模式报销:只能获取商家抬头的发票

这里以推模式报销为例: IMG_1760.jpg

以上步骤都完成,准备工作就完了

  1. 获取报销授权令牌

建议让后台去做,接入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) {
    }];
    
}
  1. 跳转到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(@"跳转失败");
                
            }
        }
}
  1. ZFB 回掉,系统会在appDelegate中回掉continueUserActivity
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{

  //这里就能看到从ZFB 获取到的发票信息了
  NSLog(@"%@",userActivity.webpageURL.absoluteString);
  return YES;
}
  1. 发票信息解密

调用ZFB API解密

以上就是获取ZFB 发票流程,文档说的很详细,在此记录一下;强烈建议后台通过ZFB SDK获取令牌以及后续的解密过程会舒适很多

上一篇 下一篇

猜你喜欢

热点阅读