首页 > 代码库 > 支付那些小事

支付那些小事

       现在不管是电商还是一些社区类的App都接入了支付的功能,有的是走的苹果的支付【内购不是Apple Pay】,有的则是支付宝、微信和银联卡,不管是买卖商品还是打赏点赞,这些都是涉及到资金的流动。当然目前据《华尔街日报》,微信和其他公司的高管表示,苹果已经要求几家国内社交网络应用禁用它们的“打赏”功能,以遵守AppStore的规则。即使是这样还可以在打打赏的位置放置一些收款二维码来替代。当然如果真的放二维码了那就跟自己的应用没关系了,所以这一块也不用担心了。那么先说一下应用的内购吧,应用的内购流程(内购的流程具体可参见:http://www.cnblogs.com/liuluoxing/p/6553109.html)其实并不复杂,主要是一些点需要注意:设置卡号选择币种的时候人民币的标识是CNY,接着设置Tax的时候一般在天朝的话直接选择

技术分享

 

图1.0

这些是税务信息一般来说U.S Tax Forms: 美国税务、Australia Tax Forms:澳大利亚税务、Canada Tax Forms: 加拿大税务 选择美国税务就可以。签完协议和税务信息,还要记得填写用户的职能即设置沙盒里面的测试账号,这样使用这个账号才能进行测试内购。这些是为内购做的准备,当进行集成的时候推荐一个轮子(RMStore这个开源库),过程中遇到一些问题就是付款过程中的未知错误处理是最多的无法连接到iTunes store,不过查阅一些资料的话可以发现,其实每种状态都有对应的枚举值如下:

enum {  
    SKErrorUnknown,  
    SKErrorClientInvalid,               // client is not allowed to issue the request, etc.  
    SKErrorPaymentCancelled,            // user cancelled the request, etc.  
    SKErrorPaymentInvalid,              // purchase identifier was invalid, etc.  
    SKErrorPaymentNotAllowed,           // this device is not allowed to make the payment  
    SKErrorStoreProductNotAvailable,    // Product is not available in the current storefront  
};  

可以根据这几个状态作相应的细节处理,提示用户即可。

       接着是支付宝和微信了,先说支付宝吧,在客户端的处理上支付宝的处理相对于微信来说更多一下,被吐槽的地方也更多一些,首先是支付宝的官方集成文档特别特别的难找,要找很久才能找对地方。这个是直达连接

https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.0JY36K&treeId=193&articleId=105295&docType=1
      技术分享

 

图2.0
        涉及到的相关流程即:首先应用端选择支付宝付款,这里分为两种情况,一种是使用公司自己的服务器生成签名,订单号和订单的相关参数值,第二种是应用在客户端自己生成签名和订单信息.因为订单信息中包含签名和秘钥,会造成信息传递的不安全,所以还是建议将生成订单的步骤放在自己的服务器端(最好是服务器给返回的数据是已经拼接好的参数串例如:
{
  "code": 0,
  "message": "SUCCESS",
  "data": [
    {
      "data": "partner=2088121050949991&seller_id=774267424@qq.com&subject=充值测试&notify_url=http://1xx.xx.xx.xx:8081/v2/notify&payment_type=1&_input_charset=utf-8&it_b_pay=30m&sign=xxxxxxxxxxxx&sign_type=RSA"
    }
  ]
}
)这样客户端就可以直接拿着相应的data里面的返回订单信息去调起支付宝的api,设置好appScheme,直接用调用支付宝的支付接口即可:
  [self sendValueToAliPayWithOrderString:signedString FromScheme:appScheme];

相关的代码为:

- (void)sendValueToAliPayWithOrderString:(NSString *)orderString FromScheme:(NSString *)appScheme
{
    
    //    提供给商户快捷订单支付功能。  支付并返回回调结果
    [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
        
     
        if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"9000"]) {
           // 支付成功的处理,跳转相关界面
        }else  if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"4001"]) {
            UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"请您重新选择支付金额" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [av show];
            
        } else  if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"4006"]) {
            
            UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"订单支付失败" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [av show];
            
            // 支付失败跳转的界面

        } else if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"4003"]) {
        
            UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您的账户目前不能正常支付" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [av show];
            // 支付失败跳转的界面

        } else if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"6001"]) {
            
            UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您已取消充值" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [av show];
            
            
        }else {
            
            UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"未支付成功" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [av show];
            // 支付失败的跳转
            
        }
    }];
}

