继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

iOS开发-微信/支付宝/内购封装

ITMISS
关注TA
已关注
手记 342
粉丝 51
获赞 244
  • 一句话集成微信支付,支付宝支付以及内购
    可以在github上下载的工具类

源码

  • 如何使用

1.将工具类拖入工程
2.AppDelegate代码如下:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{        
    return [[XNPayManager sharedPayManager] handleOpenURL:url];
}// NOTE: 9.0以后使用新API接口- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{    return [[XNPayManager sharedPayManager] handleOpenURL:url];
}

3.在使用的地方调起微信或者支付宝

  • 支付宝

TIPS:拼装参数应在商户服务端完成,商户服务端直接将组装和签名后的请求串orderString传给客户端,客户端直接传给SDK发起请求。文档和Demo是为了示例效果在客户端实现。所以我们项目中应该按照次操作

  // params应该是由后台返回的
 [[XNPayManager sharedPayManager] ALIPayWithPayParams: params success:^(PayCode code) {                    // 成功业务逻辑
                    DLog(@"成功");
  } failure:^(PayCode code) {                    // 失败业务逻辑
                    DLog(@"失败");
 }]
  • 微信支付

  // dict应该是由后台返回的
  [[XNPayManager sharedPayManager] WXPayWithPayDict: dict success:^(PayCode code) {                    // 成功业务逻辑
                    DLog(@"成功");
  } failure:^(PayCode code) {                    // 失败业务逻辑
                    DLog(@"成功");
 }];
  • 内购

//productId 产品唯一标示
        [[XNPayManager sharedPayManager] requestProductData: productId success:^(PayCode code) {           // 成功业务逻辑
        } failure:^(PayCode code) {            // 失败业务逻辑
        }];
  • 详细代码

在封装的代码中没有使用通知,因为通知是全局的,然后在项目中出现了一下问题,比如:待支付订单->订单详情 这两个页面都有支付的操作.如果使用通知:这两个控制器支付成功\失败的业务逻辑就会冲突

1.声明支付单例

+ (instancetype)sharedPayManager {    static dispatch_once_t onceToken;    static XNPayManager *instance;    dispatch_once(&onceToken, ^{
        instance = [[XNPayManager alloc] init];
    });    return instance;
}

2.自定义支付状态码,其实也可以不用定义

/**
 支付状态码
 */typedef NS_ENUM(NSInteger, PayCode) {
    WXSUCESS            = 1001,   /**成功*/
    WXERROR             = 1002,   /**失败*/
    WXSCANCEL           = 1003,   /**取消*/
    
    ALIPAYSUCESS        = 1101,   /**支付宝支付成功*/
    ALIPAYERROR         = 1102,   /**支付宝支付错误*/
    ALIPAYCANCEL        = 1103,   /**支付宝支付取消*/
    
    APPSTOREPAYSUCESS   = 1201,   /**内购支付成功*/
    APPSTOREPAYERROR    = 1201,   /**内购支付成功*/
    APPSTOREPAYCANCEL   = 1201,   /**内购支付成功*/};

3.微信支付

/**
 微信支付
 
 @param dict 微信订单字典(全部由后台拼接好给iOS端)
 @param successBlock 成功的回调
 @param failBolck 失败的回调
 */- (void)WXPayWithPayDict:(NSDictionary *)dict
                 success:(void(^)(PayCode code)) successBlock
                 failure:(void(^)(PayCode code)) failBolck {    self.successBlock = successBlock;    self.failBolck = failBolck;    NSString *strMsg = nil;    //1. 判断是否安装微信
    if (![WXApi isWXAppInstalled]) {        NSLog(@"您尚未安装\"微信App\",请先安装后再返回支付");
        strMsg = @"您尚未安装\"微信App\",请先安装后再返回支付";
        [self tipMessageAlert:nil message:strMsg];        return;
    }    
    //2.判断微信的版本是否支持最新Api
    if (![WXApi isWXAppInstalled]) {        NSLog(@"您微信当前版本不支持此功能,请先升级微信应用");
        strMsg = @"您微信当前版本不支持此功能,请先升级微信应用";
        [self tipMessageAlert:nil message:strMsg];        return;
    }    
    if (!kDictIsEmpty(dict)) {        
        //调起微信支付
        PayReq *req = [[PayReq alloc]init];
        req.openID = dict[@"appid"];
        req.partnerId = dict[@"partnerid"];
        req.prepayId = dict[@"prepayid"];
        req.nonceStr = dict[@"noncestr"];
        req.timeStamp = [dict[@"timestamp"] intValue];
        req.package = @"Sign=WXPay";
        req.sign = dict[@"sign"];
        [WXApi sendReq:req];
    }

}#pragma mark - WXApiDelegate//支付结果回调/// - see [支付结果回调](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5)- (void)onResp:(BaseResp *)resp {    
    NSString *strMsg = [NSString stringWithFormat:@"errcode:%d",resp.errCode];    
    //回调中errCode值列表:
    // 0 成功 展示成功页面
    //-1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等
    //-2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP
    
    if ([resp isKindOfClass:[PayResp class]]) {        // 支付返回结果,实际支付结果需要去微信服务器端查询
        switch (resp.errCode) {            case WXSuccess:{
                strMsg = @"支付结果:成功!";                self.successBlock(WXSUCESS);
                DLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode);                break;
            }            case WXErrCodeUserCancel:{
                strMsg = @"支付结果:取消";                self.failBolck(WXSCANCEL);
                DLog(@"支付取消-PayCancel,retcode = %d", resp.errCode);
            }            default:{
                strMsg = @"支付结果:失败";                self.failBolck(WXERROR);
                DLog(@"错误,retcode = %d, retstr = %@", resp.errCode,resp.errStr);                break;
            }
        }
        [self tipMessageAlert:@"支付结果" message:strMsg];
    }
    
}

