獲取ZFB的發(fā)票,ZFB文檔很詳細(xì)文檔,這里總結(jié)一下過程
需要平臺(tái)賬號(hào) 這里
-
在平臺(tái)注冊(cè)你的app
按照官方文檔上的流程去做,很詳細(xì)
注意1,提交完app信息需要在能力列表選擇報(bào)銷助手
注意2,ZFB要求必須設(shè)置接口加簽方式,不然不能提交審核
加簽方式 文檔說明
這里選擇的模式是公鑰方式,加簽方式SHA256withRSA
你自己生成一對(duì)密鑰,把公鑰發(fā)給支付寶,支付寶也會(huì)生成一對(duì)密鑰,提交后支付寶會(huì)把公鑰發(fā)給你
提交審核,通過后appID就可以用了
應(yīng)用的appID需要和PID綁定。
調(diào)用授權(quán)類接口,需要綁定PID詳細(xì)點(diǎn)這里查看推模式報(bào)銷需要申請(qǐng)isvAppCode,這個(gè)只能找ZFB客服,或者發(fā)郵件
推模式報(bào)銷:可以獲取到ZFB報(bào)銷管家里的所有發(fā)票
拉模式報(bào)銷:只能獲取商家抬頭的發(fā)票
以上步驟都完成,準(zhǔn)備工作就完了
- 獲取報(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) {
}];
}
- 跳轉(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)失敗");
}
}
}
- 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;
}
- 發(fā)票信息解密
調(diào)用ZFB API解密
以上就是獲取ZFB 發(fā)票流程,文檔說的很詳細(xì),在此記錄一下;強(qiáng)烈建議后臺(tái)通過ZFB SDK獲取令牌以及后續(xù)的解密過程會(huì)舒適很多