尝试所有这些步骤后,“应用内购买”仍然无法正常工作
Posted
技术标签:
【中文标题】尝试所有这些步骤后,“应用内购买”仍然无法正常工作【英文标题】:"In App Purchasing" still wont work after trying all these steps 【发布时间】:2013-08-15 19:31:36 【问题描述】:我已经执行了这几个步骤,以便在我的应用程序中使用五个非消耗性应用程序购买,但是当我转到将 IAP 代码链接到的 TableViewController 时仍然没有显示任何内容...(我也想非常感谢我遵循的教程,raywenderlich 让我走到了这一步)
-创建了一个新的应用ID -已成功完成链接和下载证书的所有步骤 将我项目的 xcode 上的捆绑 ID 更改为我为 我在 ios 开发者门户上的应用 -链接所有设备并创建一个测试用户帐户 -使iTunes上的非消耗性IAP连接并使用IAP编码中的标识符 -从我的 iTunes 帐户中注销我的手机,以便它可以与测试帐户一起使用 -IAP 的编码看起来是正确的,导入了商店套件并在 .m 文件中实现了产品标识符 -等待 24 小时让新创建的 IAP 与 iTunes Connect 同步 -我没有上传二进制文件! 我打开了苹果主机,但没有上传任何东西 - 可以 这是问题所在? 我删除了手机上的应用程序并重新安装以进行测试,但仍然 什么都没有当我成功运行构建时,我得到的只是一个页面,它看起来像是在加载一些东西,但没有一个空白页面,我可以下拉刷新,但仍然没有我创建的 IAP。
关于我还能做什么或添加什么的任何建议,如果您需要我上传所有我能做的文件的所有代码...
ViewController.h 文件中的 IAP 编码
#import "Accounts/Accounts.h"
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
@interface ViewController19 : UITableViewController
@end
ViewController.m 文件中的 IAP 编码
#import "DetailViewController.h"
#import "SecretsIAPHelper.h"
#import <StoreKit/StoreKit.h>
@interface ViewController19 ()
NSArray *_products;
NSNumberFormatter * _priceFormatter;
@end
@implementation ViewController19
- (void)viewDidLoad
[super viewDidLoad];
self.title = @"XXXXXXXXXXXXX";
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:@selector(reload) forControlEvents:UIControlEventValueChanged];
[self reload];
[self.refreshControl beginRefreshing];
_priceFormatter = [[NSNumberFormatter alloc] init];
[_priceFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[_priceFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Restore" style:UIBarButtonItemStyleBordered target:self action:@selector(restoreTapped:)];
- (void)restoreTapped:(id)sender
[[SecretsIAPHelper sharedInstance] restoreCompletedTransactions];
- (void)viewWillAppear:(BOOL)animated
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
- (void)viewWillDisappear:(BOOL)animated
[[NSNotificationCenter defaultCenter] removeObserver:self];
- (void)productPurchased:(NSNotification *)notification
NSString * productIdentifier = notification.object;
[_products enumerateObjectsUsingBlock:^(SKProduct * product, NSUInteger idx, BOOL *stop)
if ([product.productIdentifier isEqualToString:productIdentifier])
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:idx inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
*stop = YES;
];
- (void)reload
_products = nil;
[self.tableView reloadData];
[[SecretsIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products)
if (success)
_products = products;
[self.tableView reloadData];
[self.refreshControl endRefreshing];
];
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
return 1;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
return _products.count;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
SKProduct * product = (SKProduct *) _products[indexPath.row];
cell.textLabel.text = product.localizedTitle;
[_priceFormatter setLocale:product.priceLocale];
cell.detailTextLabel.text = [_priceFormatter stringFromNumber:product.price];
if ([[SecretsIAPHelper sharedInstance] productPurchased:product.productIdentifier])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.accessoryView = nil;
else
UIButton *buyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buyButton.frame = CGRectMake(0, 0, 72, 37);
[buyButton setTitle:@"Buy" forState:UIControlStateNormal];
buyButton.tag = indexPath.row;
[buyButton addTarget:self action:@selector(buyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryView = buyButton;
return cell;
- (void)buyButtonTapped:(id)sender
UIButton *buyButton = (UIButton *)sender;
SKProduct *product = _products[buyButton.tag];
NSLog(@"Buying %@...", product.productIdentifier);
[[SecretsIAPHelper sharedInstance] buyProduct:product];
@end
在 IAPHelper.h 文件中为 IAP 编码
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
UIKIT_EXTERN NSString *const IAPHelperProductPurchasedNotification;
typedef void (^RequestProductsCompletionHandler)(BOOL success, NSArray * products);
@interface IAPHelper : NSObject
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers;
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler;
- (void)buyProduct:(SKProduct *)product;
- (BOOL)productPurchased:(NSString *)productIdentifier;
- (void)restoreCompletedTransactions;
@end
在 IAPHelper.m 文件中为 IAP 编码
#import "IAPHelper.h"
#import <StoreKit/StoreKit.h>
NSString *const IAPHelperProductPurchasedNotification = @"IAPHelperProductPurchasedNotification";
// 2
@interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@end
// 3
@implementation IAPHelper
SKProductsRequest * _productsRequest;
RequestProductsCompletionHandler _completionHandler;
NSSet * _productIdentifiers;
NSMutableSet * _purchasedProductIdentifiers;
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers
if ((self = [super init]))
// Store product identifiers
_productIdentifiers = productIdentifiers;
// Check for previously purchased products
_purchasedProductIdentifiers = [NSMutableSet set];
for (NSString * productIdentifier in _productIdentifiers)
BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];
if (productPurchased)
[_purchasedProductIdentifiers addObject:productIdentifier];
NSLog(@"Previously purchased: %@", productIdentifier);
else
NSLog(@"Not purchased: %@", productIdentifier);
// Add self as transaction observer
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
return self;
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler
// 1
_completionHandler = [completionHandler copy];
// 2
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_productsRequest.delegate = self;
[_productsRequest start];
- (BOOL)productPurchased:(NSString *)productIdentifier
return [_purchasedProductIdentifiers containsObject:productIdentifier];
- (void)buyProduct:(SKProduct *)product
NSLog(@"Buying %@...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
NSLog(@"Loaded list of products...");
_productsRequest = nil;
NSArray * skProducts = response.products;
for (SKProduct * skProduct in skProducts)
NSLog(@"Found product: %@ %@ %0.2f",
skProduct.productIdentifier,
skProduct.localizedTitle,
skProduct.price.floatValue);
_completionHandler(YES, skProducts);
_completionHandler = nil;
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
NSLog(@"Failed to load list of products.");
_productsRequest = nil;
_completionHandler(NO, nil);
_completionHandler = nil;
#pragma mark SKPaymentTransactionOBserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
for (SKPaymentTransaction * transaction in transactions)
switch (transaction.transactionState)
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
;
- (void)completeTransaction:(SKPaymentTransaction *)transaction
NSLog(@"completeTransaction...");
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
NSLog(@"restoreTransaction...");
[self provideContentForProductIdentifier:transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- (void)failedTransaction:(SKPaymentTransaction *)transaction
NSLog(@"failedTransaction...");
if (transaction.error.code != SKErrorPaymentCancelled)
NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier
[_purchasedProductIdentifiers addObject:productIdentifier];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];
- (void)restoreCompletedTransactions
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
@end
SecretsIAPHelper.h 文件中的 IAP 编码
#import "IAPHelper.h"
@interface SecretsIAPHelper : IAPHelper
+ (SecretsIAPHelper *)sharedInstance;
@end
SecretsIAPHelper.m 文件中的 IAP 编码
#import "SecretsIAPHelper.h"
@implementation SecretsIAPHelper
+ (SecretsIAPHelper *)sharedInstance
static dispatch_once_t once;
static SecretsIAPHelper * sharedInstance;
dispatch_once(&once, ^
NSSet * productIdentifiers = [NSSet setWithObjects:
@"com.designsbydeondrae.XXXXXXX.remove_ads",
@"com.designsbydeondrae.XXXXXXX.FoundationSkills",
@"com.designsbydeondrae.XXXXXXX.IntermediateSkills",
@"com.designsbydeondrae.XXXXXXX.AllSkills",
@"com.designsbydeondrae.XXXXXXX.AdvancedSkills",
nil];
sharedInstance = [[self alloc] initWithProductIdentifiers:productIdentifiers];
);
return sharedInstance;
@end
DetailViewController.h 文件中的 IAP 编码
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController
@property (strong, nonatomic) id detailItem;
@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@end
DetailViewController.h 文件中的 IAP 编码
#import "DetailViewController.h"
@interface DetailViewController ()
- (void)configureView;
@end
@implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
if (_detailItem != newDetailItem)
_detailItem = newDetailItem;
// Update the view.
[self configureView];
- (void)configureView
// Update the user interface for the detail item.
if (self.detailItem)
self.detailDescriptionLabel.text = [self.detailItem description];
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
- (void)didReceiveMemoryWarning
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
@end
总结一下……
使用 StoreKit 访问应用内购买 API 并检索 运行构建时什么都不显示的列表 为我的应用指定产品标识符 显示产品,这似乎是一个问题,虽然它确实 显示一个屏幕,就像它即将加载一些东西然后什么都没有 页面上拉刷新【问题讨论】:
您通过调试了解到发生了什么?您的表格视图没有加载任何内容 - 好吧,这是为什么呢?它等待加载什么响应,得到什么响应? 删除并重新安装应用程序,您可能仍然拥有旧捆绑包。 requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) 返回一个空数组吗? 同名 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; @"Cell" 这绝对是荒谬的代码量,期望其他人阅读和调试。请将其减少到证明问题所需的最低限度。 【参考方案1】:对于以后发现此帖子的任何人来说,在请求 IAP 时没有显示任何项目的原因是由于未为托管内容上传内容。
【讨论】:
以上是关于尝试所有这些步骤后,“应用内购买”仍然无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章