iPhone 应用内购买问题
我在应用程序中使用应用程序内购买,但在测试时遇到问题。我有四种消耗品。有关我在 tableview
中显示的产品的信息。有时,当我单击按钮购买某些产品时,我会在 updatedTransaction
函数中得到交易状态 SKPaymentTransactionStateFailed
,但 transaction.error localizedFailureReason
始终为 空
。 一旦我注意到一笔交易被更新了两次(在具有相同 transactionIdentifier
的 updatedTransaction
函数交易中,交易状态为 SKPaymentTransactionStatePurchased
) - 是那么该产品被购买了两次?
所以我不知道问题出在哪里。请帮我。
我使用该类来管理应用程序内购买:
@implementation InAppPurchaseManager
@synthesize upgradeProducts;
@synthesize productsRequest;
@synthesize delegate;
- (id) init
{
self = [super init];
if (!self) return nil;
if ([SKPaymentQueue canMakePayments]) {
[self loadStore];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
upgradeProducts = [[NSMutableArray alloc] init];
delegate = nil;
return self;
}
+ (InAppPurchaseManager *) sharedInstance
{
static InAppPurchaseManager *myInstance = nil;
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
}
return myInstance;
}
- (void) loadStore
{
NSSet *productsIdentifiers = [[NSSet alloc] initWithObjects:PRODUCT_1_ID, PRODUCT_2_ID, PRODUCT_3_ID, PRODUCT_4_ID, nil];
[self requestUpgradeProductsData:productsIdentifiers];
[productsIdentifiers release];
}
- (void) requestUpgradeProductsData:(NSSet *) productIdentifiers
{
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (void) productsRequest:(SKProductsRequest *) request didReceiveResponse:(SKProductsResponse *) response
{
[upgradeProducts removeAllObjects];
for (int i = 0; i < [response.products count]; i++) {
SKProduct *product = [response.products objectAtIndex:i];
UpgradeProduct *upgradeProduct = [[UpgradeProduct alloc] initWithProductID:product.productIdentifier];
upgradeProduct.title = product.localizedTitle;
upgradeProduct.description = product.localizedDescription;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *price = [numberFormatter stringFromNumber:product.price];
[numberFormatter release];
upgradeProduct.price = price;
[self.upgradeProducts addObject:upgradeProduct];
[upgradeProduct release];
}
[productsRequest release];
if ([self.delegate respondsToSelector:@selector(didLoadStore:)])
[self.delegate didLoadStore:self.upgradeProducts];
}
+ (BOOL) canMakePurchases
{
if ([SKPaymentQueue canMakePayments])
return YES;
else {
[Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title")
message:NSLocalizedString(@"You are not authorized to purchase from AppStore", @"Payment Error Alert Text when user cannot make payments from store")];
return NO;
}
}
- (void) purchaseUpgrade:(NSString *) productIdentifier
{
if ([InAppPurchaseManager canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
- (void) recordTransaction:(SKPaymentTransaction *) transaction
{
[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"upgradeTransactionReceipt" ];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void) finishTransaction:(SKPaymentTransaction *) transaction
{
[self paymentSucceeded:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void) paymentSucceeded:(SKPaymentTransaction *) transaction
{
// provide content here
if ([self.delegate respondsToSelector:@selector(didFinishPaymentTransaction)])
[self.delegate didFinishPaymentTransaction];
}
- (void) completeTransaction:(SKPaymentTransaction *) transaction
{
[self recordTransaction:transaction];
[self finishTransaction:transaction];
}
- (void) restoreTransaction:(SKPaymentTransaction *) transaction
{
[self recordTransaction:transaction.originalTransaction];
[self finishTransaction:transaction];
}
- (void) failedTransaction:(SKPaymentTransaction *) transaction
{
if (transaction.error.code != SKErrorPaymentCancelled) {
NSMutableString *messageToBeShown = [[NSMutableString alloc] init];
if ([transaction.error localizedFailureReason] != nil) {
[messageToBeShown setString:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Reason:", @"Reason Text in alert when payment transaction failed"), [transaction.error localizedFailureReason]]];
if ([transaction.error localizedRecoverySuggestion] != nil)
[messageToBeShown appendFormat:@", %@ %@", NSLocalizedString(@"You can try:", @"Text for sugesstion in alert when payment transaction failed"), [transaction.error localizedRecoverySuggestion]];
}
[Global showAlertViewWithTitle:NSLocalizedString(@"Unable to complete your purchase", @"Payment transaction failed alert title")
message:messageToBeShown];
[messageToBeShown release];
if ([self.delegate respondsToSelector:@selector(didFailedPaymentTransaction)])
[self.delegate didFailedPaymentTransaction];
} else {
if ([self.delegate respondsToSelector:@selector(didCancelPaymentTransaction)])
[self.delegate didCancelPaymentTransaction];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (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];
break;
default:
break;
}
}
}
- (void) request:(SKRequest *) request didFailWithError:(NSError *) error
{
[Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title")
message:[NSString stringWithFormat:@"%@, %@", NSLocalizedString(@"Could not contact App Store properly", @"Alert text when request did fail"),
[error localizedDescription]]];
}
- (void) dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[upgradeProducts release];
if (productsRequest)
productsRequest = nil;
[super dealloc];
}
@end
在函数 didFinishLaunchingWithOptions 中的 AppDelegate 中,我这样做:
[InAppPurchaseManager sharedInstance];
在购买视图中,当我单击我所做的按钮时:
UpgradeProduct *selectedProduct = [self.faxProducts objectAtIndex:[purchaseButton.identifier intValue]];
if (selectedProduct) {
[[InAppPurchaseManager sharedInstance] purchaseUpgrade:selectedProduct.productID];
}
I use In App Purchase in my application, but I have problem when I'm testing that. I have four consumable products. Information about that products I show in tableview
. Sometimes when I click a button to buy some product I get a transaction state SKPaymentTransactionStateFailed
in updatedTransaction
function but transaction.error localizedFailureReason
is always null
.
Once I noticed that one transaction was updated two times (in updatedTransaction
function transaction with the same transactionIdentifier
comes, state of transaction is SKPaymentTransactionStatePurchased
) - is then that product two times purchased?.
So I have no idea where is the problem. Please help me.
I use that class to manage In App Purchase:
@implementation InAppPurchaseManager
@synthesize upgradeProducts;
@synthesize productsRequest;
@synthesize delegate;
- (id) init
{
self = [super init];
if (!self) return nil;
if ([SKPaymentQueue canMakePayments]) {
[self loadStore];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
upgradeProducts = [[NSMutableArray alloc] init];
delegate = nil;
return self;
}
+ (InAppPurchaseManager *) sharedInstance
{
static InAppPurchaseManager *myInstance = nil;
if (nil == myInstance) {
myInstance = [[[self class] alloc] init];
}
return myInstance;
}
- (void) loadStore
{
NSSet *productsIdentifiers = [[NSSet alloc] initWithObjects:PRODUCT_1_ID, PRODUCT_2_ID, PRODUCT_3_ID, PRODUCT_4_ID, nil];
[self requestUpgradeProductsData:productsIdentifiers];
[productsIdentifiers release];
}
- (void) requestUpgradeProductsData:(NSSet *) productIdentifiers
{
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (void) productsRequest:(SKProductsRequest *) request didReceiveResponse:(SKProductsResponse *) response
{
[upgradeProducts removeAllObjects];
for (int i = 0; i < [response.products count]; i++) {
SKProduct *product = [response.products objectAtIndex:i];
UpgradeProduct *upgradeProduct = [[UpgradeProduct alloc] initWithProductID:product.productIdentifier];
upgradeProduct.title = product.localizedTitle;
upgradeProduct.description = product.localizedDescription;
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *price = [numberFormatter stringFromNumber:product.price];
[numberFormatter release];
upgradeProduct.price = price;
[self.upgradeProducts addObject:upgradeProduct];
[upgradeProduct release];
}
[productsRequest release];
if ([self.delegate respondsToSelector:@selector(didLoadStore:)])
[self.delegate didLoadStore:self.upgradeProducts];
}
+ (BOOL) canMakePurchases
{
if ([SKPaymentQueue canMakePayments])
return YES;
else {
[Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title")
message:NSLocalizedString(@"You are not authorized to purchase from AppStore", @"Payment Error Alert Text when user cannot make payments from store")];
return NO;
}
}
- (void) purchaseUpgrade:(NSString *) productIdentifier
{
if ([InAppPurchaseManager canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
- (void) recordTransaction:(SKPaymentTransaction *) transaction
{
[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"upgradeTransactionReceipt" ];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void) finishTransaction:(SKPaymentTransaction *) transaction
{
[self paymentSucceeded:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void) paymentSucceeded:(SKPaymentTransaction *) transaction
{
// provide content here
if ([self.delegate respondsToSelector:@selector(didFinishPaymentTransaction)])
[self.delegate didFinishPaymentTransaction];
}
- (void) completeTransaction:(SKPaymentTransaction *) transaction
{
[self recordTransaction:transaction];
[self finishTransaction:transaction];
}
- (void) restoreTransaction:(SKPaymentTransaction *) transaction
{
[self recordTransaction:transaction.originalTransaction];
[self finishTransaction:transaction];
}
- (void) failedTransaction:(SKPaymentTransaction *) transaction
{
if (transaction.error.code != SKErrorPaymentCancelled) {
NSMutableString *messageToBeShown = [[NSMutableString alloc] init];
if ([transaction.error localizedFailureReason] != nil) {
[messageToBeShown setString:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Reason:", @"Reason Text in alert when payment transaction failed"), [transaction.error localizedFailureReason]]];
if ([transaction.error localizedRecoverySuggestion] != nil)
[messageToBeShown appendFormat:@", %@ %@", NSLocalizedString(@"You can try:", @"Text for sugesstion in alert when payment transaction failed"), [transaction.error localizedRecoverySuggestion]];
}
[Global showAlertViewWithTitle:NSLocalizedString(@"Unable to complete your purchase", @"Payment transaction failed alert title")
message:messageToBeShown];
[messageToBeShown release];
if ([self.delegate respondsToSelector:@selector(didFailedPaymentTransaction)])
[self.delegate didFailedPaymentTransaction];
} else {
if ([self.delegate respondsToSelector:@selector(didCancelPaymentTransaction)])
[self.delegate didCancelPaymentTransaction];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (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];
break;
default:
break;
}
}
}
- (void) request:(SKRequest *) request didFailWithError:(NSError *) error
{
[Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title")
message:[NSString stringWithFormat:@"%@, %@", NSLocalizedString(@"Could not contact App Store properly", @"Alert text when request did fail"),
[error localizedDescription]]];
}
- (void) dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[upgradeProducts release];
if (productsRequest)
productsRequest = nil;
[super dealloc];
}
@end
In AppDelegate in function didFinishLaunchingWithOptions I make that:
[InAppPurchaseManager sharedInstance];
In Purchase View when I click a button I make:
UpgradeProduct *selectedProduct = [self.faxProducts objectAtIndex:[purchaseButton.identifier intValue]];
if (selectedProduct) {
[[InAppPurchaseManager sharedInstance] purchaseUpgrade:selectedProduct.productID];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
此代码是错误的,您不能多次使用。要知道,如果你添加两次观察者,你会发现一笔交易被更新了两次。
This code is wrong, you can't use more than once. You know, if you add the observer for twice , you will find one transaction was updated two times.
我有同样的问题,观察者总是有 2 个事务。即使我删除
[[SKPaymentQueue defaultQueue] addPayment: payment]
,它仍然有 1 笔交易。所以我怀疑“canMakePayments”在我删除
[SKPaymentQueue canMakePayments]
后,问题似乎解决了..不知道为什么,但可能会解决你的问题I have the same problem, observer always has 2 transaction. Even i remove
[[SKPaymentQueue defaultQueue] addPayment:payment]
, it still have 1 transaction. so i suspect the "canMakePayments"After i remove
[SKPaymentQueue canMakePayments]
, the problem seem to solve.. not sure why but may be it solve yours如果您只是进行测试,只需确保从您的个人帐户注销并在 iTunesConnect 中创建一个新的测试帐户即可。
奇怪的是,如果我不使用测试用户,它就会失败。该 API 充满了黑魔法,几乎没有解释。
If you're just testing, just make sure you sign out from your personal account and create a new test account in iTunesConnect.
Strangely it would fail if I don't use a test user. The API is full of black magic with little explanation.
确保您正确使用 AppID。我遇到了同样的问题“用户已取消”,并且我两次都没有使用正确的 ID 调用交易。我自动将 com.mycompany.product" 前缀附加到我的代码中,但在某些情况下,com.mycompany.product 已经附加了。菜鸟 bug...
Make sure you use the AppID correctly. I had the same issue "User cancelled" and I was not calling the transaction with the correct ID both times. I automatically append the com.mycompany.product" prefix to my code, but in some cases, the com.mycompany.product was already appended. Rookie bug...
我收到此错误是因为我的产品标识符错误。
I got this error because I had the wrong product identifier.