解决应用内购买的无效产品 ID 问题?

Posted

技术标签:

【中文标题】解决应用内购买的无效产品 ID 问题?【英文标题】:Resolving invalid product id issue with in-app purchases? 【发布时间】:2011-12-16 10:49:36 【问题描述】:

这是“In app purchases with MKStoreKit failing: “Problem in iTunes connect configuration for product: xxx”的后续问题

我遇到了类似的问题,并尝试使用和不使用 MKStoreKit 并得到类似的消息。

检查清单

感谢:http://troybrant.net/blog/2010/01/invalid-product-ids/

您是否为您的 App ID 启用了应用内购买?

是的

您是否为您的产品检查过清仓销售?

是的

您是否已提交(并可选择拒绝)您的应用程序二进制文件?

是的

您项目的 .plist Bundle ID 是否与您的 App ID 匹配?

是的

您是否为新的 App ID 生成并安装了新的配置文件?

是的

您是否已将项目配置为使用此新的配置文件进行代码签名?

是的

您是在为 iPhone OS 3.0 或更高版本构建吗?

是的。 ios4.2 及更高版本。

您在发出 SKProductRequest 时是否使用了完整的产品 ID?

是的。也只是产品 ID 本身,没有反向域

您是否在将产品添加到 iTunes Connect 后等待了几个小时?

是的。上面写着“等待审核”,并且在过去 4-5 天内完成了

您的银行详细信息在 iTunes Connect 上是否有效?

没有。这是一个客户项目,我只是在测试它是否有效。我需要银行详细信息来测试吗?

编辑:我现在已经改变了。但我不明白为什么我需要这样做只是为了测试沙盒。

您是否尝试过从设备中删除该应用并重新安装?

是的

你的设备越狱了吗?

没有


应用符号正确

我见过的一些例子使用了这种表示法: com.domain.APP_ID.PRODUCT_TO_BUY

但其他人使用 com.domain.PRODUCT_TO_BUY

哪个是对的?

在我的代码中,我尝试使用完整的符号和产品 ID 本身,但仍然遇到“无效的产品 ID”的问题。

开发者被拒绝

App Bundle (Release) 在 iTunes Connect 上,我已经“开发者拒绝”了这个包。

图片:

等待审核?

在我的应用内购买中,我有 1 个产品,即自动续订订阅。已获准出售;然而,它是“等待审核”并且不是绿灯。

图片:

我几乎是在 4-5 天前创建的,但它仍然标记为“等待审核”??

我想知道我的应用是否被“开发者拒绝”,这是否会影响自动续订订阅的“等待审核”?

我没有更改此项目中的任何内容。

根据各种文章,我必须等待 24-48 小时才能使用它?

但是我是否需要等待它被接受或绿灯才能在我的测试中使用它?

银行详细信息

我没有填写任何银行详细信息,因为这是一个客户应用程序——我是否需要先填写银行详细信息才能继续测试?

根据这些文档:http://developer.apple.com/library/ios/#technotes/tn2259/_index.html 需要银行详细信息吗?

在运行应用之前,我是否需要在我的设备上使用测试帐户登录 iTunes?

我想知道是否有人可以澄清这些问题?也许就像等待应用内购买“绿灯”一样简单,或者我错过了一步?

注意:无论我使用 MKStoreKit 还是使用下面的代码,都会发生这种情况。

谢谢。

我的代码(这是非 MKStoreKit 版本)

#define kMySubscriptionFeature @"uk.co.samplewebsite.myappproject.sub1"

    - (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"Manage Subscriptions";


    if ([SKPaymentQueue canMakePayments])
    
        // Display a store to the user.

        //[MKStoreManager sharedManager];
        //NSLog(@"purhcasable = %@", [[MKStoreManager sharedManager] purchasableObjectsDescription] );
        [self requestProUpgradeProductData];

    
    else
    
        // Warn the user that purchases are disabled.
        NSString *message = @"In-app purchases are disabled. Please review your settings";
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
        [alertView release];
     // end if



#pragma mark - StoreKit Delegate

- (void) requestProductData

    SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject:kMySubscriptionFeature]];
    request.delegate = self;
    [request start];


- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response

    NSArray *myProduct = [[NSArray alloc] initWithArray:response.products];

    for(SKProduct *item in myProduct)
    

        NSLog(@"Product title: %@" , item.localizedTitle);
        NSLog(@"Product description: %@" , item.localizedDescription);
        NSLog(@"Product price: %@" , item.price);
        NSLog(@"Product id: %@" , item.productIdentifier);
    


    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    
        NSLog(@"Problem in iTunes connect configuration for product: %@" , invalidProductId);
    


    [myProduct release];

    // populate UI
    [request autorelease];

编辑:

为防万一,我添加了银行详细信息以防万一,但我不明白为什么这会导致问题。

我还确保我上传并拒绝了应用发布包,而不是临时发布包;虽然我不知道这是否有什么不同。

【问题讨论】:

【参考方案1】:

经过 2 天的等待,新的应用程序 ID、配置文件等为我解决了这个问题..

为什么文档说要使用完整的 com.iap.isrubbish 语法?

感谢您的帮助

我换了:

定义 kMySubscriptionFeature @"uk.co.somesite.someapp.sub1"

与:

定义 kMySubscriptionFeature @"sub1"

【讨论】:

哇...我花了整整一周的时间寻找错误。我删除了 2 个捆绑包,创建了新的捆绑包,做了很多研究才找到这个。它奏效了……我只想拥抱你们俩。 :D 我在使用完整 ID 时获得了一些销售额。但是对于某些用户,我仍然收到无效的产品 ID 错误。在 2016 年改变这一点会奏效吗?【参考方案2】:

我想我现在已经做到了。我将进行一些测试以确保。

