iOS2012. 6. 20. 15:19

당신은 지난 몇개월간 (어쩌면 몇일간) 고생해서 만든 앱을 앱스토어에 올려놨다.
아마 Waiting for Review단계라서 잠이 안 올지도 모르겠다.
그리고 처음 등록한 앱이라서 아직 설레이기도 하고 요즘 대세라는 FreeMium모델로 IAP도 설계해놨고
이제 대박이 나서 로또맞을 생각만 하고 있을지도 모른다. 
당신의 앱이 IAP설계상에서 만들어졌다면, 심사전에 반드시 확인하고 또 확인했으면 하는 것이 있다. 

케이스 1) 

A씨는 야심차게 준비한 앱을 승인올리고 매일 심사가 마무리되길 기다렸다.
승인을 올린지 4일 째 되던날 In Review가 들어갔고,
다음 날 아침에 일어나보니 Ready for Sale이라는 메일을 받았다.
신나서 앱을 릴리즈하고 보니 앱내에서 IAP 결제가 안되는 것이었다.
이런 망 ;;;; 



당신의 앱이 최초로 승인받는 앱이라면, IAP는 앱과 함께 "심사를 거쳐야 한다"
당신이 IAP를 통해서 무슨 콘텐츠를 제공할지 모르는 애플은 이 모든 것을 심사하길 원한다. 
그러므로 당신은 앱 심사를 올린 후에, [Manager In-App Purchases]에서 IAP의 상태를 다시 한번 점검해야 한다. 



 
IAP 아이템의 상태는 총 4가지 있으니 잘 기억하기 바란다. 


1) Ready to Submit: 당신의 IAP가 생성되었으나 아직 애플에 승인이 들어가지 않은 상태이다. 그러니 위의 케이스같은 황당한 일을 겪지 않기 위해서는 <앱 승인을 최초로 올려놓고 당신의 IAP가 "Ready for Submit"이라면> 큰 착오를 한것이라고 이해하고 다시 한번 App을 올려야 할 것이다. (IAP 승인요청 방법은 나중에...) 

2) Waiting for Review: 앱과 마찬가지로 심사를 기다리고 있는 중인 것이다. 당신은 "참 잘했어요" 도장을 받아야겠다.

3) Developer Action Needed: 이 케이스는 언제 발생하냐면, 애플이 당신의 앱을 리젝했을 때, 앱과 함께 심사를 요청했던 IAP들도 함께 심사가 반려된다. (IAP의 리젝은 아니다) 그 때 당신의 IAP의 상태는 Developer Action Needed 상태로 변결된다. 이때는 IAP의 <Display Name>을 살짝 수정해주면 다시 "Waiting for Review"상태로 변경되는 것을 확인할 수 있다. 만약 Developer Action Needed 상태에서 리젝됐던 앱만 다시 승인을 올릴 경우에는 다시 Case1의 상황을 맞을 수 있으니 주의하자. (난, 아직 안 당해서 모르겠네 ;;;) 
 

 

4) Approved: 앱이 판매 가능한 상태가 Ready for Sale 이라면 IAP는 Approved이다. 초록불을 보고 기뻐하면 된다. 



5) Waiting for Screenshot: 아, 이런 케이스도 봤다. IAP를 스크린샷으로 표현할 수 없는 경우도 있다. 그리고 어떤 개발자(혹은 담당자)는 깜빡하고 스크린샷을 안 올리는 실수를 범할 수 있다. 이때는 애플은 가찬없이 스크린샷이 없어서 심사를 못 하겠다고 한다. 이때는 스크린샷을 올리면 Waiting for Review상태로 돌아온다. 




자 이제 마무리를 하자. 
당신이 앱을 올리고 나서 [Manage IAP]메뉴로 들어가서 반드시 확인할 것은 "IAP가 Waiting for Review"상태인 것을 확인하는 것이다. 이 절차를 빠뜨렸다가는 아까운 5일의 시간을 그냥 날려버리는 수가 있다. 



In-App Purchase 아이템을 심사요청하는 절차는 애플이 프로세스를 이상하게 만들어놨다고 생각하는데,
어째든 그건 이 글이 사람들에게 도움을 주고 있는지 여부(댓글의 여부?)를 살펴보고 계속 작성해야겠다. 

Posted by 다오나무
iOS2012. 6. 20. 14:52

