iOS的应用内购买 iAP 坑 之一

iOS Jan 18, 2015

已搞定

内购这块坑不算少,另外因为 sandbox 测试所需要特定的配置也很多,所以对于经验不太多的开发者来说很容易就遇到各种问题,并且测试时出错Apple给出的也只有“Can not connect iTunes Store”或者"Invalid Product IDs"之类毫无价值的错误提示,并没有详细的错误说明,因此调试起来往往没有方向。

再就是博主比较懒啦,就不扫盲了,部分步骤简略些。先申请 app 证书,必须支持推送,然后项目中打开推送。

  • iTC中,新建一个 app,注意包名一定对应,再添加内购项目。
  • 单纯测试的话,截图可以不传。
  • 添加沙盒测试者 注意必须是未注册 Apple ID 的邮件地址,然后收到邮件激活即可

放代码们

下面列出来的库,一个都不好用,最终我用了 IAPHelper,自行 github 吧。

if(![IAPShare sharedHelper].iap) {
        
        NSSet* dataSet = [[NSSet alloc] initWithObjects:@"eduadm_donate_3", @"eduadm_donate_6", @"eduadm_donate_12", @"eduadm_donate_25", nil];
        
        [IAPShare sharedHelper].iap = [[IAPHelper alloc] initWithProductIdentifiers:dataSet];
        
    }
    
    [IAPShare sharedHelper].iap.production = NO;
    
    [[IAPShare sharedHelper].iap requestProductsWithCompletion:^(SKProductsRequest *request, SKProductsResponse *response) {
        if(response > 0 ) {
        
            SKProduct* product =[[IAPShare sharedHelper].iap.products objectAtIndex:0];
            
            [[IAPShare sharedHelper].iap buyProduct:product onCompletion:^(SKPaymentTransaction *transcation) {
                
                
                if(transcation.error)
                {
                    NSLog(@"Fail %@",[transcation.error localizedDescription]);
                }
                else if(transcation.transactionState == SKPaymentTransactionStatePurchased) {
                    
                    [[IAPShare sharedHelper].iap checkReceipt:transcation.transactionReceipt AndSharedSecret:@"your sharesecret" onCompletion:^(NSString *response, NSError *error) {
                        
                        //Convert JSON String to NSDictionary
                        NSDictionary* rec = [IAPShare toJSON:response];
                        
                        if([rec[@"status"] integerValue]==0)
                        {
                            NSString *productIdentifier = transcation.payment.productIdentifier;
                            [[IAPShare sharedHelper].iap provideContent:productIdentifier];
                            NSLog(@"SUCCESS %@",response);
                            NSLog(@"Pruchases %@",[IAPShare sharedHelper].iap.purchasedProducts);
                        }
                        else {
                            NSLog(@"Fail");
                        }
                    }];
                }
                else if(transcation.transactionState == SKPaymentTransactionStateFailed) {
                    NSLog(@"Fail");
                }
                
            }];
        }
    }];

下面是结果:

2015-01-18 14:45:02.526 eduadmin[441:92076] SUCCESS {
"receipt":{"original_purchase_date_pst":"2015-01-17 22:44:51 America/Los_Angeles", "purchase_date_ms":"1421563491028", "unique_identifier":"25b170fda433c754e5ac3fc1a054a4b78560c716", "original_transaction_id":"1000000139233309", "bvrs":"62", "transaction_id":"1000000139233309", "quantity":"1", "unique_vendor_identifier":"9EE7D835-713A-4BDF-A2C0-50035D978ADE", "item_id":"959284801", "product_id":"eduadm_donate_12", "purchase_date":"2015-01-18 06:44:51 Etc/GMT", "original_purchase_date":"2015-01-18 06:44:51 Etc/GMT", "purchase_date_pst":"2015-01-17 22:44:51 America/Los_Angeles", "bid":"com.pupboss.eduadmin", "original_purchase_date_ms":"1421563491028"}, "status":0}
2015-01-18 14:45:02.527 eduadmin[441:92076] Pruchases {(
    "eduadm_donate_12"
)}

不过还有个问题

直接

[[IAPShare sharedHelper].iap.products objectAtIndex:0]

你会不知道他顺序

加上这么一句

for (SKProduct *pro in [IAPShare sharedHelper].iap.products) {
                
                NSLog(@"%@-----%@-----%@-----%@-----%@",pro.localizedDescription,pro.localizedTitle,pro.price,pro.priceLocale,pro.productIdentifier);
            }

挨个打印出来,再做判断就好了