这暂时不会被接受;我正在使用不同的 storekit 框架运行一些测试。

我的输出:

2011-10-27 15:17:49.297 My Simple App[7376:707] productsRequest
2011-10-27 15:17:49.298 My Simple App[7376:707] Product title: Simple subscription
2011-10-27 15:17:49.299 My Simple App[7376:707] Product description: Subscribe and get the latest content to your iPhone or iPod Touch device
2011-10-27 15:17:49.299 My Simple App[7376:707] Product price: 2.99
2011-10-27 15:17:49.300 My Simple App[7376:707] Product id: sub1

这就是我所做的。

    我添加了我的银行详细信息。我仍然认为这与它没有任何关系。

    注意。该应用的应用内购买仍然是“等待审核”,我得到了上面的输出。

    我换了:

    #define kMySubscriptionFeature @"uk.co.somesite.someapp.sub1"

与:

#define kMySubscriptionFeature @"sub1"

我将使用 MKStoreKit 和其他框架运行一些测试,看看它是否可以。

我使用的代码如下,出于安全原因编辑:

.h 文件

//  ManageSubscriptionsVC.h
//  This doesn't have visual output, just NSLog at the moment
//  This doesn't use MKStoreKit yet

#import <UIKit/UIKit.h>
#import "StoreKit/StoreKit.h"

#define kMySubscriptionFeature @"sub1"

/*
 Shared Secret
 
 A shared secret is a unique code that you should use when you make the 
 call to our servers for your In-App Purchase receipts. 
 Without a shared secret, you will not be able to test auto-renewable 
 In-App Purchase subscriptions in the sandbox mode. 
 
 Also note that you will not be able to make them available 
 on the App Store.
 
 Note: Regardless of what app they are associated with, 
 all of your auto-renewable subscriptions will use this 
 same shared secret.
 */
#define sharedSecret @"PUTSHAREDSECRETHERE"


@interface ManageSubscriptionsVC : UIViewController
<SKProductsRequestDelegate, SKProductsRequestDelegate, SKPaymentTransactionObserver>

    SKProduct *proUpgradeProduct;
    SKProductsRequest *productsRequest;


- (void)requestProUpgradeProductData;

@end

.m 文件

//
//  ManageSubscriptionsVC.m

#import "ManageSubscriptionsVC.h"

@implementation ManageSubscriptionsVC

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)didReceiveMemoryWarning

    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.


#pragma mark - View lifecycle

- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title = @"Manage Subscriptions";
    
    
    if ([SKPaymentQueue canMakePayments])
    
        // Display a store to the user.
        
        //[MKStoreManager sharedManager];
        //NSLog(@"purhcasable = %@", [[MKStoreManager sharedManager] purchasableObjectsDescription] );
        [self requestProUpgradeProductData];
        
    
    else
    
        // Warn the user that purchases are disabled.
        NSString *message = @"In-app purchases are disabled. Please review your settings";
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
        [alertView release];
     // end if


- (void)viewDidUnload

    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);


#pragma mark - StoreKit Delegate

- (void) requestProductData

    NSLog(@"requestProductData");
    SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject:kMySubscriptionFeature]];
    request.delegate = self;
    [request start];


- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response

    NSLog(@"productsRequest");
    
    NSArray *myProduct = [[NSArray alloc] initWithArray:response.products];
    
    for(SKProduct *item in myProduct)
    
        
        NSLog(@"Product title: %@" , item.localizedTitle);
        NSLog(@"Product description: %@" , item.localizedDescription);
        NSLog(@"Product price: %@" , item.price);
        NSLog(@"Product id: %@" , item.productIdentifier);
        
        
    

    /*
    for(NSString *invalidProduct in response.invalidProductIdentifiers)
        NSLog(@"Problem in iTunes connect configuration for product: %@", invalidProduct);
    */
    
    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    
        NSLog(@"Problem in iTunes connect configuration for product: %@" , invalidProductId);
    
    
    
    [myProduct release];
    
    // populate UI
    [request autorelease];


#pragma mark - PaymentQueue

-(void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions



-(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error



-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions



-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue



#pragma mark - Other


- (void)requestProUpgradeProductData

    NSSet *productIdentifiers = [NSSet setWithObject:kMySubscriptionFeature];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
    
    // we will release the request object in the delegate callback






@end

【讨论】:

【参考方案3】:

我刚刚发现我在创建应用内购买时交换了产品 ID 和参考名称,所以在我的情况下,我使用错误的字符串来尝试查找产品......很难发现。

【讨论】:

【参考方案4】:

当我开始在 iTunes 连接消息中看到问题时,我正在使用应用程序购买功能测试我现有的、功能齐全的应用程序的最新版本,以确保该功能仍按预期工作。我的问题是(我忘记了)MKStoreKit 将购买的事实存储在我的各种设备的钥匙串上,所以即使我使用的是新用户帐户,我的钥匙串也会将设备注册为已购买的设备。 MKStoreManager 中的 [self removeAllKeychainData] 解决了这个问题。 希望这可以减轻一些人的挫败感。

【讨论】:

【参考方案5】:

我的问题是,我使用真实的苹果 ID 登录了设备。然后退出(Iphone->设置-> App Store->我的ID->退出) 然后再次部署,并欢呼它工作。

感谢网络上的每一个人。

【讨论】:

以上是关于解决应用内购买的无效产品 ID 问题?的主要内容,如果未能解决你的问题,请参考以下文章

应用内购买,总是无效的产品 ID

应用内购买,始终无效的产品ID

swift 4 中的应用内购买无效的产品标识符

itunesconnect - 应用内购买产品 ID 已更改

iPhone Store Kit 返回无效产品 ID 错误

iOS - 应用内购买 - 无效的产品标识符