精华内容
下载资源
问答
  • App内购买

    千次阅读 2016-08-08 16:51:42
    App内购买



    测试环境搭建

    1. 添加测试用户
    测试具有应用内购买功能的应用需要使用 iTunes Connect 的测试用户,不能是 iTunes Connect 的真实用户,也
    不能是 App Store 的真实用户。当管理员成功登录 iTunes Connect 后,进入用户和职能模块->沙盒技术测试员,点击“+”直接进行创建



    2. 创建App ID

    Bundle ID => Bundle Identifier


    3. 添加空白应用IAPDemo
    我们在做别的应用测试时不需要使用
    iTunes Connect ,更不需要使用它添加空白的应用,这个操作一般是在应
    用发布时 使用



    4. 为应用添加购买产品
    iTunes Connect ->我的App ->自己的应用 ->功能 -> App内购买项目 -> “+”号

    这里我们选择的是 Non-Consumable (非消耗型产品),然后进入应用内购买信息输入界面


    在下图中, Reference Name 是显示在 iTunes Connect 里的名字,这个名字在应用里是不可见的。 Product ID
    Product identifier (产品标识符),它具有唯一性,因此建议采用“包标识符 + 产品名”,我们这里输入的是
    com.51work6.IAPDemo.elves 。将 Cleared for Sale 设定为 YES 状态时,这些产品就可以购买了。 Price Tier 是产品的
    价格。


    点击 Add Language 按钮,弹出如图 14-44 所示的对话框,在这里可以输入客户端要显示的相关信息,其中
    Language 是要显示的语言, Display Name 是该语言下显示的产品名, Description 是产品的描述。当然,我们可以根
    据需要添加多种语言

    上传产品预览图片,它并不会显示在客户端,只是审核时 使用。但这里必须上传图片,并且图片的大小也有要求。输入完成后保存





    注意:
    1.正确设置上面的信息之后,有时候需要等待2-24个小时之后才能正确获得内购买的产品信息

    invalidldentifiers无效的标示符,products.count = 0
    2.

    也必须设置,不然无法获取内购买的产品信息


    创建项目

    1. 创建工程和初始化处理
    工程添加必要的框架 StoreKit.framework

    DEMO:
    展开全文
  • App内购

    2014-08-18 14:39:18
    手游开发商认为APP内购是游戏盈利的最有效方式,他们也最喜欢用这种方式来使游戏赚钱。  以上观点来自于VentureBeat Intel的一篇新调查报告,报告的数据来自于176家开发商超过1000款的游戏。在该报告的一张盈利...

      手游开发商认为APP内购是游戏盈利的最有效方式,他们也最喜欢用这种方式来使游戏赚钱。

      以上观点来自于VentureBeat Intel的一篇新调查报告,报告的数据来自于176家开发商超过1000款的游戏。在该报告的一张盈利策略坐标图中,内购不管是在“受欢迎度调查”轴,还是“有效性”轴都处在最高的位置,而载入广告、横幅广告和视频广告在这两方面表现也还不错。

      另外还有其它一些方式,效果也不错但不是非常受欢迎,如:积分墙、推广墙、应用墙以及APP内推荐。这些方式让用户更具自主权并可以有选择地参与使用这些广告,同时游戏开发商从中可以得到盈利。

     

    付费下载——手游中曾经赚钱的一种方式,现在慢慢变得不那么受欢迎,效果也没那么好了。不过这也不足为奇,现在手游更好使的赚钱方式就是免费下载增值盈利。如在美国,苹果App Store的统计中有81%的收入是来自免费增值型游戏的,而在全球的话,这个百分比还要更多。

     

    展开全文
  • 您的首个 App 购买项目必须以新的 App 版本提交。请从 App 的“App 购买项目”中选择然后点击“提交”。 在上传二进制文件并提交首个 App 购买项目以供审核后,您可以使用下表提交其他 App 购买项目。 ...
    您的首个 App 内购买项目必须以新的 App 版本提交。请从 App 的“App 内购买项目”中选择然后点击“提交”。
    

    在上传二进制文件并提交首个 App 内购买项目以供审核后,您可以使用下表提交其他 App 内购买项目。


    这个提示出现,就是把app的二进制文件提交一次。你要先提交一次带二进制文件的,然后才可以用

    展开全文
  • iOS开发之内购完全笔记 解决无限提示 --(您已购买此 App 内购买项目。此项目将免费恢复。)的问题 梳理内购逻辑 记录个人集成过程中遇到的问题点与大家分享

    1、内购流程

    • 1、在 AppStore 中创建相应的物品,创建内购沙盒测试账号
    • 2、客户端从后台获取相应的物品 ID (当然也可以再客户端写死,但后期扩展性就受限制了)
    • 3、依据相应的物品 ID 请求商品的相关信息
    • 4、依据商品信息创建订单请求交易
    • 5、依据返回的订单状态处理交易结果
    • 6、请求后台再次验证订单状态
    • 7、依据后台返回结果处理相关逻辑

    2、创建内购物品以及沙盒测试账号

    3、客户端编写相关代码

    • 再这里我把和支付相关的逻辑都抽取到了一个单例中,在最后贴上个人梳理的相关代码大家一起学习

    4、做内购过程中遇到的坑


    • 1、内购沙盒测试账号在支付成功后,再次购买相同 ID 的物品,会提示如下内容的弹窗。

      您已购买此 App 内购买项目。此项目将免费恢复


      解决方法:在使用

      [[SKPaymentQueue defaultQueue] addPayment:payment];

      将支付信息添加进苹果的支付队列后,苹果会自动完成后续的购买请求,在用户购买成功或者点击取消购买的选项后回调

       - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction;

      方法返回响应的结果信息,在该方法内除了得到响应的支付信息编写自身的业务的代码外还要记得调用

      [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

      方法通知苹果的支付队列该交易已经完成,否者就会已发起相同 ID 的商品购买就会有此项目将免费恢复的提示。


    • 2、每次启动一个新的内购支付流程,刚发起的时候系统就会调用- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction;这个方法,结果扰乱一部分的支付业务逻辑


      在 SKPaymentQueue 被启动并且添加了 addObserver之后,如果其判断到有未完成的交易,会主动调用paymentQueue updatedTransactions 这个方法来继续完成相关的交易流程,所以如果在上面那种情况下得到结果后不去调用 finish 接口,下次重新开启支付流程就会检查未完成的支付并调用该接口。

      解决方法:

      1.在得到支付结果后及时调用 finish 方法

      2.添加一个是否是新发起的支付流程的条件,在条件符合的情况下才触发应用的相关逻辑的代码

      PS:在拿到苹果的支付结果凭据的时候最好在客户端做一份持久化的数据备份,等待后台验证完成后再清除掉,避免出现验证中间出现问题导致用户支付成功但后台相关的增值处理没有完成导致用户金钱损失的问题)


    • 3、如何区分购买物品的是 沙盒测试账号 还是 真实账号 


      后台再验证支付凭据的时候要区分是沙盒测试账号购买的还是用户真实账号购买的,所以在传凭据的时候还需要告诉后台当前购买的账号性质。

      解决方法:通过在配置文件中定义相关的宏定义并结合 Debug 与 Release 的编译环境确定相关的参数

      // 苹果内购是否为沙盒测试账号,打开就代表为沙盒测试账号,注意上线时注释掉
      #define APPSTORE_ASK_TO_BUY_IN_SANDBOX 1
      		
      // 生成订单参数,注意沙盒测试账号与线上正式苹果账号的验证途径不一样,要给后台标明 
          NSNumber *sandbox;
      #if (defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))
          sandbox = @(0);
      #else
          sandbox = @(1);
      #endif

      个人没有找到相关的方法可以打完包后动态的检测购买物品的账号性质,希望知道的朋友分享一下,感谢 ^_^


    5、iOS7 客户端验证的订单状态

    • 苹果在iOS7提升了购买凭据的安全性,可以直接单独在客户端完成订单正确性的验证,但是处于金钱考虑,购买完成后,建议还是要做凭据的后台验证工作。

      #pragma mark 客户端验证购买凭据
      - (void)verifyTransactionResult
      {
          // 验证凭据,获取到苹果返回的交易凭据
          // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
          NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
          // 从沙盒中获取到购买凭据
          NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
          // 传输的是BASE64编码的字符串
          /**
           BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性
           BASE64是可以编码和解码的
           */
          NSDictionary *requestContents = @{
                                            @"receipt-data": [receipt base64EncodedStringWithOptions:0]
                                            };
          NSError *error;
          // 转换为 JSON 格式
          NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                                options:0
                                                                  error:&error];
          // 不存在
          if (!requestData) { /* ... Handle error ... */ }
          
          // 发送网络POST请求,对购买凭据进行验证
          NSString *verifyUrlString;
      #if (defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))
          verifyUrlString = @"https://sandbox.itunes.apple.com/verifyReceipt";
      #else
          verifyUrlString = @"https://buy.itunes.apple.com/verifyReceipt";
      #endif
          // 国内访问苹果服务器比较慢,timeoutInterval 需要长一点
          NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:[[NSURL alloc] initWithString:verifyUrlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
          
          [storeRequest setHTTPMethod:@"POST"];
          [storeRequest setHTTPBody:requestData];
          
          // 在后台对列中提交验证请求,并获得官方的验证JSON结果
          NSOperationQueue *queue = [[NSOperationQueue alloc] init];
          [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
                                 completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                                     if (connectionError) {
                                         NSLog(@"链接失败");
                                     } else {
                                         NSError *error;
                                         NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
                                         if (!jsonResponse) {
                                             NSLog(@"验证失败");
                                         }
                                         
                                         // 比对 jsonResponse 中以下信息基本上可以保证数据安全
                                         /*
                                          bundle_id
                                          application_version
                                          product_id
                                          transaction_id
                                          */
                                         
                                         NSLog(@"验证成功");
                                     }
                                 }];
          
      }


    6、内购验证凭据返回结果状态码说明

    • 苹果反馈的状态码:

      21000 App Store无法读取你提供的JSON数据
      21002 收据数据不符合格式
      21003 收据无法被验证
      21004 你提供的共享密钥和账户的共享密钥不一致
      21005 收据服务器当前不可用
      21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
      21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
      21008 收据信息是产品环境中使用,但却被发送到测试环境中验证


    更为详细的信息请参考

    ios 应用内支付(In-App Purchase,沙盒测试,后台验证)

    【IOS一气呵成】之IAP集成:内购和内购恢复

    另附:苹果官网内购 API 链接

    7、如何恢复购买

    • 注:此部分内容后期再详细添加 ^_^

    备注:

    相关代码:

    XYPayManager.h

    //
    //  XYPayManager.h
    //  xingyun
    //
    //  Created by 郑亚恒 on 15/11/2.
    //  Copyright © 2015年 郑亚恒. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    // 苹果内购是否为沙盒测试账号,打开就代表为沙盒测试账号,注意上线时注释掉!!
    #define APPSTORE_ASK_TO_BUY_IN_SANDBOX 1
    
    typedef void(^payCompleteBlock)(NSDictionary *resultDic, BOOL isSuccess);
    
    @interface XYPayManager : NSObject
    
    + (instancetype)sharedPayManager;
    
    /// 苹果内购
    - (void)requestAppleStoreProductDataWithString:(NSString *)productIdentifier payComplete:(payCompleteBlock)payCompletionBlock;
    /// 验证苹果支付订单凭证
    - (void)checkAppStorePayResultWithBase64String:(NSString *)base64String;
    
    @end


    XYPayManager.m

    //
    //  XYPayManager.m
    //  xingyun
    //
    //  Created by 郑亚恒 on 15/11/2.
    //  Copyright © 2015年 郑亚恒. All rights reserved.
    //
    
    #import "XYPayManager.h"
    #import <StoreKit/StoreKit.h>
    
    @interface XYPayManager() <SKPaymentTransactionObserver, SKProductsRequestDelegate>
    
    // 苹果内购
    @property (nonatomic, copy) NSString *appleProductIdentifier;
    @property (nonatomic, copy) payCompleteBlock payComplete;
    
    @end
    
    @implementation XYPayManager
    
    + (instancetype)sharedPayManager {
        static XYPayManager *payManager;
        static dispatch_once_t once = 0;
        dispatch_once(&once, ^{
            payManager = [[XYPayManager alloc] init];
            // 注册苹果内购
            [[SKPaymentQueue defaultQueue] addTransactionObserver:payManager];
            
        });
        return payManager;
    }
    
    - (void)dealloc {
        [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
    }
    
    #pragma mark - 苹果支付充值
    //请求商品
    - (void)requestAppleStoreProductDataWithString:(NSString *)productIdentifier payComplete:(payCompleteBlock)payCompletionBlock {
        if(![SKPaymentQueue canMakePayments]) {
            NSLog(@"不允许程序内付费");
    //        [APPCONTEXT.hudHelper showHudOnWindow:@"不允许程序内付费" image:nil acitivity:NO autoHideTime:DEFAULTTIME];
            
            return;
        }
        
        NSLog(@"-------------请求对应的产品信息----------------");
        self.startBuyAppleProduct = YES;
        self.payComplete = payCompletionBlock;
        self.appleProductIdentifier = productIdentifier;
        
        NSLog(@"生成产品信息");
        NSArray *product = [[NSArray alloc] initWithObjects:productIdentifier, nil];
        NSSet *nsset = [NSSet setWithArray:product];
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
        request.delegate = self;
        [request start];
        
    }
    
    //收到产品返回信息
    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
        
        NSLog(@"--------------收到产品反馈消息---------------------");
        NSArray *productArray = response.products;
        if([productArray count] == 0){
            NSLog(@"--------------没有商品------------------");
            return;
        }
        
        NSLog(@"productID:%@", response.invalidProductIdentifiers);
        NSLog(@"产品付费数量:%lu",(unsigned long)[productArray count]);
        
        SKProduct *product = nil;
        for (SKProduct *pro in productArray) {
            NSLog(@"%@", [pro description]);
            NSLog(@"%@", [pro localizedTitle]);
            NSLog(@"%@", [pro localizedDescription]);
            NSLog(@"%@", [pro price]);
            NSLog(@"%@", [pro productIdentifier]);
            
            if([pro.productIdentifier isEqualToString:self.appleProductIdentifier]){
                product = pro;
            }
        }
        
        SKPayment *payment = [SKPayment paymentWithProduct:product];
        
        NSLog(@"发送购买请求");
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    }
    
    //请求失败
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
        NSLog(@"------------------错误-----------------:%@", error);
    }
    
    - (void)requestDidFinish:(SKRequest *)request{
        NSLog(@"------------反馈信息结束-----------------");
    }
    
    //监听购买结果
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction {
        for(SKPaymentTransaction *paymentTransactionp in transaction){
            
            switch (paymentTransactionp.transactionState) {
                case SKPaymentTransactionStatePurchased:
                {
                    NSLog(@"交易完成-restoreCompletedTransactions");
                    /* your code */
                    [self buyAppleStoreProductSucceedWithPaymentTransactionp:paymentTransactionp];
                    
                    [self completeTransaction:paymentTransactionp];
                }
                    
                    break;
                    
                case SKPaymentTransactionStatePurchasing:
                    NSLog(@"商品添加进列表");
                    
                    break;
                    
                case SKPaymentTransactionStateRestored:
                    NSLog(@"已经购买过商品");
                    
                    break;
                    
                case SKPaymentTransactionStateFailed:
                {
                    NSLog(@"交易失败");
                    /* your code */
                    [self completeTransaction:paymentTransactionp];
                }
                    break;
            }
        }
    }
    
    // 苹果内购支付成功
    - (void)buyAppleStoreProductSucceedWithPaymentTransactionp:(SKPaymentTransaction *)paymentTransactionp {
    
        /* 获取相应的凭据,并做 base64 编码处理 */
        NSString *base64Str = [paymentTransactionp.transactionReceipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        NSLog(@"苹果内购凭据号\n\n\n\n\n\n%@\n\n\n\n\n\n",base64Str);
    
        [self checkAppStorePayResultWithBase64String:base64Str];
    }
    
    
    - (void)checkAppStorePayResultWithBase64String:(NSString *)base64String {
        
        /* 生成订单参数,注意沙盒测试账号与线上正式苹果账号的验证途径不一样,要给后台标明 */
        NSNumber *sandbox;
    #if (defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))
        sandbox = @(0);
    #else
        sandbox = @(1);
    #endif
        
        NSMutableDictionary *prgam = [[NSMutableDictionary alloc] init];;
        [prgam setValue:sandbox forKey:@"sandbox"];
        [prgam setValue:base64String forKey:@"reciept"];
        
        /*
         请求后台接口,服务器处验证是否支付成功,依据返回结果做相应逻辑处理
         */
    
    }
    
    //交易结束
    - (void)completeTransaction:(SKPaymentTransaction *)transaction{
        NSLog(@"交易结束");
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
    
    @end
    
    
    展开全文
  • 模式是使用RMB换成-金币比如:(1RMB = 10金币),所以会集成第三方的支付平台,使用了微信和支付宝的第三方平台过后,发现审核失败,被苹果拒绝,查了一查原因,才是因为苹果对app内的中间币的购买必须走苹果内购(比如冲点券...
  • 上篇的内购准备工作已完成,接下来就只需集成代码咯~ part 2. 代码 1.在项目中引入“storekit.framework”,并加入头文件#import 2.在.h文件中加入“SKPaymentTransactionObserver , SKProductsRequestDelegate”...
  • App内购通关:(一)非代码准备篇

    千次阅读 2016-12-01 17:46:23
    前言In-App Purchase :App内购,苹果自家的虚拟产品交易功能。 如果你的项目中涉及到开通会员、购买视频、付费道具等花钱才能享受app全部功能的这种虚拟交易,恭喜入坑,因为当下各种支付平台(支付宝、微信钱包、...
  • iOS 11以后的用户可以在App Store内的下载页面内直接购买应用的内购商品,这项功能苹果称作做Promoting In-App Purchases,如果你的App需要在App Store推广自己的内购商品,则需要在App Store推广里上传推广用的图像...
  • 内购产品类型为:消耗型项目 内购沙盒测试账号在支付成功后,再次购买相同 ID 的物品,会提示如下内容的弹窗。 您已购买此 App 内购买项目。此项目将免费恢复。 解决方法:要实现自己的恢复机制...
  • 模式是使用RMB换成-金币比如:(1RMB = 10金币),所以会集成第三方的支付平台,使用了微信和支付宝的第三方平台过后,发现审核失败,被苹果拒绝,查了一查原因,才是因为苹果对app内的中间币的购买必须走苹果内购(比如冲点券...
  • 关于ios平台下的app的充值规则: 平台的充值的要求和规范 ...在App内需要付费使用的产品功能或虚拟商品/服务,如游戏道具、电子书、音乐、视频、订阅会员、App的高级功能等。 1.2 IAP类型 如前面说的,I...
  • iOS In-App Purchase 内购之问题总结

    千次阅读 2017-07-21 16:24:56
    1、在 AppStore 中创建相应的物品,创建内购沙盒测试账号2、客户端从后台获取相应的物品 ID (当然也可以再客户端写死,但后期扩展性就受限制了)3、依据相应的物品 ID 请求商品的相关信息4、依据商品信息创建订单...
  • iOS开发--In-app Purchase内购验证方法

    千次阅读 2015-06-25 10:54:16
    IOS7开始:AppStore增加了验证内购(In App Purchasement)的方法, 以确保此次支付是有效地. 下面是苹果提供的验证地址: 开发测试用: https://sandbox.itunes.apple.com/verifyReceipt 产品用: ... 当购买成功时, ...
  • google内购In-App Billing

    千次阅读 热门讨论 2013-06-21 22:37:55
    这周做了google的内购,没搞过google的内购还是觉得比较繁琐的 google官方教程:http://developer.android.com/training/in-app-billing/index.html 这个教程主要写了四节: 第一节:Prepari
  • App内购之 Ray Wenderlich 的 IAP 文章的学习笔记。 前面几步的流程请看原文,很详细,有中文。这里主要是讲解一下代码,这块代码对新手来说有点难懂。  一、配置。这块比较繁琐,填很多表,信用卡帐号等要填 1...
  • 1.内购——应用内购买  我所说的内购——也可以说是应用内购买大家都知道通过苹果应用程序商店有三种主要赚钱的方式: 1.直接收费(与国内大部分用户的消费习惯相悖,如果要收费,直接收高的,别收6块钱) 2.广告...
  • 1.内购——应用内购买  我所说的内购——也可以说是应用内购买 大家都知道通过苹果应用程序商店有三种主要赚钱的方式: 1.直接收费(与国内大部分用户的消费习惯相悖,如果要收费,直接收高的,别收6块钱...
  • 忽然发现手头上也没什么独立App,那就随便写个放到AppStore上吧,凑个数吧。哈哈哈。 这个App是无聊找配色的时候看到的一套图 协调色-红0001.jpg 正好春节在家没什么特别的事,编码用了
  • Apple开发中,在应用中嵌入内购(IAP)功能的小伙伴们可能会发现,吃着火锅唱着歌,突然App就无法获取到产品列表了,而且产品请求操作并不会返回任何错误。 此时检查发现,并没有对App内购逻辑做任何改动。 那么,这...
  • 1、在 AppStore 中创建相应的物品,创建内购沙盒测试账号2、客户端从后台获取相应的物品 ID (当然也可以再客户端写死,但后期扩展性就受限制了)3、依据相应的物品 ID 请求商品的相关信息4、依据商品信息创建订单...
  • GooglePlay内购In-app SDK接入

    千次阅读 2019-05-28 11:32:14
    文章转载自:https://gitee.com/tjbaobao/GoogleBuillingUtil/blob/master/GoogleBillingUtil.java README.md: ... 最新正在测,有兴趣的朋友可以尝试使用最新:GoogleBilling1.2.1 ...
  • app内,点一个购买道具按钮,付款后,得到道具,这个能在app内实现吗?
  • In App Purchases(内购) 入门

    千次阅读 2012-11-30 16:08:40
    http://www.raywenderlich.com/zh-hans/26601/in-app-purchases%E5%86%85%E8%B4%AD-%E5%85%A5%E9%97%A8 ...比如,收费,免费挂广告,还有就是程序内置购买。 程序内置购买会让你爱不释手,主要有以下原因:
  • 第一印象觉得In-App Purchase(简称IAP)非常简单。Apple提供的大量文档应该让开发者很快熟悉地熟悉。那么,为什么在你的应用中集成IAP特性就如此令人生厌呢? 这是因为在开发过程中不可避免会出现一些错误...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,301
精华内容 16,920
关键字:

得到app内购版