除此之外还要在AppDelegate里面做相应的设置,这一块如果做了微信的支付回调的方法也是一致的,等下面说微信支付的时候一块贴上代码。如果签名什么的都在后台服务器做的话,那么在应用中的代码也就这么多。还有几个需要注意的点,就是为了支付成功回调做的准备:

应用注册的时候schme 在Info.plist定义URL types URL schme
将商品信息拼接成字符串
进行签名并将签名成功后的字符串格式化订单字符串
调用支付宝SDK发送数据
// 还包括相关错误码
9000 订单支付成功
8000 正在处理中
4000 订单支付失败
6001 用户中途取消
6002 网络连接出错
 

可以画个图展示一下:

技术分享

图3.0

 以上就是支付宝支付所需要注意的点了。下面来说说微信,就像之前说到的,微信支付要比起支付宝支付来讲客户端处理的内容相对的较少一些,其主要的处理都是在服务端,首先可以看一下这个流程,一看就是比较复杂,不过这些都不用客户端来处理
 技术分享

图4.0

简化一下呢,就是是4个步骤,一个就是请求生成的订单数据,另一个就是调起微信支付德的api处理支付的结果;接着就是处理支付的回调结果,最后异步处理,通知服务器支付成功。画个图展示一下具体的步骤吧

技术分享

图5.0

这些事理论上的表述,涉及到应用中的代码处理可以分为,先从服务器请求相应的数据,服务器返回的数据格式应该为:

{
  "code": 0,
  "message": "SUCCESS",
  "data": [
    {
      "app_id": "wx6a33db7xxxxx",
      "nonce_str": "IVY8yB5q7v6jpSgiVgxxxxxxxx",
      "extend_field": "Sign=WXPay",
      "partner_id": "1333317801",
      "prepay_id": "wx2017022414465218c0066b3d04xxxxxx",
      "timestamp": "1487918812",
      "sign": "D5001641D1F43C5DBA6F14xxxxxxxx"
    }
  ]
}

 在后台服务器请求完必要的参数后,此时就应该调起微信支付:具体代码如下:

  if([WXApi isWXAppInstalled]) // 判断 用户是否安装微信
    {
        PayReq *request = [[PayReq alloc] init] ;
        request.partnerId = _myModel.partner_id;
        request.prepayId= _myModel.prepay_id;
        request.package = _myModel.extend_field;
        request.nonceStr= _myModel.nonce_str;
        request.timeStamp= _myModel.timestamp;
        request.sign= _myModel.sign;
        
        [WXApi sendReq:request];
    }else {
        
        UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"提示" message:@"未安装微信客户端,请选择其他支付方式" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [av show];     
   }

再在其回调的方法内设置相应的跳转即可如下:

-(void)dealWXpayResult:(NSNotification*)notification{
    NSString*result=notification.object;
    if([result isEqualToString:@"1"]){
        // 支付成功的操作

    }else{
        
        //支付失败的操作
        UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您已取消支付" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [av show]; 
    } 
}
 以上是在当前界面下的处理的回调逻辑,除此之外还要在AppDelegate里面设置相关的代理方法具体的设置内容如下所示:
