iOS 拉取支付寶電子發(fā)票——超詳細(xì)

配圖.jpg

獲取ZFB的發(fā)票,ZFB文檔很詳細(xì)文檔,這里總結(jié)一下過程

  1. 需要平臺(tái)賬號(hào) 這里

  2. 在平臺(tái)注冊(cè)你的app


    image.png

按照官方文檔上的流程去做,很詳細(xì)
注意1,提交完app信息需要在能力列表選擇報(bào)銷助手

image.png

注意2,ZFB要求必須設(shè)置接口加簽方式,不然不能提交審核


image.png

加簽方式 文檔說明

這里選擇的模式是公鑰方式,加簽方式SHA256withRSA

你自己生成一對(duì)密鑰,把公鑰發(fā)給支付寶,支付寶也會(huì)生成一對(duì)密鑰,提交后支付寶會(huì)把公鑰發(fā)給你

提交審核,通過后appID就可以用了

  1. 應(yīng)用的appID需要和PID綁定。
    調(diào)用授權(quán)類接口,需要綁定PID詳細(xì)點(diǎn)這里查看

  2. 推模式報(bào)銷需要申請(qǐng)isvAppCode,這個(gè)只能找ZFB客服,或者發(fā)郵件

image.png

報(bào)銷模式文檔

推模式報(bào)銷:可以獲取到ZFB報(bào)銷管家里的所有發(fā)票
拉模式報(bào)銷:只能獲取商家抬頭的發(fā)票

這里以推模式報(bào)銷為例:
IMG_1760.jpg

以上步驟都完成,準(zhǔn)備工作就完了

  1. 獲取報(bào)銷授權(quán)令牌

建議讓后臺(tái)去做,接入ZFB SDK自動(dòng)簽名 過程很省事碟婆。這里演示iOS手動(dòng)簽名獲取令牌的過程,比較麻煩~
獲取令牌的文檔
生成密鑰請(qǐng)求簽名

(1). 生成待簽名字符串

添加文檔上必傳的參數(shù),按照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加密,需要導(dǎo)入頭文件:
#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實(shí)現(xiàn)了RSA2的簽名,驗(yàn)簽

(3)用生成的密鑰中的私鑰對(duì)加密結(jié)果進(jìn)行簽名

密鑰一般是從后臺(tái)獲得,這里需要把獲得的密鑰字符串轉(zhuǎn)換成SecKeyRef密鑰類型:

這里Objective-C-RSA開源庫實(shí)現(xiàn)了字符串轉(zhuǎn)SecKeyRef密鑰類型,以及RSA2加密,解密,簽名,驗(yàn)簽的過程

/// 加密,密鑰簽名
- (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 是開源庫中的工具類,實(shí)現(xiàn)了密鑰字符串轉(zhuǎn)換成SecKeyRef密鑰類型

這樣就完成了簽名過程

(4) 調(diào)用ZFB接口,獲取令牌

網(wǎng)絡(luò)請(qǐng)求用到AFNetworking

-(void)getAliPayToken {
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSString *timeStr = [dateFormatter stringFromDate:NSDate.date];
    
    //參數(shù)字典
    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. 跳轉(zhuǎn)到ZFB,獲取發(fā)票信息

跳轉(zhuǎn)方式和其他的app一樣,按照ZFB文檔說明替換相應(yīng)參數(shù)就可以
獲取到發(fā)票信息,ZFB會(huì)通過UniversalLink回掉你的app,并且攜帶發(fā)票信息

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: ------  對(duì)alipays:相關(guān)的scheme處理 -------
        // NOTE: 若遇到ZFB相關(guān)scheme累奈,則跳轉(zhuǎn)到本地ZFB App
        NSString* reqUrl = request.URL.absoluteString;
        if ([reqUrl hasPrefix:@"alipays://"] || [reqUrl hasPrefix:@"alipay://"]) {
            // NOTE: 跳轉(zhuǎn)ZFB App
            BOOL bSucc = [[UIApplication sharedApplication] openURL:request.URL];
     
            // NOTE: 如果跳轉(zhuǎn)失敗禁筏,則跳轉(zhuǎn)itune下載ZFB App
            if (!bSucc) {
                
                NSLog(@"跳轉(zhuǎn)失敗");
                
            }
        }
}
  1. ZFB 回掉,系統(tǒng)會(huì)在appDelegate中回掉continueUserActivity
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{

  //這里就能看到從ZFB 獲取到的發(fā)票信息了
  NSLog(@"%@",userActivity.webpageURL.absoluteString);
  return YES;
}
  1. 發(fā)票信息解密

調(diào)用ZFB API解密

以上就是獲取ZFB 發(fā)票流程,文檔說的很詳細(xì),在此記錄一下;強(qiáng)烈建議后臺(tái)通過ZFB SDK獲取令牌以及后續(xù)的解密過程會(huì)舒適很多

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惹骂,更是在濱河造成了極大的恐慌魂拦,老刑警劉巖毛仪,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芯勘,居然都是意外死亡箱靴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門荷愕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衡怀,“玉大人,你說我怎么就攤上這事安疗∨籽睿” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵荐类,是天一觀的道長怖现。 經(jīng)常有香客問我,道長玉罐,這世上最難降的妖魔是什么屈嗤? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮吊输,結(jié)果婚禮上饶号,老公的妹妹穿的比我還像新娘。我一直安慰自己璧亚,他們只是感情好讨韭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著癣蟋,像睡著了一般透硝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疯搅,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天濒生,我揣著相機(jī)與錄音,去河邊找鬼幔欧。 笑死罪治,一個(gè)胖子當(dāng)著我的面吹牛丽声,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播觉义,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼雁社,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了晒骇?” 一聲冷哼從身側(cè)響起霉撵,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洪囤,沒想到半個(gè)月后徒坡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘤缩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年喇完,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剥啤。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锦溪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铐殃,到底是詐尸還是另有隱情海洼,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布富腊,位于F島的核電站坏逢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赘被。R本人自食惡果不足惜是整,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望民假。 院中可真熱鬧浮入,春花似錦、人聲如沸羊异。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽野舶。三九已至易迹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間平道,已是汗流浹背睹欲。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窘疮。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓袋哼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親闸衫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涛贯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容