iOS内购-如何防止掉单

好久没有写博客,不是因为工作太忙,只是太懒罢了。昨日,经理开除同部门兄弟(中午还和那个哥们一起吃饭,下午,人说被 HR找去谈话,就走了,哎,生活本不应该苟且,就应该是有诗和远方,若没有诗和远方,那也应该有和曹文轩笔下的草房子、油麻地的田野吖),瞬间有了危机感,害怕那一天也我会失业。我上有八十岁老母,至于下吗?嘻嘻,今年,刚满足18岁,所以还没有小呢。。。。。
呵呵,不啰嗦了,今天要讲述一下,工作中如何处理内购成功后,如何防止掉单。对内购比较熟悉,可以直接看最后面章节如何防止掉单,大神可以略过。如下用一个思维导图展示内购的大体思路,本文也是按照思路讲述。

Snip20170414_4.png

一、什么是APP内购

  • APP内购简称IAP(In-App Purchase)
  • 翻译:在APP中购买,也就是在APP中让用户购买东西
  • 用户在APP中购买东西的方式:
    1> 通过第三方支付购买,比如支付宝/微信支付.
    2> APP内购
  • 集成时如何选择是要那个第三方支付还是内购?
    1> 如果用户购买的物品和应用程序本身有关系,必须采用内购(如果say NO,苹果不允许上架)
    2> 只有购买的物品与应用程序无关,才可以使用第三方支付.(比如淘宝衣服/京东电子产品/百度外卖)
  • 内购的盈利需要和苹果3:7分(苹果3,公司7)
  • 内购的常见类别:
    1> 消耗品:用完就没.(比如欢乐豆/阅读豆)
    2> 非消耗品:购买一次,永远存在.(比如游戏装备等)

二、如何集成APP内购

  • 1.对应程序的BundleID和开发者中心配置的APPID必须是明确的
    1> 明确的APPID才能做内购(不再详细介绍)

  • 2.在iTunes Connect中创建应用程序,并且添加内购项目(让购买的物品)
    1> 填写好应用程序的基本信息
    2> 创建内购项目
    3> 添加内购项目
    4> 添加测试账号(用于测试内购)

  • 3.在程序中集成内购
    1> 内购代码

三、添加内购项目

因为这样的文件的技术文章,网上一大把,就不多余介绍。具体请参考iTunes Connect(一) —— iOS应用上架到AppStore

四、添加内购项目

由于没有配置过财务相关的信息,请参考iOS开发 内购流程 手把手教你还不学?

五、代码的实现

1 、向苹果服务器请求

/*
 向苹果服务器发送内购请求,并得到内购有价格,将价格返回到游
 */
-(void)requestProductWithIDs:(NSArray*)productIDs{
    
    //向苹果请求,得到可以卖的产品
    NSSet *productId = [NSSet setWithArray:productIDs];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:productId];
    request.delegate = self;
    
    [request start];
    
}

2、苹果通过代理返回,将产品保存起来,并把产品的价格和id通过sendMsgToGame:发回给游戏,让Unity3D 来展示物品信息。

//SKProductsRequestDelegate 代理方法
// Sent immediately before -requestDidFinish:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    if (!response ) {
        NSLog(@"sorry,服务器没有响应");
        return;
    }
    //拿到苹果服务器返回的物品,并排列其顺序
    NSArray<SKProduct*> *products = [response.products sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(SKProduct* obj1, SKProduct* obj2) {
        return [obj1.price compare:obj2.price];
    }];
    
    //设置字典,存放每个product 的id 和价格
    NSMutableDictionary *productDict = [NSMutableDictionary dictionary];
    
    //product 和ID的字典
    NSMutableDictionary *productDictID = [NSMutableDictionary dictionary];

    
    for (SKProduct *product  in products) {
        NSString *key = product.productIdentifier;
        NSString *value = [NSString stringWithFormat:@"%@",product.price];
        if ( key && value){
            //将物品的价格和id保存在字典中
            [productDict setObject:value forKey:key];
            [productDictID setObject:product forKey:key];
        }
        _productDict = [NSDictionary dictionary];
        
        //记录物品
        _productDict =productDictID.copy;
    }
    
    NSDictionary *mDict = [[NSDictionary alloc] initWithObjectsAndKeys:@"999",@"type",productDict,@"products", nil];
    //将物品的信息,发送给游戏,让Unity3D 来展示物品信息。
    [GDMsgService sendMsgToGame:mDict];
}

