iOS 内购遇到的坑

https://www.jianshu.com/p/002b9b721f12

 

一.内购沙盒测试账号在支付成功后,再次购买相同 ID 的物品,会提示如下内容的弹窗。您以购买过此APP内购项目,此项目将免费恢复

  iOS 内购遇到的坑 您以购买过此APP内购项目,此项目将免费恢复.PNG
原因:

当使用内购购买过商品后没有把这个交易事件关,所以当我们再次去购买商品后就会调用以前已经购买成功的交易事件去购买因为已经购买过,才会有这个提示

解决方法:

1.当我们使用[[SKPaymentQueue defaultQueue] addPayment:payment];这个方法进行支付请求后,因为我们已经把支付所需要的信息都添加到苹果的支付队列,苹果会自动完成后续的购买请求。
在用户购买成功或者点击取消购买的后会回调- (void)paymentQueue:(SKPaymentQueue )queue updatedTransactions:(NSArray )transaction;方法返回响应的结果信息,在该方法内除了得到响应的支付信息编写自身的业务的代码外还要记得调用[[SKPaymentQueue defaultQueue] finishTransaction:transaction];方法通知苹果的支付队列该交易已经完成,否者就会调用已经购买成功的支付队列,就会出现您以购买过此APP内购项目,此项目将免费恢复这句提示。

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
    NSLog(@"调用了几次这个方法?");
    SKPaymentTransaction *transaction = transactions.lastObject;
    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchased: {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];//记得关闭交易事件

            NSLog(@"购买完成,向自己的服务器验证 ---- %@", transaction.payment.applicationUsername);
            NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
            NSString *receipt = [data base64EncodedStringWithOptions:0];
//            [self buySuccessWithReceipt:receipt transaction:transaction];
        }
            break;
        case SKPaymentTransactionStateFailed: {
            NSLog(@"交易失败");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
            break;
        case SKPaymentTransactionStateRestored: {
            NSLog(@"已经购买过该商品");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
            break;
        case SKPaymentTransactionStatePurchasing: {
            NSLog(@"商品添加进列表");
        }
            break;
        default: {
            NSLog(@"这是什么情况啊?");
        }
            break;
    }
}
2.在买次购买之前检测是否有未完成的交易如果有就关闭。
NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
   if (transactions.count > 0) {
       //检测是否有未完成的交易
       SKPaymentTransaction* transaction = [transactions firstObject];
       if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
           [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
           return;
       }  
   }

二.内购 元数据丢失

一般情况下是需要填的选项没有填写完整,还有要填写完整不然审核内购项目可能会不通过。

三.iOS 内购 您已经购买了此项目,您想免费再获取一次吗

这个是内购选择类型不匹配原因导致。
非消耗型就是消耗一次后在该appid下都能使用。
消耗型比如一些直播平台的货币 使用完以后可以在充值。
我有这个问题是 最开始我们的项目是购买完产品以后可以永久使用,后来修改成充值余额购买,但是我没有去修改类型才导致的这个错误,

四.测试时记得把App Store上的账号注销,不然会出现购买失败,注销账号后,在进行内购时登录沙盒测试账号。

五.In-App Purchase二次验证

IOS在沙箱环境下购买成功之后,向苹果进行二次验证,确认用户是否购买成功。
当应用向Apple服务器请求购买,成功之后,Apple会返回以下四个数据给应用

  1. 产品标识符: product Identifier[在itunes store应用内定义的产品ID,例如com.公司名.产品名.道具名(com.xxxx.317hu.66)]
  2. 交易状态: state
  3. Receipt:很长的一段字符串,大概49行,作为二次验证的重要依据
  4. 交易标识符: transaction Identifier 我们需要把Receipt发送給苹果的苹果的服务器验证,用户的购买信息是否真实
交易状态 解释
Purchased 购买成功
Restored 恢复购买
Failed 失败
Deferred 等待确认,儿童模式需要询问家长同意

苹果返回状态码 状态码

状态 描述
21000 App Store不能读取你提供的JSON对象
21002 receipt-data域的数据有问题
21003 receipt无法通过验证
21004 提供的shared secret不匹配你账号中的shared secret
21005 receipt服务器当前不可用
21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
    24人点赞   iOS开发    

作者:骑马纵天下
链接:https://www.jianshu.com/p/002b9b721f12
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
上一篇:mysql优化之事务隔离级别和IO关系


下一篇:事务隔离性的两种实现方式