4.支付宝

/**
 支付宝支付
 
 @param params 支付宝支付参数(全部由后台拼接好给iOS端)
 @param successBlock 成功的回调
 @param failBolck 失败的回调
 */- (void)ALIPayWithPayParams:(NSString *)params
                    success:(void(^)(PayCode code)) successBlock
                    failure:(void(^)(PayCode code)) failBolck {    
    self.successBlock = successBlock;    self.failBolck = failBolck;    NSString *appScheme = @"appScheme";
    [[AlipaySDK defaultService] payOrder:params fromScheme:appScheme callback:^(NSDictionary *resultDic) {
        DLog(@"我这里是payVC%@",resultDic);
        DLog(@"%@",resultDic[@"memo"]);
        [self aliPayResult:resultDic];
    }];


}#pragma mark - 支付宝支付结果处理- (void)aliPayResult:(NSDictionary *)resultDic {    
    // 返回结果需要通过 resultStatus 以及 result 字段的值来综合判断并确定支付结果。 在 resultStatus=9000,并且 success="true"以及 sign="xxx"校验通过的情况下,证明支付成功。其它情况归为失败。较低安全级别的场合,也可以只通过检查 resultStatus 以及 success="true"来判定支付结果
    NSInteger resultStatus = [resultDic[@"resultStatus"] integerValue];    
    if (resultDic && [resultDic objectForKey:@"resultStatus"]) {        switch (resultStatus) {            case 9000:
                [self tipMessageAlert:@"支付结果" message:@"订单支付成功"];                self.successBlock(ALIPAYSUCESS);                break;            case 8000:
                [self tipMessageAlert:@"支付结果" message:@"正在处理中"];                self.failBolck(ALIPAYERROR);                break;            case 4000:
                [self tipMessageAlert:@"支付结果" message:@"订单支付失败,请稍后再试"];                self.failBolck(ALIPAYERROR);                break;            case 6001:
                [self tipMessageAlert:@"支付结果" message:@"已取消支付"];                self.failBolck(ALIPAYCANCEL);                break;            case 6002:
                [self tipMessageAlert:@"支付结果" message:@"网络连接错误,请稍后再试"];                self.failBolck(ALIPAYERROR);                break;            default:                break;
        }
    }
    
}

5.内购