首先是支付宝的:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
    if ([url.host isEqualToString:@"safepay"]) {
        // 设备已安装支付宝客户端情况下,处理支付宝客户端返回的 url
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            // 用SBJSON 或者 JSONKit 将回调信息(字典)转成字符串
            SBJSON *sbJson = [[SBJSON alloc] init];
            NSString *resultDicToString = [sbJson stringWithObject:resultDic error:nil];
            [self paymentResult:resultDicToString];
        }];
    }
    if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回 authCode
        [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
    
        }];
    }
    return YES;
}
// 支付宝回调的新方法
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{
    if ([url.host isEqualToString:@"safepay"]) {
        //   设备已安装支付宝客户端情况下,处理支付宝客户端返回的 url
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            //    用SBJSON 或者 JSONKit 将回调信息(字典)转成字符串
            SBJSON *sbJson = [[SBJSON alloc] init];
            NSString *resultDicToString = [sbJson stringWithObject:resultDic error:nil];
            [self paymentResult:resultDicToString];
            if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"9000"]) {
                //    NSLog(@"当前页面下的支付成功");
                [[NSNotificationCenter defaultCenter]postNotificationName:@"chongzhiFinishAction" object:nil];
                
            }else {
                
                //    NSLog(@"当前页面下的未支付");
                UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您已取消支付" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
                [av show];
                
            }
        }];
    }else{
        
        return  [WXApi handleOpenURL:url delegate:self];
    }
    if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回 authCode
        [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {

            if ([[resultDic objectForKey:@"resultStatus"]isEqualToString:@"9000"]) {
                //                NSLog(@"当前页面下的支付成功");
                UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您已支付成功" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
                [av show];
            }else {
                //                NSLog(@"当前页面下的未支付");
                UIAlertView *av = [[UIAlertView alloc] initWithTitle:nil message:@"您已取消支付" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
                [av show];
                
            }
            
        }];
    }else
    {
        return  [WXApi handleOpenURL:url delegate:self];
    }
    
    return  YES;
    
    
}

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    if ([url.host isEqualToString:@"safepay"]) {
        //    设备已安装支付宝客户端情况下,处理支付宝客户端返回的 url
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            // 用SBJSON 或者 JSONKit 将回调信息(字典)转成字符串
            SBJSON *sbJson = [[SBJSON alloc] init];
            NSString *resultDicToString = [sbJson stringWithObject:resultDic error:nil];
            [self paymentResult:resultDicToString];
        }];
    }else{
        return  [WXApi handleOpenURL:url delegate:self];
    }
    if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回 authCode
        [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
       
        }];
    }else{
        //          return  [WXApi handleOpenURL:url delegate:self];
    }
    return YES;
}
//#pragma mark - 对独立客户端回调结果验证
- (void)paymentResult:(NSString *)resultDicToString
{
    //结果处理
    AlixPayResult *result = [[AlixPayResult alloc] initWithString:resultDicToString];
    if (result)
    {
        if (result.statusCode == 9000)
        {
            // 验证签名成功,交易结果无篡改
            // NSLog(@"支付成功!");
            
        }
        
        else
        {
            // 支付失败
            // NSLog(@"%d%@", result.statusCode, result.statusMessage);
        }
    }
    else
    {
        // 支付失败
        // NSLog(@"支付失败!");
    }
    
}

接着是微信的:

#pragma mark - 微信支付回调
-(void) onResp:(BaseResp*)resp
{
    NSString *strMsg = [NSString stringWithFormat:@"errcode:%d", resp.errCode];
    NSString *strTitle;
    
    if([resp isKindOfClass:[SendMessageToWXResp class]])
    {
        strTitle = [NSString stringWithFormat:@"发送媒体消息结果"];
    }
    if([resp isKindOfClass:[PayResp class]]){
        //支付返回结果,实际支付结果需要去微信服务器端查询
        strTitle = [NSString stringWithFormat:@"支付结果"];
        
        switch (resp.errCode) {
            case WXSuccess:
                strMsg = @"恭喜您支付:成功!";
                
                [[NSNotificationCenter defaultCenter] postNotificationName:@"WXpayresult" object:@"1"];
                break;
                
            default:
                strMsg = [NSString stringWithFormat:@"您已取消支付"];
                
                [[NSNotificationCenter defaultCenter] postNotificationName:@"WXpayresult" object:@"2"];
                
                break;
        }
    }
    
    
}

其实可以看出这两种方式的支付都有重合的地方,需要注意添加判断一下。

    对了,最后再说一点吧,如果你app同时使用了友盟分享(含微信分享)和微信支付 要注意两者的register步骤。要先调用友盟,然后调用微信。避免不必要的错误。

 
 

 

支付那些小事