전에 어플내 컨텐츠 구매에 대해서 썼는데 이를 테스트하기 위해선 어떻게 해야하는지를 써 볼까 합니다. 아주 사소한 문제로 2, 3일 고생했네요..ㅋㅋ


1. 테스트용 어플 등록
 일반적으로 컨텐츠를 다운로드하기 위해선 App Store에 요청을 하여 과금요청을 하여 OK가 난 경우 실제 컨텐츠를 다운로드 받습니다.
 하지만 테스트를 하기 위해서 매번 과금요청을 하면 돈 버는 것보다 테스트하느라 나가는게 더 많겠죠. 그래서 애플은 샌드박스환경을 제공합니다.
 통상 과정을 동일하나 테스트용 계정을 만들어서 과금이 발생안하고 테스트를 가능하게 해줍니다. 단순히 OK만 주는게 아니고 구입이력도 관리해줍니다.

 우선 테스트를 위해선 App Store에 과금컨텐츠를 등록합니다. 그런데 개발중이니 어플도 등록안되어 있을 텐데 컨텐츠를 등록한다는게 웃기죠.

 iTunes Connect메뉴에 들어가서 어플을 추가합니다. 이때 어플은 바이너리를 올릴 필요없이 가짜 정보를 입력해도 됩니다. 근데 귀찮게 아이콘(512*512)도 올려야 되더군요. 입력 정보는 전부(SNU번호 이외0 나중에 수정 가능하니 대충 입력합니다.

2. App ID등록
 이렇게 등록했으면 이번엔 iTunes Developer Program Portal에 가서 새로운 App ID를 등록합니다. 물론 등록한 ID에 맞게 프로비저닝도 수정할 필요도 생깁니다.

3. 과금컨텐츠 등록
 이제 다시 iTunes Connect에 가면 In App Purchase Content를 등록하는 메뉴가 있습니다. 주체가 되는 어플과 App ID를 선택해주고 Product ID를 입력하고 등록합니다. 역시 실제로 앱스토어에 보이는게 아니니 테스트용으로 입력합니다.

4. 테스트용 ID 등록
 iTunes Connect메뉴중 Account를 관리하는 메뉴가 있고, 그 안에 보면 In app purchase Account를 관리하는게 있습니다. 여기서 테스트 유저를 만듭니다. 모든 정보, 심지어 이메일주소로 대충 입력하면 됩니다.

5. 기존 계정은 사인아웃
 실제 사용중인 계정은 설정-Store에 들어가서 사인아웃해줍니다.

6. 코드 실행
 코드를 실행하면 알림창이 뜨고 다운받을 컨텐츠 정보와 계정등을 입력하는게 뜹니다. 이건 일반적으론 안뜨고 샌드박스 환경에서 테스트할 때만 뜹니다. 이때 계정은 4번에서 만든 계정을 입력합니다.

7. 컨텐츠 다운로드
 모든게 성공하면 response로 성공이 옵니다. 그럼 컨텐츠를 다운로드 하면 OK

이게 일반적인 겁니다. 모두 레퍼런스에도 나와있죠. 그런데 전 6번에서 계정입력창이 뜨지 않고 iTunes Store에 연결할 수 없다는 에러만 나오더군요. 한참 찾았습니다. 결국 Info.plist에 정의한 번들아이디가 2번의 App ID와 완전일치하지않아서 발생했습니다. 대소문자까지 구별해서..ㅠㅠ

테스트라고 해도 모두 등록 및 설정을 확실히 해주어야 합니다.

Posted by 다오나무
영삼이의 IT정보2012. 6. 10. 19:27

스토어 킷의 클래스

SKProductsRequest : 삼풍 정보를 얻기 위해서 애플 앱스토어에 요청을 보낸다.

SKProductsResponse : 검색된 결과를 저장하는 클래스 SKProduct의 배열을 담고있다.

SKProduct: 상품 하나에 대한 정보를 저장한다. 가격, 설명 등이 주된 내용이다.

SKPayment: SKProduct를 구입하기 위해서 이클래스를 생성한다.

SKPaymentQueue: 결제를 요청하기 위해서 SKPaymentQueue 객체에 SKPayment를 넣어준다.

SKPaymentTransaction: 결제 결과를 담고 있는 클래스이다.


다양한 구매등록방법

웹서버 동기화, 로컬파일 생성, 사용자 기본값에 기록, 키체인 추가


//1. 프레임워크 추가

StoreKit.framework


//2. 헤더파일 추가

#import <StoreKit/StoreKit.h>


//3. 델리게이트 추가

SKProductsRequestDelegate, SKPaymentTransactionObserver


//4. 감시 객체 등록


- (void)viewDidUnload {

     //앱에서 아이템을 구매하려면 먼저 트랜잭션 옵져버를 추가해야한다.

     //옵져버가 있어야 실제 구매를 시작할 때 구매GUI사용 할수있음.

     SKPaymentQueue* queue = [SKPaymentQueue defaultQueue];

     [queue removeTransactionObserver:self];

}


- (void)viewDidLoad {

     SKPaymentQueue* queue = [SKPaymentQueue defaultQueue];

     [queue addTransactionObserver:self];

}


//5. 구매처리


-(IBAction)actionNoAD

{

    if ([SKPaymentQueue canMakePayments])

    {     // 스토어가 사용 가능하다면

        NSLog(@"Start Shop!");

         

        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];     // Observer를 등록한다.

    }

    else

    {

        NSLog(@"Failed Shop!");

    }

   

     //상품 요청을 생성하고 실행한다.

    SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"com.corealism.FamilyMapCh.ddd"]];

    productRequest.delegate = self;

    

    [productRequest start];

   

}




