http://www.sufeinet.com/plugin.php?id=keke_group

苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 3138|回复: 5

[新手开发之旅] 【iOS新手开发之旅】应用内购买

[复制链接]
发表于 2018-12-24 14:47:21 | 显示全部楼层 |阅读模式
本帖最后由 竹林风 于 2018-12-26 15:34 编辑


  文章导航  

【iOS新手开发之旅】   http://www.sufeinet.com/thread-24000-1-1.html



应用内购买项目流程,大致分为三个部分:

第一步:iTunes connect设置,包含创建新的发布版本号、创建购买项目(商品)、设置协议税务银行业务、添加沙盒技术测试帐号;

第二步:在项目开发Xcode中设置允许In-App Purchase,然后编写代码:代码部分可以使用原生态的,也可以使用第三方集成好的,需要注意本地存储交易凭证,用于网络不佳或失败的情况下,重新提交。代码完成好之后,打包提交到App Store 等待审核,提交的时候也把之前内购项目勾选一块提交,等审核通过就可以测试了。

第三步:测试是否成功购买,这是需要真机测试的,测试时需要先注销掉测试手机上的App ID,然后在app中点击购买的时候,输入之前添加的沙盒测试帐号。这部分可能会报各种错误,可能是前面两步没有设置完善,也可能是App Store 的问题,不过,有问题就会有对应的解决方法的,网上都能找到的。

这里就直接先讲代码部分:

[Objective-C] 纯文本查看 复制代码
//去苹果服务器请求商品
- (void)requestProductData:(NSString *)productId{
    NSSet* dataSet = [[NSSet alloc] initWithArray:@[productId]];
    [IAPShare sharedHelper].iap = [[IAPHelper alloc] initWithProductIdentifiers:dataSet];
#if DEBUG==1
    [IAPShare sharedHelper].iap.production = NO;
#else
    [IAPShare sharedHelper].iap.production = YES;
#endif
    // 请求商品信息
    [[IAPShare sharedHelper].iap requestProductsWithCompletion:^(SKProductsRequest* request,SKProductsResponse* response){
         if(response.products.count > 0 ) {
             SKProduct *product = response.products[0];
             [[IAPShare sharedHelper].iap buyProduct:product onCompletion:^(SKPaymentTransaction* trans){
                 if(trans.error){
                     [self.hud hideAnimated:YES];
                     [MBProgressHUD showError:@"购买失败,请重试" toView:self.view];
                }else if(trans.transactionState == SKPaymentTransactionStatePurchased) {
                    self.receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
                    [self justifyIAP:self.hud];
                }else if(trans.transactionState == SKPaymentTransactionStateFailed) {
                    if (trans.error.code == SKErrorPaymentCancelled) {
                        [self.hud hideAnimated:YES];
                    }else{
                        [[[CommonUIAlert alloc] init] showCommonAlertView:self title:@"" message:@"购买失败,请重试" cancelButtonTitle:@"取消" otherButtonTitle:@"确定" cancle:^{
                            [self.hud hideAnimated:YES];
                            [self saveReceipt];
                        } confirm:^{
                            [self justifyIAP:self.hud];
                        }];
                    }
                }
            }];
         }else{
             [self.hud hideAnimated:YES];
             [MBProgressHUD showError:@"购买失败,请重试" toView:self.view];
         }
     }];
}
 
#pragma mark - ios iap应用内支付二次验证
- (void)justifyIAP:(MBProgressHUD*)hud{
    if(hud==nil){
        hud = [MBProgressHUD showMessag:@"支付中..." toView:self.view];
    }
    NSString *receiptBase64 = [NSString base64StringFromData:self.receipt length:[self.receipt length]];
    __weak typeof(self) weakSelf = self;
    NSMutableDictionary *requestDict = [NSMutableDictionary dictionary];
    [requestDict setObject:[DataModelInstance shareInstance].userModel.userId forKey:@"userid"];
    [requestDict setObject:[CommonMethod paramStringIsNull:receiptBase64] forKey:@"data"];
    [self requstType:RequestType_Post apiName:API_NAME_USER_POST_USER_IAPSECONDVALID paramDict:requestDict hud:hud success:^(AFHTTPRequestOperation *operation, id responseObject, MBProgressHUD *hud) {
        if([CommonMethod isHttpResponseSuccess:responseObject] == HttpResponseTypeSuccess){
            weakSelf.receipt = nil;
            [hud hideAnimated:YES];
            [weakSelf.navigationController popViewControllerAnimated:YES];
        }else{
            [[[CommonUIAlert alloc] init] showCommonAlertView:self title:@"" message:@"购买失败,请重试" cancelButtonTitle:@"取消" otherButtonTitle:@"确定" cancle:^{
                [hud hideAnimated:YES];
                [weakSelf saveReceipt];
            } confirm:^{
                [weakSelf justifyIAP:hud];
            }];
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error, MBProgressHUD *hud) {
        [[[CommonUIAlert alloc] init] showCommonAlertView:self title:@"" message:@"购买失败,请重试" cancelButtonTitle:@"取消" otherButtonTitle:@"确定" cancle:^{
            [hud hideAnimated:YES];
            [weakSelf saveReceipt];
        } confirm:^{
            [weakSelf justifyIAP:hud];
        }];
    }];
}
 
//持久化存储用户购买凭证(这里最好还要存储当前日期,用户id等信息,用于区分不同的凭证)
- (void)saveReceipt{
    if(self.receipt && self.receipt.length){
        NSString *fileName = [NSString genUUID];
        NSString *savedPath = [NSString stringWithFormat:@"%@%@.plist", AppStoreInfoLocalFilePath, fileName];
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys: self.receipt, IAP_RECEIPT,[DataModelInstance shareInstance].userModel.userId,IAP_USER_ID,nil];
        BOOL result = [dic writeToFile:savedPath atomically:YES];
        NSLog(@"%d",result);
        self.receipt = nil;
    }
}


