さて、今回の問題は、2つの製品を購入するためのアプリ内購入方法を作成したことです。初めてなので、raywenderlichのチュートリアルから学びました[1] : /introduction-to-in-app-purchases-in-ios-6-tutorial、[2]: http://xcodenoobies.blogspot.com/2012/04/implementing-inapp-purchase-in-xcode.htmlおよび [ 3]: http://www.techotopia.com/index.php/An_iPhone_iOS_6_In-App_Purchase_Tutorial、問題は、アプリケーションを開発するときです。シミュレーターテスターでアカウントを作成し、エラーなしで完全に実行され、実際のデバイスでテストして完全に実行されましたが、アプリケーションがアプリストアにアクセスして承認されたときに、アプリをiPhoneにインストールしましたが、どちらの方法も機能せず、購入も復元もできず、「Apple IDを使用」、「新しいApple IDを作成」、「キャンセル」などのメッセージダイアログも表示されません。チュートリアルに従って、それを作成するコードは次のとおりです。
//--- in viewcontroller---//
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray * productIdentifiers = [[NSArray alloc] initWithObjects:INAPP1_ID,INAPP2_ID, nil];
NSMutableArray * inAppPurchases = [InAppPurchase initWithProductIdentifiers:productIdentifiers delegate:self];
NSString * msg = nil;
if (inAppPurchases != nil)
{
NSLog(@"created %d in-app-purchase objects...", inAppPurchases.count);
inAppPurchase_ProductPRIMERO = [inAppPurchases objectAtIndex:0];
[inAppPurchase_ProductPRIMERO setVerbose:FALSE];
inAppPurchase_ProductPRIMERO.progressUploadPurchase = [[MBProgressHUD alloc]initWithView:self.view];
[self.view addSubview: inAppPurchase_ProductPRIMERO.progressUploadPurchase];
inAppPurchase_ProductPRIMERO.progressUploadPurchase.mode = MBProgressHUDModeIndeterminate;
inAppPurchase_ProductPRIMERO.progressUploadPurchase.labelText = @"Buying...";
msg = [NSString stringWithFormat:@"Product One productId: %@", inAppPurchase_ProductPRIMERO.productId];
NSLog(@"%@", msg);
inAppPurchase_ProductSEGUNDO = [inAppPurchases objectAtIndex:1];
[inAppPurchase_ProductSEGUNDO setVerbose:FALSE];
inAppPurchase_ProductSEGUNDO.progressUploadPurchase = [[MBProgressHUD alloc]initWithView:self.view];
[self.view addSubview: inAppPurchase_ProductSEGUNDO.progressUploadPurchase];
inAppPurchase_ProductSEGUNDO.progressUploadPurchase.mode = MBProgressHUDModeIndeterminate;
inAppPurchase_ProductSEGUNDO.progressUploadPurchase.labelText = @"Buying...";
msg = [NSString stringWithFormat:@"Product Two productId %@", inAppPurchase_ProductSEGUNDO.productId];
NSLog(@"%@", msg);
} else {
msg = @"Error creating in-app purchases objects!";
}
NSLog(@"in ViewDidLoad doYouDidBuyPRIMERO %s", doYouDidBuyPRIMERO ? "true" : "false");
NSLog(@"in ViewDidLoad doYouDidBuySEGUNDO %s", doYouDidBuySEGUNDO ? "true" : "false");
}
-(IBAction)BuyPRIMERO:(id)sender
{
alreadyPurchased = [inAppPurchase_ProductPRIMERO alreadyPurchased];
NSLog(@"%c",alreadyPurchased);
if (!alreadyPurchased)
[inAppPurchase_ProductPRIMERO purchaseProduct];
}
-(IBAction)RestoreBuyPRIMERO:(id)sender
{
[inAppPurchase_ProductPRIMERO restorePurchase];
}
-(IBAction)BuySEGUNDO:(id)sender
{
alreadyPurchased = [inAppPurchase_ProductSEGUNDO alreadyPurchased];
NSLog(@"%c",alreadyPurchased);
if (!alreadyPurchased)
[inAppPurchase_ProductSEGUNDO purchaseProduct];
}
-(IBAction)RestoreBuySEGUNDO:(id)sender
{
[inAppPurchase_ProductSEGUNDO restorePurchase];
}
- (void)requestedProduct:(InAppPurchase *)iap identifier:(NSString*)productId name:(NSString*)productName price:(NSString*)productPrice description:(NSString*)productDescription {
NSString * _msg = nil;
if (iap == inAppPurchase_ProductPRIMERO)
{
_msg = [NSString stringWithFormat:@"Product One is valid %@ price: %@", productName, [iap getValidProductLocalizedPrice]];
NSLog(@"localized price is %@ (id is %@)", [iap getValidProductLocalizedPrice], [iap getValidProductId]);
NSString *PRIMERO =[iap getValidProductLocalizedTitle];
NSLog(@"Title: %@",PRIMERO);
NSString *pricePRIMERO = [iap getValidProductLocalizedPrice];
NSString *titlePRIMERO = [NSString stringWithFormat:@"Buy %@ %@",PRIMERO,pricePRIMERO];
PRIMEROFunctionButton.titleLabel.text = titlePRIMERO;
} else if (iap == inAppPurchase_ProductSEGUNDO)
{
_msg = [NSString stringWithFormat:@"Product Two is valid %@ price: %@", productName, [iap getValidProductLocalizedPrice]];
NSLog(@"localized price is %@ (id is %@)", [iap getValidProductLocalizedPrice], [iap getValidProductId]);
NSString *SEGUNDO =[iap getValidProductLocalizedTitle];
NSLog(@"Title: %@",SEGUNDO);
NSString *priceIcons = [iap getValidProductLocalizedPrice];
NSString *titleIcons = [NSString stringWithFormat:@"Buy %@ %@",SEGUNDO,priceSEGUNDO];
SEGUNDOButton.titleLabel.text = titleSEGUNDO
;
} else {
}
}
- (void)successfulPurchase:(InAppPurchase*)iap restored:(bool)isRestore identifier:(NSString*)productId receipt:(NSData*)transactionReceipt
{
NSString * statusMsg = nil;
if (iap == inAppPurchase_ProductPRIMERO)
{
if (isRestore)
{
statusMsg = [NSString stringWithFormat:@"Restored purchase of Product One productId: %@", productId];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"Purchase Restore Completed" message:statusMsg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
if ([iap isPurchased])
{
doYouDidBuyPRIMERO = YES;
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DO_YOU_DID_BUY_PRIMERO"];
NSLog(@"doYouDidBuyPRIMERO %s", doYouDidBuyPRIMERO ? "true" : "false");
[self HideCancelBuyPRIMERO];
}
[inAppPurchase_ProductPRIMERO.progressUploadPurchase hide:YES];
} else {
statusMsg = [NSString stringWithFormat:@"Purchased Product One productId: %@", productId];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"Purchase Completed" message:statusMsg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
if ([iap isPurchased])
{
doYouDidBuyPRIMERO = YES;
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DO_YOU_DID_BUY_PRIMERO"];
NSLog(@"doYouDidBuyPRIMERO %s", doYouDidBuyPRIMERO ? "true" : "false");
[self HideCancelBuyPRIMERO];
}
[inAppPurchase_ProductPRIMERO.progressUploadPurchase hide:YES];
}
} else if (iap == inAppPurchase_ProductSEGUNDO) {
if (isRestore)
{
statusMsg = [NSString stringWithFormat:@"Restored purchase of Product Two productId: %@", productId];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"Purchase Restore Completed" message:statusMsg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
if ([iap isPurchased])
{
doYouDidBuySEGUNDO = YES;
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DO_YOU_DID_BUY_SEGUNDO"];
NSLog(@"doYouDidBuySEGUNDO %s", doYouDidBuySEGUNDO ? "true" : "false");
[self HideCancelBuySEGUNDO];
}
[inAppPurchase_ProductSEGUNDO.progressUploadPurchase hide:YES];
} else {
statusMsg = [NSString stringWithFormat:@"Purchased Product Two productId: %@", productId];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"Purchase Completed" message:statusMsg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
if ([iap isPurchased])
{
doYouDidBuySEGUNDO = YES;
[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DO_YOU_DID_BUY_SEGUNDO"];
NSLog(@"doYouDidBuySEGUNDO %s", doYouDidBuySEGUNDO ? "true" : "false");
[self HideCancelBuySEGUNDO];
}
[inAppPurchase_ProductSEGUNDO.progressUploadPurchase hide:YES];
}
} else {
}
}
- (void)failedPurchase:(InAppPurchase*)iap error:(NSInteger)errorCode message:(NSString*)errorMessage {
NSString * statusMsg = nil;
if (iap == inAppPurchase_ProductPRIMERO)
{
statusMsg = [NSString stringWithFormat:@"Failed purchased for Product One!\Error code: %d Error message: %@", errorCode, errorMessage];
NSLog(@"%@",statusMsg);
}else if (iap == inAppPurchase_ProductSEGUNDO) {
statusMsg = [NSString stringWithFormat:@"Failed purchased for Product Two!\nError code: %d Error message: %@", errorCode, errorMessage];
NSLog(@"%@",statusMsg);
} else {
}
}
- (void)incompleteRestore:(InAppPurchase*)iap {
NSString * statusMsg = nil;
if (iap == inAppPurchase_ProductPRIMERO) {
statusMsg = @"Incomplete restore for Product One!";
NSLog(@"%@",statusMsg);
} else if (iap == inAppPurchase_ProductSEGUNDO) {
statusMsg = @"Incomplete restore for Product Two!";
NSLog(@"%@",statusMsg);
} else {
}
}
- (void)failedRestore:(InAppPurchase*)iap error:(NSInteger)errorCode message:(NSString*)errorMessage {
NSString * statusMsg = nil;
if (iap == inAppPurchase_ProductPRIMERO) {
statusMsg = @"Failed restore for Product One";
NSLog(@"%@",statusMsg);
} else if (iap == inAppPurchase_ProductSEGUNDO) {
statusMsg = @"Failed restored for Product Two!";
NSLog(@"%@",statusMsg);
} else {
}
}
// AND IN APP PURCHASE HELPER .m
#import "InAppPurchase.h"
@implementation InAppPurchase
@synthesize delegate;
@synthesize validProduct;
@synthesize productId;
@synthesize progressUploadPurchase;
+ (NSMutableArray *)initWithProductIdentifiers:(NSArray *)productIdentifiers delegate:(id<InAppPurchaseDelegate>)_delegate {
NSMutableArray * iapPurchaseArray = nil;
if (productIdentifiers != nil) {
InAppPurchase * purchase = nil;
NSString * productIdentifier = nil;
iapPurchaseArray = [[NSMutableArray alloc] initWithCapacity:productIdentifiers.count];
for (int i = 0; i < productIdentifiers.count; i++) {
productIdentifier = [productIdentifiers objectAtIndex:i];
purchase = [[InAppPurchase alloc] initWithProductId:productIdentifier delegate:_delegate];
[iapPurchaseArray addObject:purchase];
}
}
return iapPurchaseArray;
}
+ (InAppPurchase *)initWithProductIdentifier:(NSString *)productIdentifier delegate:(id<InAppPurchaseDelegate>)_delegate {
InAppPurchase * purchase = nil;
if (productIdentifier != nil)
purchase = [[InAppPurchase alloc] initWithProductId:productIdentifier delegate:_delegate];
return purchase;
}
+ (InAppPopoverView *)showPurchasePopover:(NSArray *)purchases atPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title includeRestore:(BOOL)includeRestore delegate:(id<InAppPopoverViewDelegate>)delegate {
InAppPopoverView * inAppPopoverView = nil;
if (purchases != nil && purchases.count > 0) {
NSMutableArray * stringArray = [[NSMutableArray alloc] init];
InAppPurchase * inAppPurchase = nil;
NSString * _productTitle = nil;
NSString * localizedPrice = nil;
BOOL wrongClassObject = FALSE;
BOOL alreadyPurchased = FALSE;
for (int i = 0; i < purchases.count; i++) {
inAppPurchase = [purchases objectAtIndex:i];
if ([inAppPurchase isKindOfClass:InAppPurchase.class])
{
if ([inAppPurchase isValidProduct] == FALSE) {
NSLog(@"Your purchases NSArray contains some non InAppPurchase that has not been validated! Please check!");
_productTitle = [NSString stringWithFormat:@"%@ not validated yet!", inAppPurchase.productId];
} else {
_productTitle = [inAppPurchase getValidProductLocalizedTitle];
alreadyPurchased = [inAppPurchase alreadyPurchased];
if (alreadyPurchased) {
localizedPrice = [inAppPurchase getValidProductLocalizedPrice];
if ([InAppPurchase isRunningIPad])
_productTitle = [_productTitle stringByAppendingFormat:@" (already purchased for %@)", localizedPrice];
else
_productTitle = [_productTitle stringByAppendingFormat:@" (%@)", localizedPrice];
} else
_productTitle = [NSString stringWithFormat:@"Buy %@", [inAppPurchase getValidProductLocalizedTitle]];
}
[stringArray addObject:_productTitle];
} else
wrongClassObject = TRUE;
}
if (wrongClassObject)
NSLog(@"Your purchases NSArray contains some non InAppPurchase class objects! Please check!");
else {
if (includeRestore) {
// last add 'Restore Purchase' which is required by Apple AppStore so good idea to add or have available elsewhere
[stringArray addObject:@"Restore Purchases"];
}
inAppPopoverView = [InAppPopoverView showPopoverAtPoint:point inView:view withTitle:title withStringArray:stringArray delegate:delegate];
}
} else {
NSLog(@"nil InAppPurchases array provided!");
}
return inAppPopoverView;
}
+ (BOOL)hasAlreadyPurchased:(NSString *)productId {
BOOL result = FALSE;
if (productId != nil)
result = [[NSUserDefaults standardUserDefaults] boolForKey:productId];
return result;
}
- (id)initWithProductId:(NSString *)_productId delegate:(id<InAppPurchaseDelegate>)_delegate {
if ((self = [super init])) {
self.productId = _productId;
self.delegate = _delegate;
purchased = FALSE;
restored = FALSE;
verbose = FALSE;
NSLog(@"purchased %s", purchased? "true" : "false");
[self requestProduct:self.productId];
purchased = [[NSUserDefaults standardUserDefaults] boolForKey:self.productId];
NSLog(@"purchased %s", purchased? "true" : "false");
if (purchased)
NSLog(@"The product %@ is already purchased.", self.productId);
NSLog(@"purchased %s", purchased? "true" : "false");
}
return self;
}
- (void)setVerbose:(BOOL)_verbose {
verbose = _verbose;
}
- (BOOL)canMakePayments {
return [SKPaymentQueue canMakePayments];
}
- (BOOL)alreadyPurchased {
return [self isPurchased];
NSLog(@"purchased %s", purchased? "true alreadyPurchased" : "false alreadyPurchased");
}
- (BOOL)isPurchased
{
return purchased;
NSLog(@"purchased %s", purchased? "true" : "false");
}
- (BOOL)isRestored {
return restored;
}
- (BOOL)isValidProduct {
BOOL result = FALSE;
if (self.validProduct != nil)
result = TRUE;
return result;
}
- (NSString *)getProductId {
return self.productId;
}
- (SKProduct *)getValidProduct {
return self.validProduct;
}
- (NSString *)getValidProductId {
NSString * _id = nil;
if ([self isValidProduct])
_id = [self.validProduct productIdentifier];
return _id;
}
- (NSString *)getValidProductLocalizedDescription {
NSString * description = nil;
if ([self isValidProduct])
description = [self.validProduct localizedDescription];
return description;
}
- (NSString *)getValidProductLocalizedTitle {
NSString * title = nil;
if ([self isValidProduct])
title = [self.validProduct localizedTitle];
return title;
}
- (NSString *)getValidProductLocalizedPrice {
NSString * priceStr = nil;
if ([self isValidProduct]) {
NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:self.validProduct.priceLocale];
priceStr = [numberFormatter stringFromNumber:self.validProduct.price];
}
return priceStr;
}
- (BOOL)requestProduct:(NSString *)_id {
if (_id != nil)
{
if (verbose)
NSLog(@"InAppPurchase requestProduct: %@", _id);
if ([SKPaymentQueue canMakePayments])
{
SKProductsRequest * prodRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:_id]];
prodRequest.delegate = self;
[prodRequest start];
return YES;
} else {
if (verbose)
NSLog(@"InAppPurchase requestProduct: IAP Disabled");
return NO;
}
} else {
if (verbose)
NSLog(@"InAppPurchase requestProduct: productId = NIL");
return NO;
}
}
- (BOOL)purchaseProduct {
return [self purchaseProduct:self.validProduct];
}
- (BOOL)purchaseProduct:(SKProduct*)requestedProduct
{
NSLog(@"InAppPurchase purchaseProduct: %@", requestedProduct.productIdentifier);
if (requestedProduct != nil)
{
if (verbose)
NSLog(@"InAppPurchase purchaseProduct: %@", requestedProduct.productIdentifier);
if ([SKPaymentQueue canMakePayments])
{
SKPayment *paymentRequest = [SKPayment paymentWithProduct:requestedProduct];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:paymentRequest];
return YES;
} else {
if (verbose)
NSLog(@"InAppPurchase purchaseProduct: IAP Disabled");
return NO;
}
} else {
if (verbose)
NSLog(@"InAppPurchase purchaseProduct: SKProductis nil");
return NO;
}
}
- (BOOL)restorePurchase {
if (verbose)
NSLog(@"InAppPurchase restorePurchase");
if ([SKPaymentQueue canMakePayments])
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
return YES;
} else {
return NO;
}
}
- (void)clearUserDefaultsSetting {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:self.productId];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
self.validProduct = nil;
int count = [response.products count];
if (count > 0) {
self.validProduct = [response.products objectAtIndex:0];
if (verbose)
NSLog(@"got valid product %@ for product id %@", self.validProduct, productId);
}
if (self.validProduct) {
if ([delegate respondsToSelector:@selector(requestedProduct:identifier:name:price:description:)])
[delegate requestedProduct:self identifier:self.validProduct.productIdentifier name:self.validProduct.localizedTitle price:[self.validProduct.price stringValue] description:self.validProduct.localizedDescription];
} else {
if ([delegate respondsToSelector:@selector(requestedProduct:identifier:name:price:description:)])
[delegate requestedProduct:self identifier:nil name:nil price:nil description:nil];
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(@"1");
[self.progressUploadPurchase show:YES];
break;
case SKPaymentTransactionStatePurchased:
purchased = TRUE;
NSLog(@"2");
NSLog(@"purchased %s", purchased? "true" : "false");
purchased product.
if ([delegate respondsToSelector:@selector(successfulPurchase:restored:identifier:receipt:)])
[delegate successfulPurchase:self restored:NO identifier:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:transaction.payment.productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
break;
case SKPaymentTransactionStateRestored:
purchased = TRUE;
NSLog(@"3");
NSLog(@"purchased %s", purchased? "true" : "false");
if (!restored && [delegate respondsToSelector:@selector(successfulPurchase:restored:identifier:receipt:)])
[delegate successfulPurchase:self restored:YES identifier:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
restored = TRUE;
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:transaction.payment.productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"4");
[self.progressUploadPurchase hide:YES];
if (transaction.error.code != SKErrorPaymentCancelled)
{
if ([delegate respondsToSelector:@selector(failedPurchase:error:message:)])
[delegate failedPurchase:self error:transaction.error.code message:transaction.error.localizedDescription];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions {
if (verbose)
NSLog(@"InAppPurchase removedTransactions");
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
if (verbose)
NSLog(@"InAppurchase paymentQueueRestoreCompletedTransactionsFinished");
if ([queue.transactions count] == 0) {
if (verbose)
NSLog(@"InAppPurchase restore queue.transactions count == 0");
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
if ([delegate respondsToSelector:@selector(incompleteRestore:)])
[delegate incompleteRestore:self];
} else {
if (verbose)
NSLog(@"InAppPurchase restore queue.transactions available");
for (SKPaymentTransaction *transaction in queue.transactions) {
if (verbose)
NSLog(@"InAppPurchase restore queue.transactions - transaction data found");
if (!restored && [delegate respondsToSelector:@selector(successfulPurchase:restored:identifier:receipt:)])
[delegate successfulPurchase:self restored:YES identifier:transaction.payment.productIdentifier receipt:transaction.transactionReceipt];
restored = TRUE;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
if (verbose)
NSLog(@"InAppPurchase restoreCompletedTransactionsFailedWithError");
if ([delegate respondsToSelector:@selector(failedRestore:error:message:)])
[delegate failedRestore:self error:error.code message:error.localizedDescription];
}
#pragma mark - Internal Methods & Events
+ (BOOL)isRunningIPad {
if ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)]) {
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
}
return NO;
}
@end
私のコードが間違っているか不完全な場合は、どこにあるか教えてください!!、stackoverflowから別の回答を見ましたが、48時間待っているか、デバイスをリセットしましたが、エラーが見つからないか、見つかりません問題の説明があれば、apsstore に搭乗する前に同じプロジェクトで動作するのは奇妙に思えます。同じ作業プロジェクトである場合、アプリケーションをダウンロードしたときに気付く違いです。ありがとうございました。