微信提供了外部App拉起发票列表的接口。与微信内拉起发票列表接口相似,外部App开发者在用户勾选并点击确认后,可以获得发票的标识数据。微信电子发票详细文档
1 需要一个微信开放平台账号;微信开放平台
2 在微信开放平台上创建一个应用并提交应用通过审核。
审核通过会得到AppID, AppSecret要用这两个凭证来获取access_token,access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。
详细文档
https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
3 接入微信SDK,通过cocoaPods倒入,或者直接拖到工程目录下都可以 微信SDK下载
3.1 导入到工程中
这里只做演示,就直接拖到工程,下载下来的SDK如下:
拖到工程以后,如果报错
library not found for -
需要到 Targets -> Build Phases -> Link Binary With Libraries 添加 libWeChatSDK.a,一般新建的工程拖进来会自动添加,老的项目就需要注意替换,如果还报错,可能是中途改了目录或者添加的路径不对,删掉重新拖进来试试?3.2 SDK激活
需要当前应用在开放平台注册的appID, universalLink需要开发者在工程里配置。
universalLink是微信返回的你的app,并且带着发票信息的重要参数,没有就不能获取到发票信息
universalLink的配置参考这里
[WXApi registerApp:@"appID" universalLink:@"universalLink"];
拉起微信:
[WXApi sendReq:cardReq completion:^(BOOL success) {
//do ...
}]
WXChooseInvoiceReq是微信SDK提供的类型,封装了请求参数,对api_ticket,timeStamp,nonceStrtongg签名后,赋值给cardSign;
如下:
-(void)popToWeChat{
BOOL isWXApplnstalled = [WXApi isWXAppInstalled];
if (!isWXApplnstalled) { // 用户没装微信,直接返回。
return;
}
WXChooseInvoiceReq *cardReq = [[WXChooseInvoiceReq alloc]init];
cardReq.appID = WX_APPID;
cardReq.timeStamp = [[NSDate date] timeIntervalSince1970];
NSString* timeStamp = [NSString stringWithFormat:@"%u",(unsigned int)cardReq.timeStamp];
cardReq. nonceStr = @"sfim_invoice";
//api_ticket 通过 access_token换取
NSString *cardSign = [self genCardSignWithNonceStr: cardReq.nonceStr andTimeStr:timeStamp andApiTicket:api_ticket];
cardReq.cardSign = cardSign;
[WXApi sendReq:cardReq completion:^(BOOL success) {
//do ...
}];
}
签名中用到api_ticket,通过上面access_token 换取(获取access_token上面已经提到过)
api_ticket获取文档
请求URL:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
请求方法:GET
签名过程,对需要签名的参数按照ASCII排序,最后拼成字符串并签名如下:
-(NSString *)genCardSignWithNonceStr:(NSString *)nonceStr andTimeStr:(NSString *)timeStamp andApiTicket:(NSString *)ticket{
NSMutableDictionary *cardSignDic = [NSMutableDictionary dictionary];
[cardSignDic setObject:nonceStr forKey:@"nonceStr"];
[cardSignDic setObject:timeStamp forKey:@"timestamp"];
[cardSignDic setObject:ticket forKey:@"api_ticket"];
[cardSignDic setObject:@"INVOICE" forKey:@"cardType"];
[cardSignDic setObject:WX_APPID forKey:@"appid"];
NSMutableString *contentString = [NSMutableString string];
NSArray *values = [cardSignDic allValues];
//按字母顺序排序
NSArray *sortedArray = [values sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
//拼接字符串
for (NSString *value in sortedArray) {
[contentString appendFormat:@"%@", value];
}
NSString *cardSign = [self sha1:contentString];
return cardSign;
}
sha1签名算法:
- (NSString *)sha1:(NSString *)input {
NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (unsigned int)data.length, digest);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++){
[output appendFormat:@"%02x", digest[I]];
}
return output;
}
从微信获取到发票之后系统会在 appDelegate中回掉:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
在这个方法里调用微信的handleOpenUniversalLink
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler{
return [WXApi handleOpenUniversalLink:userActivity delegate:self];
}
微信代理:
微信的回掉,加密后的发票信息保存在resp 的cardAry数组中
- (void)onResp:(BaseResp *)resp{
if ([resp isKindOfClass:[WXChooseInvoiceResp class]]) {
[self getWxticketInfo:(WXChooseInvoiceResp *)resp];
}
}
调用微信接口解密:参考电子发票文档
单条获取,批量获取;
示例:
请求:
{
"card_id": "pjZ8Yt5crPbAouhFqFf6JFgZv4Lc",
"encrypt_code": "fbdt/fWy1VitQwhbKtSjNeR3BJyfpeJXfZjjGsdCXiM="
}
返回:
{
"errcode": 0,
"errmsg": "ok",
"card_id": "pjZ8Yt5crPbAouhFqFf6JFgZv4Lc",
"begin_time": 1476068114,
"end_time": 1476168114,
"user_card_status": "EXPIRE",
"openid": "obLatjnG4vRXJvSO8p914rSK8-Vo",
"type": "广东省增值税普通发票",
"payee": "测试-收款方",
"detail": "测试-detail",
"user_info": {
"fee": 1100,
"title": "XX公司",
"billing_time": 1468322401,
"billing_no": "hello",
"billing_code": "world",
"info": [
{
"name": "绿巨人",
"num": 10,
"unit": "吨",
"price": 4
}
],
"accept": true,
"fee_without_tax": 2345,
"tax": 123,
"pdf_url": "pdf_url",
" reimburse_status": "INVOICE_REIMBURSE_INIT",
}
}
总结:微信的文档说的很详细,但是会有些零散因此写这片文章记录下