[Objective-C] 纯文本查看 复制代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        
        
    //从服务器验证receipt失败之后,在程序再次启动的时候,使用保存的receipt再次到服务器验证
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:AppStoreInfoLocalFilePath]) {//如果在改路下不存在文件,说明就没有保存验证失败后的购买凭证,也就是说发送凭证成功。
        [fileManager createDirectoryAtPath:AppStoreInfoLocalFilePath//创建目录
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:nil];
    }else{//存在购买凭证,说明发送凭证失败,再次发起验证
        [self sendFailedIapFiles];
    }
    return YES;
}
 
//验证receipt失败,App启动后再次验证
- (void)sendFailedIapFiles{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error = nil;
    
    //搜索该目录下的所有文件和目录
    NSArray *cacheFileNameArray = [fileManager contentsOfDirectoryAtPath:AppStoreInfoLocalFilePath error:&error];
    
    if (error == nil){
        for (NSString *name in cacheFileNameArray){
            if ([name hasSuffix:@".plist"]){//如果有plist后缀的文件,说明就是存储的购买凭证
                NSString *filePath = [NSString stringWithFormat:@"%@/%@", AppStoreInfoLocalFilePath, name];
                [self sendAppStoreRequestBuyPlist:filePath];
            }
        }
    }
}
 
- (void)sendAppStoreRequestBuyPlist:(NSString *)plistPath{
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:plistPath];
    //这里的参数请根据自己公司后台服务器接口定制,但是必须发送的是持久化保存购买凭证
    NSData *receipt = [dic objectForKey:IAP_RECEIPT];
    if(receipt==nil){
        [self sendAppStoreRequestSucceededWithData:plistPath];
        return;
    }
    NSString *receiptBase64 = [NSString base64StringFromData:receipt length:[receipt length]];
    NSMutableDictionary *requestDict = [NSMutableDictionary dictionary];
    [requestDict setObject:[dic objectForKey:IAP_USER_ID] forKey:@"userid"];
    [requestDict setObject:[CommonMethod paramStringIsNull:receiptBase64] forKey:@"data"];
    [[[UIViewController alloc] init] requstType:RequestType_Post apiName:API_NAME_USER_POST_USER_IAPSECONDVALID paramDict:requestDict hud:nil success:^(AFHTTPRequestOperation *operation, id responseObject, MBProgressHUD *hud) {
        if([CommonMethod isHttpResponseSuccess:responseObject] == HttpResponseTypeSuccess){
            [self sendAppStoreRequestSucceededWithData:plistPath];
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error, MBProgressHUD *hud) {
    }];
}
 
//验证成功就从plist中移除凭证
- (void)sendAppStoreRequestSucceededWithData:(NSString *)plistPath{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:plistPath]){
        [fileManager removeItemAtPath:plistPath error:nil];
    }
}


下一篇  自动布局


1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
发表于 2018-12-24 14:48:09 | 显示全部楼层
我只是路过打酱油的。
 楼主| 发表于 2018-12-24 14:49:00 | 显示全部楼层
内购 itunes Connect设置

iOS内购(IAP,In App Purchases)Itunes Connect设置
http://www.sufeinet.com/thread-24488-1-1.html
(出处: 苏飞论坛)
发表于 2018-12-24 15:33:49 | 显示全部楼层
真是难得给力的帖子啊。
发表于 2018-12-26 14:02:15 | 显示全部楼层
楼主加油,我们都看好你哦。
发表于 2018-12-27 09:39:53 | 显示全部楼层
强烈支持楼主ing……
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-5-29 08:11

© 2014-2021

快速回复 返回顶部 返回列表