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

配图.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获取令牌以及后续的解密过程会舒适很多

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容