iOS学习内购

iOS之苹果内购最新2017年教程

2017-04-28  本文已影响1552人  charlotte2018

公司有个功能叫付费加速制作模型。这属于服务费,之前用的支付宝和微信支付,后来微信通过其官方公众号发出通知,称因为苹果对iOS应用的新规定,将关闭微信公众号在iOS上的打赏功能。所以为了不被苹果拒绝。支付换做内购了。今天学习下如何使用苹果支付。

协议,税务和银行业务

1242012-69099549f1c19d98.png

点击

申请合同.png

点击request申请合同

1242012-d240abc2ad52cf23.png

添加联系人

1242012-e4b46eebc037c1c9.png

同意协议然后提交


1242012-447905cbad7e757b.png

设置相关的信息如联系人,银行,税务信息。

1242012-56d222c1b8dd3aa8.png

联系人信息

先点击蓝色的add New Contact 写完后save,注意在role(角色)中,为联系人选择身份(高级管理人员 ,金融,技术,法律,营销),点击Done保存

银行信息

添加银行信息

1242012-f0975f1235ee8cfa.png

选择国家


1242012-7222d2b96d4c8463.png

填写CNAPS

CNAPS 银行网点联行号.我们可以直接到银行客服电话查询 CNAPS, 快速便捷.还可以通过下图的Look up CNAPS Code 查询. 不过有的查询不到


1242012-52e42c1d0678e05a.png 1242012-f32b0ee23bb4eb3c.png

确认银行信息


1242012-407a7da27f6730a1.png

.填写公司银行账号信息


1242012-efc941edf1b339fc.png

税务信息

税务信息有三个选项:美国税务、澳大利亚税务、加拿大税务。我们在这里选择美国税务就可以

1242012-2eec17fd00430f79.png 1242012-e7cbd0888d850872.png

选No

1242012-391d636a208ade83.png

选No

填写税务相关信息

9b.Foreign TIN 是填写公司税务识别码.公司营业执照上同意社会信用代码去掉前两位和最后一位就是公司税务识别码(15位)


1242012-eeb0455ed5164c73.png

点击提交之后会让你确认信息,确认无误后再次点击提交(提交后无法修改)

添加内购

点击功能,然后点加号。


WX20170503-155202@2x.png

根据项目需求,选择内购项目

1242012-ee6d6740f12728a9.png

填写内购项目的相关信息

商品名称根据你的消费道具的实际意义来说明
产品ID是比较重要的,只要唯一即可,在实际应用中,一定要认真填写。
选择价格

WX20170503-155643@2x.png

本地化版本

将在 App Store 上可见的 App 内购买项目名称。可以参考App Store中其他应用的内购项目描述
描述不得少于10个字符


WX20170503-155755@2x.png

审核信息

1.只会在审核中使用屏幕快照,不会将其显示在 App Store 上。屏幕快照必须具有适合您 App 平台的有效尺寸。
2.能够有助于我们进行审核的关于您的 App 内购买项目的其他信息,如测试帐户(包括用户名、密码等)。审核备注不得超过 4000 个字符。


WX20170503-155814@2x.png

内购项目则添加完成

申请沙盒测试账号(用来测试购买项目)

我们不必用真实的人民币测试购买内购项目
首先我们回到iTunes Connect中,在这里我们选择用户和职能。
添加沙箱技术测试员

1242012-e90d8ee77aa59add.png

添加测试员详细信息

所有信息都可以随意填写,不用管是否真实。但是App Store地区必须对应
注意: 邮件地址不能填写与 Apple ID 关联的, 密码保护问题必须在 6 到 35 个字符之间。密码必须包含至少一个大写字母。

1242012-7a721315d3c40521.png WX20170503-160340@2x.png

内购原理

20150723155327761.jpeg

在项目中实现购买

#import "PurchaseService.h"
#import <StoreKit/StoreKit.h>
#import "MaskView.h"

@interface PurchaseService()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
//productId是在开发者平台填写的产品id,排队加速
@property(nonatomic,copy)NSString *productId;

@property(nonatomic,strong)MaskView *maskView;

@property(nonatomic,assign)BOOL isAccelerate;

@property(nonatomic,strong)NSString *filePath;

@end

@implementation PurchaseService

- (instancetype)initWithAccelerate:(BOOL)isAccelerate;

{
    self = [super init];
    if (self) {
       
        self.isAccelerate = isAccelerate;
       
        
    }
    return self;
}

- (void)setIsAccelerate:(BOOL)isAccelerate
{
    _isAccelerate = isAccelerate;
     NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    //槽位的路径
    NSString *receiptPath = [docPath stringByAppendingPathComponent:@"slot_receitp.plist"];
    
    if (_isAccelerate == YES) {
        
        receiptPath = [docPath stringByAppendingPathComponent:@"accelerate_receitp.plist"];
    }
    self.filePath = receiptPath;
}

- (void)pay
{
  
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:self.filePath];
    
    if (dic  != nil) {
        
        DLog(@"沙盒中拿");
        
        NSString *receiptEncodeStr = dic[@"receiptEncodeStr"];
        //去服务器验证
        //配置服务器需要的参数
        NSMutableDictionary *params = [NSMutableDictionary dictionary];
        params[@"xxx"] = xxx;
        //params[@"xxx"] = @(1x);
        params[@"xxx"] = xxxx;
        params[@"xxx"] = @(false);
        [self verifyPurchaseWithDic:params];
        
        return;
    }
    
    //添加一个交易队列观察者
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    
    //判断是否允许程序内购买
    if ([SKPaymentQueue canMakePayments]) {
        
        //获取商品列表
        WS(weakSelf)
        [SWAYNetWorking get:IapProductInfoUrl parameters:nil success:^(id responseObject) {
            
            if ([responseObject[@"code"] integerValue] == 100) {
               
                NSDictionary *dic = [responseObject[@"data"] objectAtIndex:0];
                if (self.isAccelerate == NO) {
                    dic = [responseObject[@"data"] objectAtIndex:1];
                }
                NSInteger p_id = [dic[@"productId"] integerValue];
                weakSelf.productId =  [NSString stringWithFormat:@"%ld",p_id];
                //去苹果服务器请求产品信息
                [weakSelf requestProductData:weakSelf.productId];
            }
            
        } failure:^(NSError *error) {
            
        }];
        
        
    }else{
        
        [SVProgressHUD showImage:nil status:@"用户禁止应用内购买,请到设置->通用->访问限制里打开App内购买项目"];
        
    }
    
}