2015-01-18 17:43:30.568 eduadmin[521:120874] 大约是一个汉堡的价格-----自由捐赠-----12-----<__NSCFLocale: 0x1740e8f00>-----eduadm_donate_12
2015-01-18 17:43:30.571 eduadmin[521:120874] 大约是中杯星巴克的价格-----自由捐赠-----25-----<__NSCFLocale: 0x1740e8f00>-----eduadm_donate_25
2015-01-18 17:43:30.571 eduadmin[521:120874] 大约是一瓶可口可乐的价格-----自由捐赠-----3-----<__NSCFLocale: 0x1740e8f00>-----eduadm_donate_3
2015-01-18 17:43:30.572 eduadmin[521:120874] 大约是一碗麻辣烫的价格-----自由捐赠-----6-----<__NSCFLocale: 0x1740e8f00>-----eduadm_donate_6

下面介绍坑们

  • 你是否在 iOS Dev Center中打开了对应应用AppID的 In-App Purchases 功能?登陆 iOS Dev Centre 的 Certificates, Identifiers & Profiles 下,在 Identifiers 中找到正在开发的 App,In-App Purchase 一项应当显示 Enabled(如果使用 Xcode5,可以直接在 Xcode 的 Capabilities 页面中打开 In-App Purchases)。
  • 你是否在 iTunes Connect 中注册了你的 IAP 项目,并将其设为 Cleared for Sale?
  • 你的 plist 中的 Bundle identifier 的内容是否和你的 AppID 一致?
  • 你是否正确填写了 Version(CFBundleVersion)和 Build(CFBuildNumber)两个数字?两者缺一不可。
  • 你用代码向 Apple 申请售卖物品列表时是否使用了完整的在 iTC 注册的 Product ID?(使用在 IAP 管理中内购项目的 Product ID一栏中的字符串)
  • 你是否在打开 IAP 以后重新生成过包含 IAP 许可的 provisioning profile?
  • 你是否重新导入了新的包含 IAP 的 provisioning profile?建议在 Organiser 中先删掉原来设备上的老的 provisioning profile。
  • 你是否在用包含 IAP 的 provisioning profile 在部署测试程序?在 Xcode5 中,建议使用 General 中的 Team 选项来自动管理。
  • 你是否是在模拟器中测试 IAP?虽然理论上说模拟器在某些情况下可以测试 IAP,但是条件很多也不让人安心,因此你确实需要一台真机来做 IAP 测试。
  • 你是在企业版发布中测试 IAP 么?因为企业版没有 iTC 进行内购项目管理,也无法发布 AppStore 应用,所以你在企业版的 build 中不能使用 IAP。
  • 你是否将设备上原来的 app 删除了,并重新进行了安装?记得在安装前做一下 Clean 和 Clean Build Folder。
  • 你是否在运行应用前将设备上实际的 Apple ID 登出了?建议在设置->iTunes Store 和 App Stroe 中将使用中的 Apple ID 登出,以未登录状态进入应用进行测试。
  • 你是否使用的是 Test User?如果你还没有创建 Test User,你需要到 iTC 中创建。
  • 你使用的测试账号是否是美国区账号?虽然不是一定需要,但是鉴于其他地区的测试账号经常抽风,加上美国区账号一直很稳定,因此强烈建议使用美国区账号。正常情况下 IAP 不需要进行信用卡绑定和其他信息填写,如果你遇到了这种情况,可以试试删除这个测试账号再新建一个其他地区的。
  • 你是否有新建账户进行测试?可能的话,可以使用新建测试账户试试看,因为某些特定情况下测试账户会被 Apple 锁定。
  • 你的应用是否是被拒状态(Rejected)或自己拒绝(Developer Rejected)了?被拒绝状态的应用的话对应还未通过的内购项目也会一起被拒,因此你需要重新将IAP项目设为 Cleared for Sale。
  • 你的应用是否处于等待开发者发布(Pending Developer Release)状态?等待发布状态的 IAP 是无法测试的。
  • 你的内购项目是否是最近才新建的,或者进行了更改?内购项目需要一段时间才能反应到所有服务器上,这个过程一般是一两小时,也可能再长一些达到若干小时。
  • 你在 iTC 中 Contracts, Tax, and Banking Information 项目中是否有还没有设置或者过期了的项目?不完整的财务信息无法进行内购测试。
  • 你是在越狱设备上进行内购测试么?越狱设备不能用于正常内购,你需要重装或者寻找一台没有越狱的设备。
  • 你是否能正常连接到 Apple 的服务器,你可以访问 Apple 开发者论坛关于 IAP 的板块,如果苹果服务器正 down 掉,那里应该有热烈的讨论。

详细教程

第三方库推荐

Tags

Jie Li

🚘 On-road / 📉 US Stock / 💻 Full Stack Developer / 🎓 Grad Student / ®️ ENTJ

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.