アプリ内課金 その3 プロダクトの取得


SKRequestのサブクラスのSKProductRequestを使ってプロダクト情報を取得する。
インスタンスには下記のメソッドを使う

-(id)initWithProductIdentifiers:(NSSet*)ProductIdenTifiers;

プロダクトIDはNSSetととして設定。
ということは、複数のプロダクトを取得もできそうだけれど、今回は一個だけ。

	//プロダクトIDの集合を生成
	NSSet *productIds;
	productIds = [NSSet setWithObject:PRODUCT];
	
	//SKProductRequestを作成
	SKProductsRequest *preq = [[SKProductsRequest alloc]initWithProductIdentifiers:productIds];

次に、AppSoreにアクセスしてプロダクト情報を取得する。

  • (void)starメソッドでアクセスを開始。キャンセルは-(void)cancelメソッドを使う。

結果はデリゲートで受け取る事になる。
SKRequestDelegateプロトコルと、そのサブクラスのSKPruductsRequestDelegateで定義される。
実用上はSKProductsRequestDelegateとして設定することになるので、ヘッダーにSKProductsRequestDelegateを追加。

定義されているデリゲートメソッドは下記の3つ

-(void)requestDidFinish:(SKRequest*)request //----終了通知
-(void)request:(SKRequest*)request didFailWithError:(NSError*)error //---アクセス中のエラー
-(void)productsRequest(SKProductsRequest*)request didReceiveResponse:(SKProductsResponce*)response //--レスポンスの受信通知

アクセス結果はSKProductsResponseオブジェクトで受け取る。
このクラスにはプロダクト情報を配列で持っているProdustsプロパティを持つ。
取得に失敗した場合はinvalidProductIdentifiersという配列に入れられる。

アプリケーションでプロダクトの価格を表示する場合、どの地域の通貨か意識する必要がある。
priceプロパティとpriceLocalプロパティを使う事により変換が可能。

	NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];//フォーマットを作成

        //フォーマットを設定
	[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
	[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

        //PriceLocalを設定
	[numberFormatter setLocale:product.priceLocale];

	NSString *formattedString = [numberFormatter stringFromNumber:product.price];//価格を表示する文字列
	[numberFormatter release];
	

下記にはあえてSKPaymentQueueのオブザーバーは登録しない。
これは購入処理結果の取得で使うものなので。

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

@class WorldAppDelegate;
@interface InAppPurchaseViewController : UIViewController
<SKProductsRequestDelegate>{
	IBOutlet UILabel *lb1;
}
@property(nonatomic,retain)UILabel *lb1;
-(IBAction)purchase;
-(IBAction)closeAction;

@end


#import "InAppPurchaseViewController.h"

#define PRODUCT @"XXXX"

@implementation InAppPurchaseViewController
@synthesize lb1;
#pragma mark -
#pragma mark View lifecycle

- (void)viewDidLoad {
	[lb1 release];
	[super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];
}

#pragma mark -
#pragma mark button
-(IBAction)purchase{
	Reachability* curReach = [Reachability reachabilityForInternetConnection];
	NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
	
	//ネットワーク判定
	if ([curReach currentReachabilityStatus]==NotReachable){
		 NSLog(@"No Network");
		return;
	}
	//デバイスの機能制限
//	if([SKPaymentQueue canMakePayments]==NO){
//		NSLog(@"device lock");
//		return;
//	}
	
	//SKPaymentQueue *
	//プロダクトIDの集合を生成
	NSSet *productIds;
	productIds = [NSSet setWithObject:PRODUCT];
	
	//SKProductRequestを作成
	SKProductsRequest *preq = [[SKProductsRequest alloc]initWithProductIdentifiers:productIds];
	preq.delegate = self;
	
	//Store Kitへのアクセスを開始
	[preq start];

}

#pragma mark -
#pragma mark SKProductsRequest Delegate

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
	NSLog(@"Error: Could not contact App Store properly, %@", [error localizedDescription]);
	lb1.text = [NSString stringWithFormat:@"Error: Could not contact App Store properly, %@", [error localizedDescription]];
}

- (void)requestDidFinish:(SKRequest *)request
{
	[request release];
	NSLog(@"Request finished.");
}

-(void)productsRequest:(SKProductsRequest *)request
	didReceiveResponse:(SKProductsResponse *)response{
	
	
	SKProduct *product = [[response products] lastObject];
	if (!product)
	{
		NSLog(@"no product ids:%@",[[response invalidProductIdentifiers] lastObject]);
		return;
	}
		
	// Retrieve the localized price
	NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
	[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
	[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
	[numberFormatter setLocale:product.priceLocale];
	NSString *formattedString = [numberFormatter stringFromNumber:product.price];
	[numberFormatter release];
	
	// Create a description that gives a heads up about 
	// a non-consumable purchase
	NSString *buyString = formattedString; 
	NSString *describeString = [NSString stringWithFormat:@"%@\n\nIf you have already purchased this item, you will not be charged again.", product.localizedDescription];
	
				NSLog(@"%@",[product productIdentifier]);
				NSLog(@"%@",[product localizedTitle]);
				NSLog(@"%@",[product localizedDescription]);
				NSLog(@"%@",buyString);
				NSLog(@"%@",describeString);

}

色々なパターンでプロダクトを登録してみたが、
SKProductsRequestで指定したproductIdentifierがinvalidProductIdentifiersになって返ってくきてしまう。
色々調べてみた結果、下記の事項を調べて確認してみた。

僕の場合はDebugのコードサインが違っていたみたい。。。
上に示したコードで見事にプロダクトの取得が成功♪

  1. App IDでIn-App Purchasesは有効になっているか。
  2. そのプロダクトは「Cleared for Sale」になっているか。
  3. そのアプリの新しいバージョンをiTunes Connect上で追加しているか。(バイナリも上げておく必要があるらしい)
  4. Xcodeプロジェクトの.plistのBundle IDはApp IDと一致していますか?
  5. そのApp IDで新しいProvisioning Profileを作成してインストールしているか。
  6. アプリがそのProvisioning Profileでコードサインがされるように設定されているか。
  7. iOS 3.0以降が対象になるようにビルドされているか。
  8. SKProductRequestに渡しているProduct IDはiTunes Connectで指定したものと一致しているか。
  9. iTunes Connectでプロダクトを追加してから数時間待つ必要あり。
  10. iTunes Connectに正しく銀行口座情報が登録されているか。
  11. アプリをいったんデバイスから削除して再インストールしてみる。
  12. XcodeのDebugでビルドしないとsandboxにはつながらないらしい。


次回は購入処理を実装します。

参考
http://n-lights.co.jp/iphone-dev/category/%E6%9C%AA%E5%88%86%E9%A1%9E