// 去苹果服务器请求产品信息
- (void)requestProductData:(NSString *)productId {
    
    self.maskView = [[MaskView alloc]init];
    [KWindow addSubview:self.maskView];
    [self.maskView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.bottom.top.mas_equalTo(0);
    }];
    
    
    
    NSArray *productArr = [[NSArray alloc]initWithObjects:productId, nil];
    
    NSSet *productSet = [NSSet setWithArray:productArr];
    
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:productSet];
    request.delegate = self;
    [request start];
    
}

// SKProductsRequestDelegate 收到产品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    
    
    NSArray *productArr = response.products;
    
    if ([productArr count] == 0) {
        
        DLog(@"没有该商品");
        [self.maskView removeFromSuperview];
        return;
    }
    
    DLog(@"productId = %@",response.invalidProductIdentifiers);
    DLog(@"产品付费数量 = %zd",productArr.count);
    
    SKProduct *p = nil;
    
    for (SKProduct *pro in productArr) {
        DLog(@"description:%@",[pro description]);
        DLog(@"localizedTitle:%@",[pro localizedTitle]);
        DLog(@"localizedDescription:%@",[pro localizedDescription]);
        DLog(@"price:%@",[pro price]);
        DLog(@"productIdentifier:%@",[pro productIdentifier]);
        if ([pro.productIdentifier isEqualToString:self.productId]) {
            p = pro;
        }
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    
    //发送内购请求
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}

- (void)requestDidFinish:(SKRequest *)request {
    NSLog(@"完成");
    [self.maskView removeFromSuperview];
}



- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    NSString *errMessage = [error.userInfo objectForKey:@"NSLocalizedDescription"];
    [SVProgressHUD showErrorWithStatus:errMessage];
    [self.maskView removeFromSuperview];
    
}


// SKPaymentTransactionObserver监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
    
    for (SKPaymentTransaction *tran in transactions) {
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased: //交易完成
                // 发送到服务器验证凭证
                [self completeTransaction:tran];
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                break;
            case SKPaymentTransactionStatePurchasing: //商品添加进列表
                
                break;
            case SKPaymentTransactionStateRestored: //购买过
                // 发送到苹果服务器验证凭证
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                break;
            case SKPaymentTransactionStateFailed: //交易失败
                
                [[SKPaymentQueue defaultQueue]finishTransaction:tran];
                [SVProgressHUD showErrorWithStatus:@"购买失败"];
                break;
                
            default:
                break;
        }
    }
}

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
    //商品id
    NSString *produckID = transaction.payment.productIdentifier;
    //订单号
    NSString *transactionIdentifier = transaction.transactionIdentifier;
    
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    NSString *receiptEncodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    //存储收据
    NSMutableDictionary *receiptDic = [NSMutableDictionary dictionary];
    [receiptDic setObject:produckID forKey:@"produckID"];
    [receiptDic setObject:transactionIdentifier forKey:@"transactionIdentifier"];
    [receiptDic setObject:receiptEncodeStr forKey:@"receiptEncodeStr"];
    
   
    [receiptDic writeToFile:self.filePath atomically:YES];
    //配置服务器需要的参数
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"receipt"] = receiptEncodeStr;
    params[@"chooseEnv"] = @(false);
    [self verifyPurchaseWithDic:params];
    
}

#pragma mark-  服务器端做验证
- (void)verifyPurchaseWithDic:(NSDictionary *)dic
{
    [NetWorking post:IapCertificateUrl parameters:dic success:^(id responseObject) {
        
        if ([responseObject[@"code"] integerValue] == 100) {
            
            //刷新首页
             [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadHomeNotification" object:nil];
            
            [SVProgressHUD showImage:nil status:responseObject[@"message"]];
    
            [[NSFileManager defaultManager] removeItemAtPath:self.filePath error:nil];
            
            
        }else{
            
            [SVProgressHUD showImage:nil status:responseObject[@"message"]];
            
            
        }
        
    } failure:^(NSError *error) {
        
    }];
}


//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
// 验证购买
- (void)verifyPurchaseWithPaymentTrasaction {
    
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    
    
    // 发送网络POST请求,对购买凭据进行验证
    //测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt
    //正式验证地址:https://buy.itunes.apple.com/verifyReceipt
    NSURL *url = [NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *urlRequest =
    [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
    urlRequest.HTTPMethod = @"POST";
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    urlRequest.HTTPBody = payloadData;
    // 提交验证请求,并获得官方的验证JSON结果 iOS9后更改了另外的一个方法
    NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
    // 官方验证结果为空
    if (result == nil) {
        NSLog(@"验证失败");
        return;
    }
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    if (dict != nil) {
        // 比对字典中以下信息基本上可以保证数据安全
        // bundle_id , application_version , product_id , transaction_id
        //        NSLog(@"验证成功!购买的商品是:%@", @"_productName");
        
        NSLog(@"验证成功%@",dict);
    }
    
}

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




@end

上一篇下一篇

猜你喜欢

热点阅读