美文网首页IOS开发键盘上的鼓手iOS大咖说
iOS 内购笔记以及一些坑的总结

iOS 内购笔记以及一些坑的总结

作者: 未来可期me | 来源:发表于2017-01-05 00:34 被阅读5122次

    人生最终的价值在于觉醒和思考的能力,而不只在于生存。—— 亚里士多德

    jay.jpeg

    或许,正是思考的力量,最近上边要求开发直播的功能。评审之类的流程结束之后,我们的任务就是其实就是在我们的原生应用中添加一个类似于淘宝直播的这样一个直播平台。
    这么多功能其实还是都是陌生的,因为直播没做过,内购没做过,聊天室没做过!
    但是人生不就是一次一次的挑战吗!

    鸡汤.jpeg

    鸡汤总的喝点,不然开发路上的问题还不把程序猿折磨的掉光头发!

    扯淡完毕,技术研讨正式开始。。。。。。。

    内购的场景

    1.如果你购买的商品,是在本app中使用和消耗的,就一定要用内购,否则会被拒绝上线,例如:游戏币,在线书籍,app中使用的道具等。本例中,就是直播中你用来打赏用的金币,那东西可就属于消耗型的。
    2.如果是直接购买商城之类的快递包邮的那些东东,那就直接调用支付宝,微信啦,之类的三方支付就好了,淘宝,京东都玩过哈!
    比较坑的一点就是,内购的话,还要和苹果3/7分成,那就可以说,充值相同的钱,相对来说,iOS是比安卓亏的!

    内购的流程

    一.向appStore提交资料

    登录itunes connect

    第一步.png 第二步.png
    第三步.png

    操作完第三步然后记得保存

    第四步.png 第五步.png

    先点击Contact Info 的Set Up

    第六步.png

    ![Uploading 第七步_006422.png . . .]

    都填写完记得保存,然后回到上一个页面

    ![Uploading 第八步_134993.png . . .]

    第九步.png 第十步.png
    第十一步.png 第十二步.png

    进行十二步的时候可能有些银行通过苹果这个方法查不到,就需要借助百度了,一定要准确查询,否则会有问题。我这里推荐一个地址https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp

    第十三步.png

    这一步需要注意的是,货币类型可能有歧义,看你是想收美元还是人民币了,都说美元合适。不过,我做的时候为了避免事情,还是选择了CNY,支持国产。还有一点,银行账号如果是对公的账号,需要填写公司的英文名称,如果没有的话,上拼音!然后点击保存银行信息就算ok了,然后退回到最开始的页面

    第十四步.png 第十五步.png

    ![Upload 第十六步.png failed. Please try again.]

    第十七步.png 第十八步.png 第十九步.png

    这里要注意的是,虽然这个页面看起来要填写的信息很多,其实很多都没有什么卵用,都是对于美国那边什么法律需要配合的那些,一般咱们都不用,只需要把该勾选的地方勾选,然后提交就好了

    ![Uploading 第二十步_761551.png . . .]

    二十一步.png 二十二步.png

    注意:若应用是首次做内购的话,必须等审核信息通过,下面流程中,申请了产品ID,在代码中才会有对应的产品信息

    通过的样子.png

    二.创建内购项目

    第一步.png 第二步.png 第三步.png 第四步.png 第五步.png

    注意在这个流程中,我们会测试,以至于随便填写123,等数据,我们最好不要这样写,因为即使之后可以删除,但是也不能删除记录,会造成这个界面相当的乱。。。

    WechatIMG3.jpeg

    注册沙箱账号

    通过的样子.png ![Uploading 添加账号2_887315.png . . .] 添加账号2.png

    最后一步,上代码,直接复制,粘贴,测试---记得思考

    内购代码几乎类似,主要的话,就是订单验证,安全的做法是让我们的后台去验证,最好不要app验证。

    第一步导入StoreKit.framework库
    然后先看.h文件

    #import <StoreKit/StoreKit.h>
    
    enum{
    IAP0p20=20,
    IAP1p100,
    IAP4p600,
    IAP9p1000,
    IAP24p6000,
    }buyCoinsTag;
    
    //代理
    @interface RechargeVC : UIViewController <SKPaymentTransactionObserver,SKProductsRequestDelegate >
    
    {
    int buyType;
    }
    
    - (void) requestProUpgradeProductData;
    
    -(void)RequestProductData;
    
    -(void)buy:(int)type;
    
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
    
    -(void) PurchasedTransaction: (SKPaymentTransaction *)transaction;
    
    - (void) completeTransaction: (SKPaymentTransaction *)transaction;
    
    - (void) failedTransaction: (SKPaymentTransaction *)transaction;
    
    -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;
    
    -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;
    
    - (void) restoreTransaction: (SKPaymentTransaction *)transaction;
    
    -(void)provideContent:(NSString *)product;
    
    -(void)recordTransaction:(NSString *)product;
    
    @end
    
    #import "RechargeVC.h"
    
    //在内购项目中创的商品单号
    #define ProductID_IAP0p20 @"Nada.JPYF01"//20
    #define ProductID_IAP1p100 @"Nada.JPYF02" //100
    #define ProductID_IAP4p600 @"Nada.JPYF03" //600
    #define ProductID_IAP9p1000 @"Nada.JPYF04" //1000
    #define ProductID_IAP24p6000 @"Nada.JPYF05" //6000
    
    @interface RechargeVC ()
    
    @end
    
    @implementation RechargeVC
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
    
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        [self buy:IAP0p20];
    
    }
    
    -(void)buy:(int)type
    {
        buyType = type;
        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 = nil;
        switch (buyType) {
            case IAP0p20:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP0p20,nil];
            break;
            case IAP1p100:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP1p100,nil];
            break;
            case IAP4p600:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP4p600,nil];
            break;
            case IAP9p1000:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP9p1000,nil];
            break;
            case IAP24p6000:
            product=[[NSArray alloc] initWithObjects:ProductID_IAP24p6000,nil];
            break;
    
            default:
            break;
    }
        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 = nil;
        switch (buyType) {
            case IAP0p20:
            payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP0p20];    //支付25
            break;
            case IAP1p100:
            payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP1p100];    //支付108
            break;
            case IAP4p600:
            payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP4p600];    //支付618
            break;
            case IAP9p1000:
            payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP9p1000];    //支付1048
            break;
            case IAP24p6000:
            payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP24p6000];    //支付5898
            break;
            default:
            break;
    }
        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
    
    

    为什么iOS 要使用内购,不可以直接跟安卓一样,直接三方支付购买呢,不是技术上不支持,而是苹果要求这样做,他们要分红。。

    需要动态控制虚拟货币三方充值,绕过内购的可以看看下面的知乎链接,找找思路,其实不难。
    知乎链接

    [demo全部流程]http://www.code4app.com/thread-12396-1-1.html

    最后感谢下面文章的主人,在开发路上,献出的温暖,😘
    原文链接--点点点

    相关文章

      网友评论

      • UncleFool:APP审核被拒,因为不能强制用户登录才能使用内购,可是不登录怎么和账户关联呢。楼主遇到过这个问题吗?
      • 清無:![Uploading 第七步_006422.png . . .]
      • 住册新账号:我用的单例类,现在不知道该在何处removeTransactionObserver,求思路
      • rollingstoneW:购买会员必须要走app内购吗
      • lc_cat:内购商品的价格 能自己自定义吗
        未来可期me:@lc_cat 可以啊,你看那些直播不都有各种价格:smile:
      • IMKel:这里添加银行卡是干嘛的,是随便填写一张就可以了是吗?还是说这银行卡是用于收账的,求楼主告知
        IMKel:@流浪着的梦想家 谢谢:+1:
        未来可期me:@IMKel 那是苹果给你打钱用的
      • 960b0a0481df:你好,我想问一下,接入内购之后,是不是就可以不用支付宝这些了?
        未来可期me:@960b0a0481df看业务了,内购苹果是需要拿抽成的,必须的才走这种方式
      • da1794c85c33:应该是有别的状态的没finish,导致这样的状况
      • Aacmr:请问你的漏单是怎么处理的? 订单购买失败的时候,我在项目中也调了finish,但是还是会出现“您已购买此App内购买项目,此项目将免费恢复”的提示,而且上次购买失败未完成的订单,也在再次请求时充值余额成功了, 自动完成了上次没完成的订单。请问你遇到了吗?
        da1794c85c33:@Aacmr 还有别的几种状态 restore defer 在重新验证的时候怎么处理的
        Aacmr:@流浪着的梦想家 这个失败订单还得好好测下,我明天再测测。谢谢!
        未来可期me:@Aacmr 这个我倒是没遇到,你的失败订单,还能重新充值成功??
      • Aacmr:你好,请问我做的内购,收据是后台验证的,就是内购上架App Store的时候,那个环境environment需要移动端传给后台吗?还是后台自己搞定?
        Aacmr:@流浪着的梦想家 请问你是怎么传的呀?我打印的请求数据中没有环境的数据呀。能详细说一下吗?
        Aacmr:请问你是怎么传的呀?我打印的请求数据中没有环境的数据呀。能详细说一下吗?
        未来可期me:@Aacmr 我们是传给后台的
      • 翀鹰精灵:大神 你遇到过内购的时候为啥获取不到商品response.products的问题吗 ?
        lc_cat:@翀鹰女孩 大神做出来了吗 我现在也是
        翀鹰精灵:@流浪着的梦想家 我们遇到的估计不是同一个问题,我的是还没有上线的产品,说白了就是一个demo,但是一直没有获取到商品ID (其他信息配置ok)
        未来可期me:@翀鹰女孩 我那个是第一次做内购,注册的信息,还没通过,所以获取不到

      本文标题:iOS 内购笔记以及一些坑的总结

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