//6. SKProductsRequest 델리게이트 구현 


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

     NSLog(@"SKProductRequest got response");

     if ( [response.products count] ==0 )

     {

          UIAlertView* askView = [[UIAlertView alloc]

                                        initWithTitle:NSLocalizedString(@"Buy", @"buy items")

                                        message:NSLocalizedString(@"Can't retrieve product information.", @"buy items")

                                        delegate:self

                                        cancelButtonTitle:NSLocalizedString(@"Okay", @"confirm action")

                                        otherButtonTitles:nil

                                        ];

          [askView show];

          [askView release];

          return;

     }

   

     if( [response.products count] > 0 )

    {

          SKProduct *product = [response.products objectAtIndex:0];

          NSLog(@"Title : %@", product.localizedTitle);

          NSLog(@"Description : %@", product.localizedDescription);

          NSLog(@"Price : %@", product.price);

       

        SKPayment *payment = [SKPayment paymentWithProduct:product];

        [[SKPaymentQueue defaultQueue] addPayment:payment];

     }

    

     if( [response.invalidProductIdentifiers count] > 0 )

    {

          NSString *invalidString = [response.invalidProductIdentifiers objectAtIndex:0];

          NSLog(@"Invalid Identifiers : %@", invalidString);

     }

}



//7.SKPaymentTransactionObserver 델리게이트 구현

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

{

    for (SKPaymentTransaction *transaction in transactions)

    {

        switch (transaction.transactionState)

        {

            case SKPaymentTransactionStatePurchasing:

                NSLog(@"SKPaymentTransactionStatePurchasing");

                break;


            case SKPaymentTransactionStatePurchased:

                NSLog(@"SKPaymentTransactionStatePurchased");               

                NSLog(@"Trasaction Identifier : %@", transaction.transactionIdentifier);

                NSLog(@"Trasaction Date : %@", transaction.transactionDate);

                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

                break;

           

            case SKPaymentTransactionStateFailed:                   

                NSLog(@"SKPaymentTransactionStateFailed");               

                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

                break;

           

            case SKPaymentTransactionStateRestored:

                NSLog(@"SKPaymentTransactionStateRestored");               

                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

            default:

                break;

        }

    }

}





//8. 과거에 구매한 내역


-(void) onRestror

{

     SKPaymentQueue *queue =[SKPaymentQueue defaultQueue];

     [queue restoreCompletedTransactions];

}



//9. 구매 등록


    //사용자 설정을 변경한다.

    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"Puchased"];

    [[NSUserDefaults standardUserDefaults] synchronize];

   

    //구매버튼 숨김

    self.navigationItem.leftBarButtonItem=nil;

[출처] StoreKit|작성자 일마레

'영삼이의 IT정보' 카테고리의 다른 글

맥용 SVN 서버 설치  (0) 2012.06.12
Tabbar 아이콘  (0) 2012.06.11
iOS 키보드  (0) 2012.06.10
아이폰 OS 개발 자료 총정리  (2) 2012.06.04
UIImageJPEGRepresentation  (0) 2012.06.04
Posted by 다오나무