3、设置交易事件的监听者

-(instancetype)init{
    if (self = [super init]) {
    //设置交易队列的监听者
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    return self;
}

4、移除交易事件的监听者

-(void)dealloc{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

5、在苹果商店购买商品,创建票据,将票据加入在交易队列中

#pragma mark - 购买商品
- (void)buyProduct:(SKProduct *)product
{
    // 1.创建票据
    SKPayment *payment = [SKPayment paymentWithProduct:product];
    
    // 2.将票据加入到交易队列
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
    // 3.添加观察者,监听用户是否付钱成功
    // [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

6、实现观察者协议中的方法,来监听交易的变化

#pragma mark - 实现观察者协议中的方法,来监听交易的变化
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
 
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchasing:
            {
                NSLog(@"正在购买商品");
              
            }
                break;
                
            case SKPaymentTransactionStatePurchased:
            {
                if (transaction.payment.productIdentifier) {
initWithObjectsAndKeys:@"7","type",transaction.payment.productIdentifier,@"productID",@"0",@"result", nil];         
                    NSDictionary *mDict = @{@"type": @"7",@"productID":transaction.payment.productIdentifier,@"result":@"0"};
                    [GDMsgService sendMsgToGame:mDict];
                }
                NSLog(@"购买成功.给用户对应商品");
                [queue finishTransaction:transaction];
            }
                break;
                
            case SKPaymentTransactionStateFailed:
                NSLog(@"购买失败");
                [queue finishTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateRestored:
                NSLog(@"恢复购买");
                [queue finishTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateDeferred:
                NSLog(@"未决定状态");
                break;
            default:
                break;
        }
    }
}

六、如何防止掉单

相信上面代码大家都应该很熟悉,但是第六步的“实现观察者协议中的方法,来监听交易的变化”,是有问题的。如果用户付钱了,但是游戏没有得到收据,那么该怎么办?其实现有两种方式用来处理,具体的代码实现就没有写(后续会更新),只是两种可行的思路。

第一种是无服务器(因为是单机游戏,老大说不需要服务器)

将收据存放在本地中,然后再将数据发送给游戏,如果游戏收到数据,将返回内容给SDK,这样就可以删除本地的收据。
A、游戏将用户点击的产品 id 和 点击时的时间(点击时间作为 key 存放在本地) 返回给 SDK(客户端)。
B、用户购买成功,将以时间作为key, 产品id 和价格组合成数组 作为value,保存在本地中
C、SDK(客户端)将时间、产品id 和价格发送给游戏。
D、游戏接收成功时,会返回 点击购买的时间和reslut,SDK(客户端)将删除本地购买信息。
E、假如本地有购买信息,将按照上面C和D的步骤操作。

Snip20170414_3.png
第二种有服务器

大致思路都是一样的,先将成功买的信息存储在本地数据库中,然后再发送给服务器,成功发送给数据库后,再删除本地数据库中的成功购买的信息。


Snip20170414_7.png

若有不足之处,请指正,感恩!
May maker help us all!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 购买过程的最后一部分是应用程序等待应用商店处理支付请求,存储本次购买的信息以便将来启动,下载购买的内容,然后标记交...
    Dosun阅读 1,114评论 0 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,268评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,982评论 4 60
  • 蒙无,外号丑无,五官精致、举止优雅,是小镇最丑的人。 1. 蒙无所在的小镇叫绝世镇,以美人出名; 镇上的美人有很多...
    aishe阅读 307评论 0 0
  • 文/苏卿扬 2. 寂静无声的夜晚,寒风瑟瑟,街道上的角落里,几只老鼠在啃食着人们掉落在地上的食物残渣和垃圾。这时,...
    苏卿扬阅读 216评论 0 0