iOS内购图文流程(2017)

什么是内购?

只要在iPhone App上购买的不是实物产品(也就是虚拟产品如qq币.虎牙币.电子书......) 都需要走内购流程,苹果在里面抽走三成。

使用内购需要走的流程。

1,填写协议,税务和银行业务;
2,填写用户和职能; 创建内购的项目
3,写代码,和后台配合
4,添加项目内购测试账号;检验成果

具体步骤:

接下来的步骤特别繁琐,请做好准备。

一.填写协议,税务和银行业务配置 https://itunesconnect.apple.com

iOS内购图文流程(2017)_第1张图片

1.请求合同

iOS内购图文流程(2017)_第2张图片

填写地址信息

iOS内购图文流程(2017)_第3张图片

阅读同意协议

iOS内购图文流程(2017)_第4张图片

2.填写联系方式

iOS内购图文流程(2017)_第5张图片

添加新的联系人

iOS内购图文流程(2017)_第6张图片
iOS内购图文流程(2017)_第7张图片

选中联系人

iOS内购图文流程(2017)_第8张图片

3.填写银行信息

iOS内购图文流程(2017)_第9张图片

添加银行卡

iOS内购图文流程(2017)_第10张图片

选择银行卡所在国家

iOS内购图文流程(2017)_第11张图片

填写银行CNAPS Code
iOS内购图文流程(2017)_第12张图片
货币类型 CN###银行账号如果是对公的账号,需要填写公司的英文名称,如果没有的话拼音

iOS内购图文流程(2017)_第13张图片

4.填写税务信息

U.S Tax Forms: 美国税务
Australia Tax Forms:澳大利亚税务
Canada Tax Forms: 加拿大税务


iOS内购图文流程(2017)_第14张图片

第一个问题如下:询问你是否是美国居民,有没有美国伙伴关系或者美国公司,如果没有直接选择No。


iOS内购图文流程(2017)_第15张图片

第二个问题如下:询问你有没有在美国的商业性活动,没有也直接选No

然后填写你的税务信息,包括以下几点:

Individual or Organization Name:个人或者组织名称
Country of incorporation: 所在国家
Type of Beneficial Owner:受益方式,独立开发者选个人
Permanent Residence:居住地址
Mailing address:邮寄地址
Name of Person Making this Declaration:声明人
Title:头衔

填写完这些信息后就可以提交了

iOS内购图文流程(2017)_第16张图片

iOS内购图文流程(2017)_第17张图片

iOS内购图文流程(2017)_第18张图片

5.等待审核,时间24小时左右。

iOS内购图文流程(2017)_第19张图片

二.创建内购项目

选中你要添加内购项目的APP然后点击功能,点击+创建内购项目。

iOS内购图文流程(2017)_第20张图片

根据自己APP的需求选择类型
iOS内购图文流程(2017)_第21张图片

填写项目名称id (ps:应用在首次添加内购买项目时需要与新的应用版本一起提交审核。)

iOS内购图文流程(2017)_第22张图片

添加沙盒技术测试员

用户职能>沙箱技术测试员

iOS内购图文流程(2017)_第23张图片

iOS内购图文流程(2017)_第24张图片

注意事项:

邮箱随便写但是格式要正确([email protected]),但是不能用已经是AppleID的邮箱

App Store 地区不要乱选。虽然随便哪个地区都可以用来测试(还没上线之前app并没有地区之分),但是在沙盒测试的时候,弹出的购买提示框会根据当前AppleID(沙盒账号)的地区显示语言的。

使用沙盒测试一定要用真机 (越狱的不行)

沙盒账号不能直接登录AppleStore登录时会提示"不允许创建iTunes账户”

进行沙盒测试时需要退出AppleStore的账号

三.代码

#import 
#import "WXApi.h"

typedef NS_ENUM(NSInteger , Payment) {
    IAP6 = 6,
    IAP25 = 25,
    IAP60 = 60
};

@interface PayCenter : NSObject

singleton_interface(PayCenter);

- (void)startInit;

- (void)payWithMoney:(NSInteger)money andType:(PayType)type dataDic:(NSDictionary *)dataDic;

@property (nonatomic, strong) MBProgressHUD * hud;

@property (nonatomic, copy) NSString * rechargeNumber;

@end
#define kProductID_IAP6 @"org.qqhl.nursning.6"//6

#import "PayCenter.h"
#import "PayHttpRequest.h"
//#import "Order.h"
//#import "DataSigner.h"
//#import 
#import 

@interface PayCenter()
{
    int buyType;
    NSInteger _money;
}
@property (nonatomic, strong) NSMutableDictionary * dataDic;

@end
@implementation PayCenter

singleton_implementation(PayCenter);

- (void)startInit
{
    [WXApi registerApp:kWeChatShareAppKey withDescription:appDefaultTilte];
}

- (void)payWithMoney:(NSInteger)money andType:(PayType)type dataDic:(NSDictionary *)dataDic
{
    _money = money;
    self.dataDic = [NSMutableDictionary dictionaryWithDictionary:dataDic];
    switch (type) {
        case PayTypeWX:
            [self payTypeWXPay];
            break;
        case ApplePay:
//            [self payTypeAliPay];
            [[SKPaymentQueue defaultQueue]addTransactionObserver:self];
           
            if ([SKPaymentQueue canMakePayments]) {
                HULog(@"允许程序内付费购买");

                [self payTypeApplePay];
            }else {
                HULog(@"不允许程序内付费购买");
                UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"提示"
                                                                    message:@"您的手机没有打开程序内付费购买"
                                                                   delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
               
                [alerView show];
               
            }

            break;
        default:
            break;
    }
}

- (void)payTypeApplePay{
    NSLog(@"---------请求对应的产品信息------------");
    NSArray *product = nil;
    switch (_money) {
        case IAP6:
        {
            product=[[NSArray alloc] initWithObjects:kProductID_IAP6,nil];
            NSLog(@"---------IAP6------------");

        }
            break;
        case IAP25:
        {
            NSLog(@"---------IAP25------------");

        }
            break;
        case IAP60:
        {
            NSLog(@"---------IAP60------------");
        }

            break;
    
        default:
            break;
    }
   
    NSSet *nsSet = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:nsSet];
    request.delegate = self;
    [request start];
}
#pragma mark -  SKProductsRequestDelegate代理
//返回的在苹果服务器请求的产品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    HULog(@"收到产品信息");
    NSArray *myProduct = response.products;
    HULog(@"产品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 (_money) {
        case IAP6:
        {
            payment = [SKPayment paymentWithProductIdentifier:kProductID_IAP6];
        }
            break;
        case IAP25:{
           
        }
        default:
            break;
    }
   
    NSLog(@"发起购买请求");
    [[SKPaymentQueue defaultQueue]addPayment:payment];
   
   
}
//实现监听方法
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    NSLog(@"调用了几次这个方法?");
    SKPaymentTransaction *transaction = transactions.lastObject;
    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchased: {
            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;
    }
}

@end```
####购买成功后需要跟服务器交互验证交易是否成功

// 验证凭据,获取到苹果返回的交易凭据
// 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;  

测试环境 verifyUrlString = @"https://sandbox.itunes.apple.com/verifyReceipt";
生产环境 verifyUrlString = @"https://buy.itunes.apple.com/verifyReceipt";
// 国内访问苹果服务器比较慢,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(@"验证成功");  
                           }  
                       }];  

}

[苹果官方文档](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW4)
```刚接触内购如有不足之处请指教 ```

你可能感兴趣的:(iOS内购图文流程(2017))