アプリ内課金 その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のコードサインが違っていたみたい。。。
上に示したコードで見事にプロダクトの取得が成功♪
- App IDでIn-App Purchasesは有効になっているか。
- そのプロダクトは「Cleared for Sale」になっているか。
- そのアプリの新しいバージョンをiTunes Connect上で追加しているか。(バイナリも上げておく必要があるらしい)
- Xcodeプロジェクトの.plistのBundle IDはApp IDと一致していますか?
- そのApp IDで新しいProvisioning Profileを作成してインストールしているか。
- アプリがそのProvisioning Profileでコードサインがされるように設定されているか。
- iOS 3.0以降が対象になるようにビルドされているか。
- SKProductRequestに渡しているProduct IDはiTunes Connectで指定したものと一致しているか。
- iTunes Connectでプロダクトを追加してから数時間待つ必要あり。
- iTunes Connectに正しく銀行口座情報が登録されているか。
- アプリをいったんデバイスから削除して再インストールしてみる。
- XcodeのDebugでビルドしないとsandboxにはつながらないらしい。
次回は購入処理を実装します。
参考
http://n-lights.co.jp/iphone-dev/category/%E6%9C%AA%E5%88%86%E9%A1%9E