/**
 内购
 
 @param productId productId
 @param successBlock 成功的回调
 @param failBolck 失败的回调
 */- (void)requestProductData:(NSString *)productId
                   success:(void(^)(PayCode code)) successBlock
                   failure:(void(^)(PayCode code)) failBolck {    if ([SKPaymentQueue canMakePayments]) {        self.successBlock = successBlock;        self.failBolck = failBolck;        // 最好设置上
        MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:kKeyWindow animated:YES];
        hud.labelText = @"正在购买,请勿离开...";
        hud.dimBackground = YES;        self.productId = productId;        NSArray *productArr = [[NSArray alloc]initWithObjects:productId, nil];        
        NSSet *productSet = [NSSet setWithArray:productArr];        
        SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:productSet];
        
        request.delegate = self;
        
        [request start];
        
    }else{
        DLog(@"不允许程序内付费");
    }

}#pragma mark - SKProductsRequestDelegate// 收到产品返回信息- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {    
    
    NSArray *productArr = response.products;    
    if ([productArr count] == 0) {
        DLog(@"没有该商品");
        [MBProgressHUD hideAllHUDsForView:kKeyWindow animated:YES];        return;
    }
    
    DLog(@"productId = %@",response.invalidProductIdentifiers);
    DLog(@"产品付费数量 = %zd",productArr.count);    
    SKProduct *p = nil;    
    for (SKProduct *pro in productArr) {
        DLog(@"description:%@",[pro description]);
        DLog(@"localizedTitle:%@",[pro localizedTitle]);
        DLog(@"localizedDescription:%@",[pro localizedDescription]);
        DLog(@"price:%@",[pro price]);
        DLog(@"productIdentifier:%@",[pro productIdentifier]);        if ([pro.productIdentifier isEqualToString:self.productId]) {
            p = pro;
        }
    }    
    SKPayment *payment = [SKPayment paymentWithProduct:p];    
    //发送内购请求
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}#pragma mark - SKRequestDelegate- (void)requestDidFinish:(SKRequest *)request {
    
    DLog(@"获取产品成功");//    [MBProgressHUD hideHUDForView:kKeyWindow animated:YES];
    
    }
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    
    [MBProgressHUD hideHUDForView:kKeyWindow animated:YES];
    
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:kKeyWindow animated:YES];
    hud.labelText = @"购买失败";
    hud.mode = MBProgressHUDModeText;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [MBProgressHUD hideHUDForView:kKeyWindow animated:YES];
    });
    
}// 监听购买结果//SKPaymentTransactionObserver- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {    
    
    for (SKPaymentTransaction *tran in transactions) {        switch (tran.transactionState) {            case SKPaymentTransactionStatePurchased: //交易完成
                [self completeTransaction:tran];                // Remove the transaction from the payment queue.
                [[SKPaymentQueue defaultQueue] finishTransaction: tran];                break;            case SKPaymentTransactionStatePurchasing: //商品添加进列表
                break;            case SKPaymentTransactionStateRestored: //购买过
                [self restoreTransaction:tran];                break;            case SKPaymentTransactionStateFailed: //交易失败
                [self failedTransaction:tran];                // Remove the transaction from the payment queue.
                [[SKPaymentQueue defaultQueue] finishTransaction: tran];                break;                
            default:                break;
        }
    }
}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {    NSString * productIdentifier = transaction.payment.productIdentifier;
    DLog(@"productIdentifier Product id:%@", productIdentifier);    NSString *transactionReceiptString= nil;    
    //系统IOS7.0以上获取支付验证凭证的方式应该改变,切验证返回的数据结构也不一样了。
    
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];    NSData * receiptData = [NSData dataWithContentsOfURL:receiptUrl];
    
    transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    DLog(@"transactionReceiptString == %@",transactionReceiptString);    
    if ([productIdentifier length] > 0) {        self.hud.labelText = @"正在验证,请勿离开...";         // 请求自己的服务器去验证用户购买结果
        // 往后台验证,只有服务器有反应就hide
        [MBProgressHUD hideAllHUDsForView:kKeyWindow animated:YES];
    }


}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {    if(transaction.error.code != SKErrorPaymentCancelled) {
        DLog(@"购买失败");        self.failBolck(APPSTOREPAYCANCEL);
    } else {
        DLog(@"用户取消交易");        self.failBolck(APPSTOREPAYCANCEL);
    }
    [MBProgressHUD hideHUDForView:kKeyWindow animated:YES];
    [SMGlobalMethod showViewCenter:kKeyWindow.center longMessage:@"购买失败"];
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {    // 对于已购商品,处理恢复购买的逻辑
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

6.单例回调

#pragma mark - 单例类回调- (BOOL)handleOpenURL:(NSURL *)url {    
    if ([url.host isEqualToString:@"safepay"])
    {        //跳转支付宝钱包进行支付,处理支付结果
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            DLog(@"result = %@",resultDic);
            DLog(@"openURL : 支付宝回调 : result = %@",resultDic);
            [self aliPayResult:resultDic];
        }];        // 授权跳转支付宝钱包进行支付,处理支付结果
        [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {            NSLog(@"result = %@",resultDic);            // 解析 auth code
            NSString *result = resultDic[@"result"];            NSString *authCode = nil;            if (result.length>0) {                NSArray *resultArr = [result componentsSeparatedByString:@"&"];                for (NSString *subResult in resultArr) {                    if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
                        authCode = [subResult substringFromIndex:10];                        break;
                    }
                }
            }
            DLog(@"授权结果 authCode = %@", authCode?:@"");
        }];        
        return [url.host isEqualToString:@"safepay"];
    }    else
    {        return [WXApi handleOpenURL:url delegate:self];
    }
    
}



作者:看我的大白眼
链接:https://www.jianshu.com/p/4e03b45e687a


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP