iOS Apple内购及掉单问题

作者: 走在路上的小菜鸟 | 来源:发表于2016-04-27 15:06 被阅读16143次

在iOS开发中你是否遇到过购买虚拟物品的而无法使用第三方支付的问题,让不熟悉Apple内购的你不知所措,废话不多说,直接搞起。

第一部分:协议


第1步.png 第2步.jpg
第3步.jpg
第4步.png
第5步.png
第6步.jpg
第7步.png
第8步.jpg
第9步.jpg
第10步.png

CNAPS CODE 查询地址
https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp

第11步.jpg 第12步.jpg 第13步.png
第14步.png
第15步.jpg
![第16步.jpg](http:https://img.haomeiwen.com/i1975881/dd1ac4d3d8fdd555.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
第17步.png
第18步.png

协议Done,我们现在已经和Apple签订了协议,接下来该去上架商品了

第二部分:创建内购项目

第1步.png
第2步.png
第3步.png
第4步.png
第5步.png
第6步.png
第7步.png

Apple内购的价格是等级制的,无法自己随意定价,而且每比订单成交都要向苹果缴纳百分之30的抽成,坑爹吧!!

第三部分:App代码集成

介绍一下APP内购的步骤:

一般的内购分为两种,一种是我们app有自己的服务器,一种是本地的,像我们玩的闯关游戏需要购买关卡一般都是本地的,像那种联网手游,会员VIP的基本都是服务器的。

服务器模式:
1.调用服务器接口创建一个商品的订单
2.请求Apple的商品列表
3.选取商品调用苹果支付
4.支付成功(会返回凭证)
5.把支付成功的返回凭证上传到APP服务器(带上订单的ID,有利于后台判断是哪个订单支付成功)
6.APP服务器保存该凭证等数据并像苹果服务器发起凭证验证,验证成功则发送商品

本地模式:
1.请求Apple的商品列表
2.选取商品调用苹果支付
3.支付成功(会返回凭证)
4.把凭证与商品发送状态保存到一个本地的数据库
5.app调用apple服务器的验证API
6.验证成功发送商品并改变数据库的物品发送状态

最后一步了,是不是有些欣喜,最后在代码中实现

首先导入StoreKit.framework库

#import "ApplePayVC.h"
#import <StoreKit/StoreKit.h>

//在内购项目中创的商品单号,从itunesConnect里可以看到
#define ProductID_1 @"product1"
#define ProductID_2 @"product2" 
#define ProductID_3 @"product3" 
#define ProductID_4 @"product4"
#define ProductID_5 @"product5"

@interface ApplePayVC ()
{
    NSString *buyProductId;
}
@end

@implementation ApplePayVC

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [self buyProduct:ProductID_1];
    
}

-(void)buyProduct:(NSString *)productId
{
    buyProductId = productId;
    if ([SKPaymentQueue canMakePayments]) {
        [self RequestProductData];
        NSLog(@"允许程序内付费购买");
    }
    else
    {
        NSLog(@"不允许程序内付费购买");
        UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"提示"
                                                            message:@"您的手机没有打开程序内付费购买"
                                                           delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
        
        [alerView show];
        
    }
}

-(void)RequestProductData
{
    NSLog(@"---------请求对应的产品信息------------");
    NSArray *product = [[NSArray alloc] initWithObjects:buyProductId,nil];
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];
    
}

//<SKProductsRequestDelegate> 请求协议
//收到的产品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"-----------收到产品反馈信息--------------");
    NSArray *myProduct = response.products;
    NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);
    NSLog(@"产品付费数量: %d", (int)[myProduct count]);
    // populate UI
    for(SKProduct *product in myProduct){
        NSLog(@"product info");
        NSLog(@"SKProduct 描述信息%@", [product description]);
        NSLog(@"产品标题 %@" , product.localizedTitle);
        NSLog(@"产品描述信息: %@" , product.localizedDescription);
        NSLog(@"价格: %@" , product.price);
        NSLog(@"Product id: %@" , product.productIdentifier);
    }
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:buyProductId];
 
    NSLog(@"---------发送购买请求------------");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}
- (void)requestProUpgradeProductData
{
    NSLog(@"------请求升级数据---------");
    NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
    SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
    
}
//弹出错误信息
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"-------弹出错误信息----------");
    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
                                                       delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
    [alerView show];
    
}

-(void) requestDidFinish:(SKRequest *)request
{
    NSLog(@"----------反馈信息结束--------------");
    
}

-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"-----PurchasedTransaction----");
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
}

//<SKPaymentTransactionObserver> 千万不要忘记绑定,代码如下:
//----监听购买结果
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果
{
    NSLog(@"-----paymentQueue--------");
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:{//交易完成
                [self completeTransaction:transaction];
                NSLog(@"-----交易完成 --------");
                
                UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@""
                                                                    message:@"购买成功"
                                                                   delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
                
                [alerView show];
                
            } break;
            case SKPaymentTransactionStateFailed://交易失败
            { [self failedTransaction:transaction];
                NSLog(@"-----交易失败 --------");
                UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"提示"
                                                                     message:@"购买失败,请重新尝试购买"
                                                                    delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
                
                [alerView2 show];
                
            }break;
            case SKPaymentTransactionStateRestored://已经购买过该商品
                [self restoreTransaction:transaction];
                NSLog(@"-----已经购买过该商品 --------");
            case SKPaymentTransactionStatePurchasing:      //商品添加进列表
                NSLog(@"-----商品添加进列表 --------");
                break;
            default:
                break;
        }
    }
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction

{
    NSLog(@"-----completeTransaction--------");
    // Your application should implement these two methods.
    NSString *product = transaction.payment.productIdentifier;
    if ([product length] > 0) {
        
        NSArray *tt = [product componentsSeparatedByString:@"."];
        NSString *bookid = [tt lastObject];
        if ([bookid length] > 0) {
            [self recordTransaction:bookid];
            [self provideContent:bookid];
        }
    }
    
    // Remove the transaction from the payment queue.
    
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    
}

//记录交易
-(void)recordTransaction:(NSString *)product{
    NSLog(@"-----记录交易--------");
}

//处理下载内容
-(void)provideContent:(NSString *)product{
    NSLog(@"-----下载--------");
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"失败");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    
}
-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{
    
}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@" 交易恢复处理");
    
}

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
    NSLog(@"-------paymentQueue----");
}

#pragma mark connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"%@",  [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    switch([(NSHTTPURLResponse *)response statusCode]) {
        case 200:
        case 206:
            break;
        case 304:
            break;
        case 400:
            break;
        case 404:
            break;
        case 416:
            break;
        case 403:
            break;
        case 401:
        case 500:
            break;
        default:
            break;
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"test");
}

-(void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听
    
}

@end
我们已经完成了内购的付款操作了,至于如何给到用户商品就在
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
这个代理方法里面就行操作

你以为这样就完成了么?那你就惨了,APP上线以后你就会发现各种掉单问题,那时你心中肯定有10000只草泥马在奔腾,接下来我们来看看如何避免掉单。

附:解决掉单篇

我们先来看看有哪些请况会发生掉单:

①. 在ApplePay付款成功后由于网络或各种原因没有返回Transaction(SKPaymentTransaction),从而不能得到凭证去Apple服务器验证订单的正确性。
②.苹果服务器成功返回了Transaction,但是在APP在上传凭证给服务器时发生了网络或各种原因,造成了凭证的丢失,产生了掉单(用户付了款却没有得到相应的商品)

[SKPaymentQueue defaultQueue]这个队列里面存着所有的已支付,未支付的订单,而且需要手动移除,而APP每次启动的时候都会去判断这个队列里面是否为空,如果不为空的话会调用<SKPaymentTransactionObserver>代理的

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果

所以我们可以把AppDelegate设置成这个协议的代理并实现这个方法,当然我一般是会写一个遵循<SKPaymentTransactionObserver>的工具类单例,毕竟协议是一对一的,不管是哪里的支付回调,都只走这个类,统一处理。

上面我们说到每次APP启动时都会判断订单队列是否为空,而且队列需要手动移除,所以我们可以在确保商品已经成功发放到用户手中再做移除操作,这样就完美了。

移除代码如下:

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];

iOS 7.0后 我们是用[[NSBundle mainBundle] appStoreReceiptURL]来获取凭证。

注:苹果官方内购验证文档
https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

到这里可能有些童鞋会懵逼了,他会说我付款后怎么和订单关联上啊,完全没有区分的地方啊!
解决办法如下:当我们创建苹果订单初始化SKPayment时我们应该使用SKMutablePayment,这个类里面有一个参数叫applicationUsername的成员变量,我们可以把后台服务器的订单号写到这里,在付款成功后返回的SKPaymentTransaction里面能拿到这个参数,然后就带着它去请求本地服务器.

我们把内购搭建好直接进行测试,会提示你购买失败对吧?内购测试我们要到iTunes connection 里去添加沙盒测试员

1.png
2.png
3.png

然后我们测试的时候换上这个appleId就能进行测试了

perfect!!!!!!
哈哈,第一次写技术博客可能写得不好,猿媛们哪里不明白可以在下面提问!!!

相关文章

  • iOS Apple内购及掉单问题

    在iOS开发中你是否遇到过购买虚拟物品的而无法使用第三方支付的问题,让不熟悉Apple内购的你不知所措,废话不多说...

  • Apple内购及掉单设计

    AppStore充值至关重要,开发流程别人总结很多,比如这篇iOS Apple内购及掉单问题,我就不多说了,就总结...

  • IOS 内购掉单问题

    向服务器请求OrderID,向ios发起内购时传递给payment: SKMutablePayment *paym...

  • iOS内购丢单的解决方案

    iOS内购这块的开发一直比较麻烦,除了各种购买选项的问题,最恶心的问题就是丢单问题。丢单就是iOS内购过程中付了钱...

  • iOS内购-如何防止掉单

    好久没有写博客,不是因为工作太忙,只是太懒罢了。昨日,经理开除同部门兄弟(中午还和那个哥们一起吃饭,下午,人说被 ...

  • iOS内购掉单处理教程

    1.前言 最近公司的项目需要接入苹果内购支付。看了下项目里面,内购这个模块的功能之前就已经写好了,然后就跟后台调试...

  • iOS 内购漏单问题解决参考方案

    问题:iOS内购漏单的问题 事由: 不久前,有用户反映,大概意思是这样:苹果扣款成功了,但是没有发放应得的内购产品...

  • iOS 内购掉单 补单 解决整理

    本小记准备两天写完,起因还是因为自己在做内购时,去网上找了很多资料,但是都没有给出具体的补单方案,都只是泛泛而谈,...

  • 苹果内购(IAP)及掉单处理

    官方文档In-App Purchase 首先Xcode里的Capabilities中的In-App Purchas...

  • iOS内购(最新)-内含遇到的"坑"

    内购--- iOS 客户端进行虚拟商品的支付方式 官方中文内购教程文档:http://help.apple.com...

网友评论

  • 8b29bb6873e4:请问一下为什么 每次我一进来 控制器页面就 走 updatedTransactions 这个方法 的交易完成情况啊,然后就弹出输入appleid的alert,我只是再viewdidload里添加了[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    8b29bb6873e4:@羽惊 3q
    羽惊:每个支付完成都得调用[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    如果未调用 这个支付就会一直存在队列中
    你每次进来调用这个[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    就是检测队列中是否有订单未完成
    每次弹出 支付的alert 就是说明你有订单未完成
  • BohrIsLay:订阅型内购,vip按月收费,和按年收费,如果用户已订阅按月收费,删除app后,再次进入,此时还是可以进入vip购买页面,这个时候用户再选择按年收费购买,岂不是又另外收取年费,这个如何控制?
  • Exia_L:请问楼主有没有遇到过正式环境中走- (void)failedTransaction:(SKPaymentTransaction *)transaction 的情况,审核过了一天了,测试环境可以,是不是和苹果服务器有关系啊
  • Alice爱吃鱼:请问下有遇到在请求的时候,一直报无法连接到iTunesstore;或者是请求到了,支付的状态就是fail的问题吗?
  • 择势量投:谢谢分享,很详细,补充下控制器 需要遵循 <SKPaymentTransactionObserver,SKProductsRequestDelegate>
  • 正确的道路上用笨方法:请问 所有内购都抽成?
    圣斗士皮皮:嗯 苹果,谷歌的内测都收的
  • 拉风的胖鱼:请问,你第一个掉单的方法,是在启动APP的时候加上监控就行了么?
  • 剪刀_石头_布:上线审核的时候是给https://sandbox.itunes.apple.com/verifyReceipt这个测试服务器吗?
    圣斗士皮皮:嗯 审核那边是用泥泥沙盒账号测试的
  • d02dde29eab0:想问下“遵循<SKPaymentTransactionObserver>的工具类单例”这个是怎么写的
  • 大斜的张:- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions 这个方法一直返回购买失败的方法 说是无法连接iTunes store
  • Exia_L:请问一下,服务器与苹果服务器验证是怎么弄的,后台不是很清楚怎么弄
  • zeqinjie:请问我app最近内购订单信息获取失败是什么原因,你们有遇到过吗??
  • d96e017e2494:请问 transaction.payment.applicationUsername 为空怎么解决
    887d1fc86fe6:transaction.payment.applicationUsername 这个不能作为信任的值存储。苹果这个字段存在BUG,这个值在某些情况下会为nil, 所以需要换一种存储验证方式,不能依赖这个字段。至今未修复,这个是好久以前就提出的BUG
  • 成功先森:请问,后台订单号如何生成?求个步骤
    圣斗士皮皮:保证唯一即可。时间戳,snowflake,数据库的自增等等
  • 星座是射手座:在ios10.3.2系统上response.products数组返回为0,10.3.1支付就没有问题
  • 0710108eced5:[SKPaymentQueue defaultQueue]每次成功后都有finish,但是凭证验证通过返回的订单信息总是包括了所有的历史订单,请问作者遇到过这种情况吗?
  • Aacmr:请问,只要在确保商品已经成功发放到用户手中再做移除操作,[[SKPaymentQueue defaultQueue] finishTransaction: transaction]。你这句话的意思是不是在后台验证成功之后再做移除操作,因为只有后台验证成功了,商品才能发放到客户手中。这样就可以避免漏单了吗?这样就能完美实现了吗? 我看的其他的文章,还要把收据存储到本地,还有失败重发机制,感觉比较麻烦,如果漏单问题,你这个能一句代码解决,真的是再好不过了。
    走在路上的小菜鸟:@Aacmr 可以的,就是你自己管理购买队列,我也是做课程视频啊,你们是做哪块
    Aacmr:@走在路上的小菜鸟 作者呀,我的验证收据是在我们后台服务器验证的。就是不知道漏单丢单移动端要做哪些操作? 就像17楼那个白牛桑说的“要在确保商品发放到用户手上的之后,才执行[[SKPaymentQueue defaultQueue] finishTransaction: transaction]”这句代码,就能解决吗?我做的是购买课程视频。
    走在路上的小菜鸟:这个只是把漏单的问题从移动端转移到服务端,如果是那些单机游戏的话是可以做在移动端,放在服务器端的安全性肯定要比你在本地存储的要好的多,当你付完钱APPLE返回你的支付凭证,你是可以在移动端去像苹果服务器验证这个订单,成功后再去调取服务器的发放商品的接口,但是这样的话安全性得不到保障,很容易被人攻击
  • YYYYYY25:你好,我想问一下,购买成功后,使用base64进行验证,验证成功后,怎么让这个信息失效呢?如果被人抓包,是不是一个购买凭证就无限刷了?
    走在路上的小菜鸟:@YYYYYY25 我也不清楚Apple那边是否可以重复验证,应该是可以的,付完钱要做什么操作是你们决定啊,被人抓包也没有问题,我们这里是这样做的,点击付完款,会获取到苹果返回的一系列信息,然后把这些信息提交给自己的服务器并对应订单,然后由服务器去与苹果服务器进行验证,验证成功则发放商品,并且使那个订单及验证信息失效,这个也是由我们自己控制的,这里也没有任何问题对吧!如果你们自己的接口数据什么的都不进行加密的话被抓包就没法了
  • Aacmr:请问你的掉单处理写哪里了? 标出来行不? 有去服务器验证吗?
  • ab149a495e88:楼主有demo吗,AppDelegate那一块怎么处理的,还是不太清除
  • df0582e56108:①. 在ApplePay付款成功后由于网络或各种原因没有返回Transaction(SKPaymentTransaction),从而不能得到凭证去Apple服务器验证订单的正确性。
    这种情况如何处理
    白牛桑:作者不是说了吗,我们要在确保商品发放到用户手上的之后,才执行[[SKPaymentQueue defaultQueue] finishTransaction: transaction];原理如下:
    [SKPaymentQueue defaultQueue]这个队列里面存着所有的已支付,未支付的订单,而且需要手动移除,而APP每次启动的时候都会去判断这个队列里面是否为空,如果不为空的话会调用<SKPaymentTransactionObserver>代理的- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//方法

  • 0x00chen:楼主在吗,我用沙盒注册的appleID 支付的时候会出现“验证Apple ID 打开“设置”以继续使用“我的沙盒邮箱”登录”这个弹框,这种情况怎么解决啊,
  • 6a717ad0ba8c:楼主有没有碰到这样的问题, 后台记录了多笔订单,最后和苹果对账的时候,发现少了许多,我怀疑是网上的黑卡造成的。这个对公司的对账来说就多了许多财务问题, 而且也没有证据找到是哪些用户用了黑卡(多半是淘宝代充)。 您有好的解决方法没? :pray:
  • 庄开心:请问我使用了applicationUsername来记录订单号,但是某些时候,当第二次回调updateTransaction方法时,applicationUsername 是空的,把我之前赋的值丢掉了,所以导致的还是丢单,这种情况怎么处理呢?
    d96e017e2494:@zeqinjie 如何解决?求教
    zeqinjie:@风逝_4940 +1 如何解决好 难道缓存订单号
    0a9b5c667d1e:你好,我也遇到这个问题了,请问你是怎么解决的?applicationUsername存储的订单号是多少位的?
  • 56d35fdf1a2a:大神 我是用keychain来存储未完成订单信息的 当点击支付时 先检查keychain中是否有订单 有的话 我调用了一个方法 使[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 但是为什么没用哇 不会处理[[SKPaymentQueue defaultQueue] addTransactionObserver:self];的方法
  • 超_iOS:applicationUsername这个字段存用户id,和苹果返回的信息一起传给后台是不是就可以了?另外在appdelaget中添加监听(程序刚进来)和(程序挂起时)移除监听是不是也可以解决掉单问题?
    辣椒小鱼:@_超 我也发现 我也有一例 两个订单 票据一样 ,你的解决了吗
    超_iOS:@走在路上的小菜鸟 我现在遇到用户的多次内购,他们的购买凭证都是一样的.这个楼主有什么想法么.想请教
    走在路上的小菜鸟:@李二超 是在APPdelegate里面添加监听 一般username都是存订单号吧,然后付完款就调一下完成订单的接口就可以避免掉单了
  • bb19f132a87c:如果是ios6要怎么关联服务端生成的订单号呢?
  • bb19f132a87c:弱弱问下,apple审核的时候,需要提供一个真实的appid让他测试内购吗?
    走在路上的小菜鸟:@nerver_more 需要啊,提交审核的时候要写上去
    bb19f132a87c:@走在路上的小菜鸟 需要把这个沙盒账号提供给apple测试吗?
    走在路上的小菜鸟:@nerver_more 你可以用开发者账号添加沙盒测试账号的
  • 275e1838f50d:像购买视频课程和电子书是不是只能购买一次?还是可以无限制的购买?
    慕诩:层主这个问题解决没?视频课程和电子书这样的属于那种内购类型?价格怎么办
    走在路上的小菜鸟:@php程序员 那要看你的需求是怎么样的
    走在路上的小菜鸟:@php程序员 这要看你们的需求了,需要哪种都能实现
  • imimbluer:如果要在服务器校验交易收据成功返回后再调用finishTransaction的话,请问,服务器返回数据中是不是需要带上订单号。然后遍历transactions中的SKPaymentTransaction,通过订单号找到校验的那个SKPaymentTransaction,在finish掉,是这样吗?
    Coke26:@imimbluer 同问这个方式是否可行,另外怎么给苹果订单附带订单号消息和服务器订单号交验?
  • d079da11e5f9:你在appdelegate 怎么处理的
    走在路上的小菜鸟:@路灯下眺望 这个我倒没有试过
    d079da11e5f9:@路灯下眺望 我想问下你做内购时碰到过如果用户的Apple id 绑定的是信用卡可以购买成功,如果绑定的不是信用卡会产生购买失败!
    走在路上的小菜鸟:@路灯下眺望 appdelegate里面就是实现监听订单回调的方法啊
  • d079da11e5f9:楼主你能把处理掉单的那部分代码贴出来吗?我这个地方遇到了一些问题!谢谢
    d079da11e5f9:@路灯下眺望 我掉单处理是将苹果返回的单号保存在本地,如果后台验证成功就移除,但是不能没有写在appdelegate中
    走在路上的小菜鸟:@路灯下眺望 如果哪里不懂可以问我
    走在路上的小菜鸟:@路灯下眺望 代码已经写在那里啦!你仔细看看吧
  • 294b8c38d51e:楼主写的太好了,最近做内购遇到坑不少还没跳出来,请教一下。我每次购买后,不能及时回调observer的方法,但是下次app启动就出现了上一次购买后写在observer里面的各种打印。还有一个问题,我的产后是消耗型的,为什么当我重复购买,苹果会弹窗说该项目已经购买,已经帮您恢复购买!太无解了,求指导!
    294b8c38d51e:@走在路上的小菜鸟 试了好多次,第一次购买完,updateTansanction那个方法硬是来不了,每次重启app就来了,但是显示上一次的本该打印的结果。还有我把测试账号删了换了一个,然后购买各种提示要我输入密码,默认是之前设置的那个Apple账号,原本以为是延迟,过了一天了居然还是这样,之前的测试号还能购买成功。仔细看了,我就配了一个消耗品,确实是消耗品没错!😔😔😔😔
    走在路上的小菜鸟:@_却真真如果购买完毕回调没有返回,下次启动APP的时候判断购买队列里面有东西的话还会回调的
    走在路上的小菜鸟:@_却真真 如果是消耗类型的,是可以无限制的重复购买,可能是你在ituns里面配错了吧,仔细检查一下
  • LightReason:我不是演双簧,我最近在做内购,遇到了问题会及时骚扰你的 哦
  • 76440382f762:哇,作者写的真不错啊,刚好我也在做这个功能,可以教一下我吗?
    Zrocky:@McMilo 这双簧演的, 忒假了吧

本文标题:iOS Apple内购及掉单问题

本文链接:https://www.haomeiwen.com/subject/frscrttx.html