source

앱 내 구매를 iOS 애플리케이션에 추가하려면 어떻게 해야 합니까?

itover 2023. 4. 12. 22:18
반응형

앱 내 구매를 iOS 애플리케이션에 추가하려면 어떻게 해야 합니까?

iOS 앱에 앱 내 구매를 추가하려면 어떻게 해야 합니까?자세한 내용은 무엇이며, 샘플 코드는 없습니까?

이는 iOS 앱에 앱 내 구매를 추가하는 방법에 대한 다양한 정보를 제공합니다.

Swift 사용자

Swift 사용자는 My Swift Answer에서 질문을 확인할 수 있습니다.
또는 이 Objective-C 코드를 Swift로 변환한 Yedidya Reiss의 Answer를 참조하십시오.

Objective-사용자

이 답변의 나머지 부분은 목표 C에 기재되어 있습니다.

앱스토어 연결

  1. appstoreconnect.apple.com에 접속하여 로그인합니다.
  2. [ ] 를 합니다.My Apps을 클릭해서 하실 수 있습니다.
  3. 하다를 합니다.Featuresheader를 header를 선택합니다.In-App Purchases
  4. 하다를 합니다.+
  5. 튜토리얼에서는 앱 내 이므로, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★non-consumable번 살 수 을 제공하려고 , 하실 수 있습니다consumable.
  6. 참조명은 원하는 것을 입력합니다(단, 반드시 알고 있어야 합니다).
  7. 에는 ID를 입력합니다.tld.websitename.appname.referencename이 가장 효과적이기 에 예를 「」를 할 수 있습니다.com.jojodmo.blix.removeads
  8. [ ] 를 합니다.cleared for sale1(99g)으로 하다층 2 、 1 . 99 、 은 3 、 2 . 99 、은 을 수 있습니다.view pricing matrix제1계층이는 보통 광고를 삭제하는 데 가장 많은 비용을 지불하기 때문입니다.
  9. 합니다.add language버튼을 눌러 정보를 입력합니다.모두 않은 말아 주세요.
  10. ★★★의 hosting content with Apple거절하다
  11. 지금은 리뷰 노트를 공백으로 둘 수 있습니다.
  12. 뛰다screenshot for review 일단, 우리가 건너뛴 모든 것들은 다시 돌아올 것이다.
  13. '저장'을 클릭합니다.

가 'ID'에 등록되기까지 몇 시간이 수 .App Store Connect츠미야

프로젝트 설정

앱스토어 Connect에서 앱 내 구매 정보를 설정하고 Xcode 프로젝트로 이동한 후 응용 프로그램 관리자(메서드와 헤더 파일의 맨 위에 있는 파란색 페이지 모양 아이콘)로 이동하여 대상 아래에서 앱을 클릭한 다음 일반으로 이동합니다.에는 「 」라고 됩니다.linked frameworks and libraries합니다.StoreKit.framework이렇게 하지 않으면 앱 내 구매가 작동하지 않습니다!

앱의 언어로 Objective-C를 사용하는 경우 다음 5단계를 건너뜁니다.그렇지 않으면 Swift를 사용하는 경우 My Swift Answer에 따라질문에 답하십시오. 앱 내 구매 코드에 Objective-C를 사용하지만 앱에서 Swift를 사용하는 경우 다음을 수행할 수 있습니다.

  1. " " " 를 ..h하여 파일을 작성하다FileNewFile...(Command ⌘ + ) 이 파일은 "고객님의.h을하십시오.

  2. 프롬프트가 뜨면 [Create Bridging Header]을 클릭합니다.이것은 브리징헤더 파일이 됩니다.프롬프트가 표시되지 않으면 스텝3으로 넘어갑니다프롬프트가 표시되면 스텝3을 건너뛰고 스텝4로 직접 넘어갑니다

  3. 른른을 작성하다.h '''Bridge.h Manager(파란색 아이콘하여 Application Manager(어플리케이션 매니저)에서합니다.Targets하고 을 클릭합니다.Build Settings. Swift Compiler - Code Generation 옵션을 찾아 Objective-C Bridging Header 옵션을 설정합니다.Bridge.h

  4. 에, 「」라고 하는 합니다.#import "MyObjectiveCHeaderFile.h"서, snowledge.MyObjectiveCHeaderFile는 스텝 1에서 작성한 헤더파일 이름입니다예를 들어 헤더 파일의 이름을 InAppPurchase.h로 지정하면 행을 추가합니다.#import "InAppPurchase.h"브릿지 헤더 파일로 이동합니다.

  5. 메서드를 만듭니다(Objective-C 메서드.m )에하여 파일링 합니다.FileNewFile...( + ) 스텝1에서 작성한 헤더파일과 같은 이름을 붙입니다.Command ⌘예를 들어 1단계 InAppPurchase.h에서 파일을 호출한 경우 이 새 파일을 InAppPurchase.m이라고 합니다.이 파일은 "당신의.m파일"을 참조하십시오.

코딩

이치노를 더해서 사용하다, 하다, 더 하다..h 삭제:

BOOL areAdsRemoved;

- (IBAction)restore;
- (IBAction)tapsRemoveAds;

하다'라는 것'을해야 합니다.StoreKit을 짜다.m를 추가해 .SKProductsRequestDelegate ★★★★★★★★★★★★★★★★★」SKPaymentTransactionObserver@interface★★★★

#import <StoreKit/StoreKit.h>

//put the name of your view controller in place of MyViewController
@interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver>

@end

@implementation MyViewController //the name of your view controller (same as above)
  //the code below will be added here
@end

, 그럼 이제 해 보겠습니다..m이 부분은 .

//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product

#define kRemoveAdsProductIdentifier @"put your product id (the one that we just made in App Store Connect) in here"

- (IBAction)tapsRemoveAds{
    NSLog(@"User requests to remove ads");

    if([SKPaymentQueue canMakePayments]){
        NSLog(@"User can make payments");
    
        //If you have more than one in-app purchase, and would like
        //to have the user purchase a different product, simply define 
        //another function and replace kRemoveAdsProductIdentifier with 
        //the identifier for the other product

        SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]];
        productsRequest.delegate = self;
        [productsRequest start];
    
    }
    else{
        NSLog(@"User cannot make payments due to parental controls");
        //this is called the user cannot make payments, most likely due to parental controls
    }
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    SKProduct *validProduct = nil;
    int count = [response.products count];
    if(count > 0){
        validProduct = [response.products objectAtIndex:0];
        NSLog(@"Products Available!");
        [self purchase:validProduct];
    }
    else if(!validProduct){
        NSLog(@"No products available");
        //this is called if your product id is not valid, this shouldn't be called unless that happens.
    }
}

- (void)purchase:(SKProduct *)product{
    SKPayment *payment = [SKPayment paymentWithProduct:product];

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

- (IBAction) restore{
    //this is called when the user restores purchases, you should hook this up to a button
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"received restored transactions: %i", queue.transactions.count);
    for(SKPaymentTransaction *transaction in queue.transactions){
        if(transaction.transactionState == SKPaymentTransactionStateRestored){
            //called when the user successfully restores a purchase
            NSLog(@"Transaction state -> Restored");

            //if you have more than one in-app purchase product,
            //you restore the correct product for the identifier.
            //For example, you could use
            //if(productID == kRemoveAdsProductIdentifier)
            //to get the product identifier for the
            //restored purchases, you can use
            //
            //NSString *productID = transaction.payment.productIdentifier;
            [self doRemoveAds];
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        }
    }   
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    for(SKPaymentTransaction *transaction in transactions){
        //if you have multiple in app purchases in your app,
        //you can get the product identifier of this transaction
        //by using transaction.payment.productIdentifier
        //
        //then, check the identifier against the product IDs
        //that you have defined to check which product the user
        //just purchased            

        switch(transaction.transactionState){
            case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
                //called when the user is in the process of purchasing, do not add any of your own code here.
                break;
            case SKPaymentTransactionStatePurchased:
            //this is called when the user has successfully purchased the package (Cha-Ching!)
                [self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"Transaction state -> Purchased");
                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"Transaction state -> Restored");
                //add the same code as you did from SKPaymentTransactionStatePurchased here
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                //called when the transaction does not finish
                if(transaction.error.code == SKErrorPaymentCancelled){
                    NSLog(@"Transaction state -> Cancelled");
                    //the user cancelled the payment ;(
                }
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
        }
    }
}

이제 사용자가 트랜잭션을 완료했을 때 발생하는 작업에 대한 코드를 추가하려고 합니다. 이 튜토리얼에서는 추가 제거 기능을 사용합니다.배너 뷰가 로드되었을 때 발생하는 작업에 대한 자체 코드를 추가해야 합니다.

- (void)doRemoveAds{
    ADBannerView *banner;
    [banner setAlpha:0];
    areAdsRemoved = YES;
    removeAdsButton.hidden = YES;
    removeAdsButton.enabled = NO;
    [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
    //use NSUserDefaults so that you can load whether or not they bought it
    //it would be better to use KeyChain access, or something more secure
    //to store the user data, because NSUserDefaults can be changed.
    //You're average downloader won't be able to change it very easily, but
    //it's still best to use something more secure than NSUserDefaults.
    //For the purpose of this tutorial, though, we're going to use NSUserDefaults
    [[NSUserDefaults standardUserDefaults] synchronize];
}

앱에 광고가 없으면 원하는 것을 사용할 수 있습니다.예를 들어, 우리는 배경의 색을 파란색으로 만들 수 있다.그러기 위해서는 다음을 사용합니다.

- (void)doRemoveAds{
    [self.view setBackgroundColor:[UIColor blueColor]];
    areAdsRemoved = YES
    //set the bool for whether or not they purchased it to YES, you could use your own boolean here, but you would have to declare it in your .h file

    [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
    //use NSUserDefaults so that you can load wether or not they bought it
    [[NSUserDefaults standardUserDefaults] synchronize];
}

그럼 의 viewDidLoad다음 코드를 추가합니다.

areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];
//this will load wether or not they bought the in-app purchase

if(areAdsRemoved){
    [self.view setBackgroundColor:[UIColor blueColor]];
    //if they did buy it, set the background to blue, if your using the code above to set the background to blue, if your removing ads, your going to have to make your own code here
}

를 추가했습니다.「 」로 ..xib ★★★★★★★★★★★★★★★★★」storyboard파일을 만들고 두 개의 버튼을 추가합니다. 하나는 구매라고 하고 다른 하나는 복원이라고 합니다.tapsRemoveAds IBAction과 'Manager'의 'Manager' 버튼을 클릭합니다.restore IBAction[ Restore ](복원) The ]restore액션은 사용자가 이전에 앱 내 구매를 했는지 확인하고, 아직 앱 내 구매를 하지 않은 경우 무료로 제공합니다.

리뷰를 위해 제출하다

그런 다음 App Store Connect로 이동하여Users and Access 을 합니다.Sandbox Testersheader를하여 header를 합니다.+ Testers을 사용법이메일은 진짜일 필요는 없습니다.기억만 하면 됩니다.비밀번호를 입력하고(기억해야 합니다) 나머지 정보를 입력합니다..Date of Birth18번입니다. App Store Territory 올바른 국가에 있어야 합니다.그런 다음 기존 iTunes 계정에서 로그아웃합니다(이 튜토리얼이 끝나면 다시 로그인할 수 있습니다).

이제 애플리케이션을 iOS 기기에서 실행합니다. 시뮬레이터에서 실행하려고 하면 구매 오류가 항상 발생합니다. iOS 기기에서 실행해야 합니다.앱이 실행되면 구매 버튼을 누릅니다.iTunes 계정에 로그인하라는 메시지가 나타나면 방금 만든 테스트 사용자로 로그인합니다.다음으로 99파운드의 구입을 확인하거나 가격 계층을 설정한 것을 확인하는 메시지가 뜨면 IT의 스크린 스냅숏을 찍습니다.이러한 스냅샷은 고객님이 사용하는 것입니다.screenshot for review참の참이제 결제를 취소하세요.

이제 App Store Connect로 이동하고 다음으로 이동합니다.My Appsthe app you have the In-app purchase onIn-App Purchases그런 다음 앱 내 구매를 클릭하고 앱 내 구매 상세 내역 아래에 있는 편집을 클릭합니다.그런 다음 iPhone에서 방금 찍은 사진을 컴퓨터에 Import하여 스크린샷으로 업로드한 후 리뷰 노트에 TEST User 이메일과 비밀번호를 입력합니다.이것은 검토 과정에서 사과에 도움이 될 것이다.

이 작업을 완료한 후 iOS 기기의 애플리케이션으로 돌아가서 테스트 사용자 계정으로 로그인한 후 구매 버튼을 클릭합니다.이번에는 지불 확인 Don't worry, 이것은 당신의 계정에 돈을 청구하지 않습니다. 테스트 사용자 계정은 모든 앱 내 구매를 무료로 받을 수 있습니다. 지불 확인 후 사용자가 실제로 제품을 구매했을 때 어떤 일이 일어나는지 확인하십시오.그렇지 않으면, 그것은 당신의 에러가 될 것입니다.doRemoveAds again 말씀드리지만,앱 내 테스트에서는 배경을 하는 것이 단, 실제 앱 내.다시 말씀드리지만, 앱 내 구매를 테스트하려면 배경을 파란색으로 변경하는 것이 좋습니다. 단, 실제 앱 내 구매는 아니어야 합니다.커넥트에 내용을 !앱스토어 커넥트에 업로드할 때 앱 내 구매를 새 바이너리에 포함시키세요!


일반적인 에러는 다음과 같습니다.

기록됨: No Products Available

이는 다음 4가지를 의미합니다.

  • 앱내는 ID입니다).kRemoveAdsProductIdentifier
  • App Store Connect에서 판매하기 위해 앱 내 구매를 클리어하지 않았습니다.
  • App Store Connect에 앱 내 구매 ID가 등록되기를 기다리지 않았습니다.ID 생성 후 몇 시간 정도 기다리면 문제가 해결될 것입니다.
  • 계약, 세금 및 은행 정보 입력을 완료하지 않았습니다.

한 번에 안 되더라도 화내지 마!포기하지 마세요!5시간 정도 걸려서야 제대로 된 코드를 찾을 수 있었어요!위의 코드를 그대로 사용하면 정상적으로 동작합니다.질문이 있으시면 언제든지 말씀해주세요.

Jojodmo 코드를 Swift로 변환하면 됩니다.

class InAppPurchaseManager: NSObject , SKProductsRequestDelegate, SKPaymentTransactionObserver{





//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product

let kRemoveAdsProductIdentifier = "put your product id (the one that we just made in iTunesConnect) in here"

@IBAction func tapsRemoveAds() {

    NSLog("User requests to remove ads")

    if SKPaymentQueue.canMakePayments() {
        NSLog("User can make payments")

        //If you have more than one in-app purchase, and would like
        //to have the user purchase a different product, simply define
        //another function and replace kRemoveAdsProductIdentifier with
        //the identifier for the other product
        let set : Set<String> = [kRemoveAdsProductIdentifier]
        let productsRequest = SKProductsRequest(productIdentifiers: set)
        productsRequest.delegate = self
        productsRequest.start()

    }
    else {
        NSLog("User cannot make payments due to parental controls")
        //this is called the user cannot make payments, most likely due to parental controls
    }
}


func purchase(product : SKProduct) {

    let payment = SKPayment(product: product)
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().addPayment(payment)
}

func restore() {
    //this is called when the user restores purchases, you should hook this up to a button
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}


func doRemoveAds() {
    //TODO: implement
}

/////////////////////////////////////////////////
//////////////// store delegate /////////////////
/////////////////////////////////////////////////
// MARK: - store delegate -


func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {

    if let validProduct = response.products.first {
        NSLog("Products Available!")
        self.purchase(validProduct)
    }
    else {
        NSLog("No products available")
        //this is called if your product id is not valid, this shouldn't be called unless that happens.
    }
}

func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {


    NSLog("received restored transactions: \(queue.transactions.count)")
    for transaction in queue.transactions {
        if transaction.transactionState == .Restored {
            //called when the user successfully restores a purchase
            NSLog("Transaction state -> Restored")

            //if you have more than one in-app purchase product,
            //you restore the correct product for the identifier.
            //For example, you could use
            //if(productID == kRemoveAdsProductIdentifier)
            //to get the product identifier for the
            //restored purchases, you can use
            //
            //NSString *productID = transaction.payment.productIdentifier;
            self.doRemoveAds()
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            break;
        }
    }
}


func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

    for transaction in transactions {
        switch transaction.transactionState {
        case .Purchasing: NSLog("Transaction state -> Purchasing")
            //called when the user is in the process of purchasing, do not add any of your own code here.
        case .Purchased:
            //this is called when the user has successfully purchased the package (Cha-Ching!)
            self.doRemoveAds() //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            NSLog("Transaction state -> Purchased")
        case .Restored:
            NSLog("Transaction state -> Restored")
            //add the same code as you did from SKPaymentTransactionStatePurchased here
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
        case .Failed:
            //called when the transaction does not finish
            if transaction.error?.code == SKErrorPaymentCancelled {
                NSLog("Transaction state -> Cancelled")
                //the user cancelled the payment ;(
            }
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
        case .Deferred:
            // The transaction is in the queue, but its final status is pending external action.
            NSLog("Transaction state -> Deferred")

        }


    }
}
} 

신속한 회답

이는 Swift 사용자의 Objective-C 답변을 보완하고 Objective-C 답변이 너무 커지지 않도록 하기 위한 것입니다.

세우다

먼저 appstoreconnect.apple.com에서 앱 내 구매를 설정합니다.이 작업에 대한 지침은 목표-C 답변의 시작 부분(App Store Connect 헤더 아래 단계 1-13)에 따르십시오.

제품 ID가 App Store Connect에 등록되는 데 몇 시간이 걸릴 수 있으므로 기다려 주십시오.

Connect에서내앱 내대한 Apple의 Connect로 추가해야 합니다.StoreKit , 에에접접접 , , , , , , , ,.

Xcode 프로젝트로 이동하여 응용 프로그램 매니저(앱 파일이 있는 왼쪽 바의 맨 위에 있는 파란색 페이지 모양 아이콘)로 이동합니다.왼쪽 대상 아래에 있는 앱을 클릭한 다음(첫 번째 옵션이어야 함), 맨 위에 있는 "기능"으로 이동합니다.목록에 "앱 내 구매" 옵션이 표시됩니다.켜면 에 Xcode가 됩니다.StoreKit당신의 프로젝트에 적용하세요.

코딩

이제 코드쓰기를 시작하겠습니다!

먼저 모든 앱 내 구매를 관리할 새로운 빠른 파일을 만드십시오.는 이렇게 IAPManager.swift

클래스인 '를 IAPManager은 ,입니다.SKProductsRequestDelegate ★★★★★★★★★★★★★★★★★」SKPaymentTransactionObserver Import를 합니다.Foundation ★★★★★★★★★★★★★★★★★」StoreKit

import Foundation
import StoreKit

public class IAPManager: NSObject, SKProductsRequestDelegate,
                         SKPaymentTransactionObserver {
}

구매 인앱 구매 식별자를 할 수도 ).enum복수의 IAP가 있는 경우 유지보수가 용이해집니다).

// This should the ID of the in-app-purchase you made on AppStore Connect.
// if you have multiple IAPs, you'll need to store their identifiers in
// other variables, too (or, preferably in an enum).
let removeAdsID = "com.skiplit.removeAds"

다음으로 클래스용 이니셜라이저를 추가합니다.

// This is the initializer for your IAPManager class
//
// A better, and more scaleable way of doing this
// is to also accept a callback in the initializer, and call
// that callback in places like the paymentQueue function, and
// in all functions in this class, in place of calls to functions
// in RemoveAdsManager (you'll see those calls in the code below).

let productID: String
init(productID: String){
    self.productID = productID
}

그럼 에는 꼭 .SKProductsRequestDelegate ★★★★★★★★★★★★★★★★★」SKPaymentTransactionObserver★★★★

, 그럼 이제 ㅇㅇㅇㅇㅇㅇㅇㅇ를 하겠습니다.RemoveAdsManager 수업

// This is called when a SKProductsRequest receives a response
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse){
    // Let's try to get the first product from the response
    // to the request
    if let product = response.products.first{
        // We were able to get the product! Make a new payment
        // using this product
        let payment = SKPayment(product: product)

        // add the new payment to the queue
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().add(payment)
    }
    else{
        // Something went wrong! It is likely that either
        // the user doesn't have internet connection, or
        // your product ID is wrong!
        //
        // Tell the user in requestFailed() by sending an alert,
        // or something of the sort

        RemoveAdsManager.removeAdsFailure()
    }
}

// This is called when the user restores their IAP sucessfully
private func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue){
    // For every transaction in the transaction queue...
    for transaction in queue.transactions{
        // If that transaction was restored
        if transaction.transactionState == .restored{
            // get the producted ID from the transaction
            let productID = transaction.payment.productIdentifier

            // In this case, we have only one IAP, so we don't need to check
            // what IAP it is. However, this is useful if you have multiple IAPs!
            // You'll need to figure out which one was restored
            if(productID.lowercased() == IAPManager.removeAdsID.lowercased()){
                // Restore the user's purchases
                RemoveAdsManager.restoreRemoveAdsSuccess()
            }

            // finish the payment
            SKPaymentQueue.default().finishTransaction(transaction)
        }
    }
}

// This is called when the state of the IAP changes -- from purchasing to purchased, for example.
// This is where the magic happens :)
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]){
    for transaction in transactions{
        // get the producted ID from the transaction
        let productID = transaction.payment.productIdentifier

        // In this case, we have only one IAP, so we don't need to check
        // what IAP it is.
        // However, if you have multiple IAPs, you'll need to use productID
        // to check what functions you should run here!

        switch transaction.transactionState{
        case .purchasing:
            // if the user is currently purchasing the IAP,
            // we don't need to do anything.
            //
            // You could use this to show the user
            // an activity indicator, or something like that
            break
        case .purchased:
            // the user successfully purchased the IAP!
            RemoveAdsManager.removeAdsSuccess()
            SKPaymentQueue.default().finishTransaction(transaction)
        case .restored:
                // the user restored their IAP!
                IAPTestingHandler.restoreRemoveAdsSuccess()
                SKPaymentQueue.default().finishTransaction(transaction)
        case .failed:
                // The transaction failed!
                RemoveAdsManager.removeAdsFailure()
                // finish the transaction
                SKPaymentQueue.default().finishTransaction(transaction)
        case .deferred:
                // This happens when the IAP needs an external action
                // in order to proceeded, like Ask to Buy
                RemoveAdsManager.removeAdsDeferred()
                break
        }
    }
}

이제 구매 또는 복원 구매를 시작하는 데 사용할 수 있는 몇 가지 기능을 추가해 보겠습니다.

// Call this when you want to begin a purchase
// for the productID you gave to the initializer
public func beginPurchase(){
    // If the user can make payments
    if SKPaymentQueue.canMakePayments(){
        // Create a new request
        let request = SKProductsRequest(productIdentifiers: [productID])
        // Set the request delegate to self, so we receive a response
        request.delegate = self
        // start the request
        request.start()
    }
    else{
        // Otherwise, tell the user that
        // they are not authorized to make payments,
        // due to parental controls, etc
    }
}

// Call this when you want to restore all purchases
// regardless of the productID you gave to the initializer
public func beginRestorePurchases(){
    // restore purchases, and give responses to self
    SKPaymentQueue.default().add(self)
    SKPaymentQueue.default().restoreCompletedTransactions()
}

다음으로 IAP를 관리하기 위한 새로운 유틸리티 클래스를 추가합니다.이 모든 코드가 하나의 클래스에 포함될 수 있지만 여러 개의 코드가 있으면 조금 깨끗해집니다.새 거예요.RemoveAdsManager그 에 몇 기능을 .

public class RemoveAdsManager{

    class func removeAds()
    class func restoreRemoveAds()

    class func areAdsRemoved() -> Bool

    class func removeAdsSuccess()
    class func restoreRemoveAdsSuccess()
    class func removeAdsDeferred()
    class func removeAdsFailure()
}

번째 세 기능, " " " " 입니다.removeAds,restoreRemoveAds , , , , 입니다.areAdsRemoved는 특정 액션을 수행하기 위해 호출하는 함수입니다. 네 는 4번으로 예요.IAPManager.

처음 두 기능인 '어느 정도'에 해 볼까요?removeAds ★★★★★★★★★★★★★★★★★」restoreRemoveAds:

// Call this when the user wants
// to remove ads, like when they
// press a "remove ads" button
class func removeAds(){
    // Before starting the purchase, you could tell the
    // user that their purchase is happening, maybe with
    // an activity indicator

    let iap = IAPManager(productID: IAPManager.removeAdsID)
    iap.beginPurchase()
}

// Call this when the user wants
// to restore their IAP purchases,
// like when they press a "restore
// purchases" button.
class func restoreRemoveAds(){
    // Before starting the purchase, you could tell the
    // user that the restore action is happening, maybe with
    // an activity indicator

    let iap = IAPManager(productID: IAPManager.removeAdsID)
    iap.beginRestorePurchases()
}

마지막으로 마지막 5가지 기능에 코드를 추가해 보겠습니다.

// Call this to check whether or not
// ads are removed. You can use the
// result of this to hide or show
// ads
class func areAdsRemoved() -> Bool{
    // This is the code that is run to check
    // if the user has the IAP.

    return UserDefaults.standard.bool(forKey: "RemoveAdsPurchased")
}

// This will be called by IAPManager
// when the user sucessfully purchases
// the IAP
class func removeAdsSuccess(){
    // This is the code that is run to actually
    // give the IAP to the user!
    //
    // I'm using UserDefaults in this example,
    // but you may want to use Keychain,
    // or some other method, as UserDefaults
    // can be modified by users using their
    // computer, if they know how to, more
    // easily than Keychain

    UserDefaults.standard.set(true, forKey: "RemoveAdsPurchased")
    UserDefaults.standard.synchronize()
}

// This will be called by IAPManager
// when the user sucessfully restores
//  their purchases
class func restoreRemoveAdsSuccess(){
    // Give the user their IAP back! Likely all you'll need to
    // do is call the same function you call when a user
    // sucessfully completes their purchase. In this case, removeAdsSuccess()

    removeAdsSuccess()
}

// This will be called by IAPManager
// when the IAP failed
class func removeAdsFailure(){
    // Send the user a message explaining that the IAP
    // failed for some reason, and to try again later
}

// This will be called by IAPManager
// when the IAP gets deferred.
class func removeAdsDeferred(){
    // Send the user a message explaining that the IAP
    // was deferred, and pending an external action, like
    // Ask to Buy.
}

모든 것을 종합하면 다음과 같은 결과를 얻을 수 있습니다.

import Foundation
import StoreKit

public class RemoveAdsManager{

    // Call this when the user wants
    // to remove ads, like when they
    // press a "remove ads" button
    class func removeAds(){
        // Before starting the purchase, you could tell the
        // user that their purchase is happening, maybe with
        // an activity indicator

        let iap = IAPManager(productID: IAPManager.removeAdsID)
        iap.beginPurchase()
    }

    // Call this when the user wants
    // to restore their IAP purchases,
    // like when they press a "restore
    // purchases" button.
    class func restoreRemoveAds(){
        // Before starting the purchase, you could tell the
        // user that the restore action is happening, maybe with
        // an activity indicator

        let iap = IAPManager(productID: IAPManager.removeAdsID)
        iap.beginRestorePurchases()
    }

    // Call this to check whether or not
    // ads are removed. You can use the
    // result of this to hide or show
    // ads
    class func areAdsRemoved() -> Bool{
        // This is the code that is run to check
        // if the user has the IAP.

        return UserDefaults.standard.bool(forKey: "RemoveAdsPurchased")
    }

    // This will be called by IAPManager
    // when the user sucessfully purchases
    // the IAP
    class func removeAdsSuccess(){
        // This is the code that is run to actually
        // give the IAP to the user!
        //
        // I'm using UserDefaults in this example,
        // but you may want to use Keychain,
        // or some other method, as UserDefaults
        // can be modified by users using their
        // computer, if they know how to, more
        // easily than Keychain

        UserDefaults.standard.set(true, forKey: "RemoveAdsPurchased")
        UserDefaults.standard.synchronize()
    }

    // This will be called by IAPManager
    // when the user sucessfully restores
    //  their purchases
    class func restoreRemoveAdsSuccess(){
        // Give the user their IAP back! Likely all you'll need to
        // do is call the same function you call when a user
        // sucessfully completes their purchase. In this case, removeAdsSuccess()
        removeAdsSuccess()
    }

    // This will be called by IAPManager
    // when the IAP failed
    class func removeAdsFailure(){
        // Send the user a message explaining that the IAP
        // failed for some reason, and to try again later
    }

    // This will be called by IAPManager
    // when the IAP gets deferred.
    class func removeAdsDeferred(){
        // Send the user a message explaining that the IAP
        // was deferred, and pending an external action, like
        // Ask to Buy.
    }

}

public class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver{

    // This should the ID of the in-app-purchase you made on AppStore Connect.
    // if you have multiple IAPs, you'll need to store their identifiers in
    // other variables, too (or, preferably in an enum).
    static let removeAdsID = "com.skiplit.removeAds"

    // This is the initializer for your IAPManager class
    //
    // An alternative, and more scaleable way of doing this
    // is to also accept a callback in the initializer, and call
    // that callback in places like the paymentQueue function, and
    // in all functions in this class, in place of calls to functions
    // in RemoveAdsManager.
    let productID: String
    init(productID: String){
        self.productID = productID
    }

    // Call this when you want to begin a purchase
    // for the productID you gave to the initializer
    public func beginPurchase(){
        // If the user can make payments
        if SKPaymentQueue.canMakePayments(){
            // Create a new request
            let request = SKProductsRequest(productIdentifiers: [productID])
            request.delegate = self
            request.start()
        }
        else{
            // Otherwise, tell the user that
            // they are not authorized to make payments,
            // due to parental controls, etc
        }
    }

    // Call this when you want to restore all purchases
    // regardless of the productID you gave to the initializer
    public func beginRestorePurchases(){
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().restoreCompletedTransactions()
    }

    // This is called when a SKProductsRequest receives a response
    public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse){
        // Let's try to get the first product from the response
        // to the request
        if let product = response.products.first{
            // We were able to get the product! Make a new payment
            // using this product
            let payment = SKPayment(product: product)

            // add the new payment to the queue
            SKPaymentQueue.default().add(self)
            SKPaymentQueue.default().add(payment)
        }
        else{
            // Something went wrong! It is likely that either
            // the user doesn't have internet connection, or
            // your product ID is wrong!
            //
            // Tell the user in requestFailed() by sending an alert,
            // or something of the sort

            RemoveAdsManager.removeAdsFailure()
        }
    }

    // This is called when the user restores their IAP sucessfully
    private func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue){
        // For every transaction in the transaction queue...
        for transaction in queue.transactions{
            // If that transaction was restored
            if transaction.transactionState == .restored{
                // get the producted ID from the transaction
                let productID = transaction.payment.productIdentifier

                // In this case, we have only one IAP, so we don't need to check
                // what IAP it is. However, this is useful if you have multiple IAPs!
                // You'll need to figure out which one was restored
                if(productID.lowercased() == IAPManager.removeAdsID.lowercased()){
                    // Restore the user's purchases
                    RemoveAdsManager.restoreRemoveAdsSuccess()
                }

                // finish the payment
                SKPaymentQueue.default().finishTransaction(transaction)
            }
        }
    }

    // This is called when the state of the IAP changes -- from purchasing to purchased, for example.
    // This is where the magic happens :)
    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]){
        for transaction in transactions{
            // get the producted ID from the transaction
            let productID = transaction.payment.productIdentifier

            // In this case, we have only one IAP, so we don't need to check
            // what IAP it is.
            // However, if you have multiple IAPs, you'll need to use productID
            // to check what functions you should run here!

            switch transaction.transactionState{
            case .purchasing:
                // if the user is currently purchasing the IAP,
                // we don't need to do anything.
                //
                // You could use this to show the user
                // an activity indicator, or something like that
                break
            case .purchased:
                // the user sucessfully purchased the IAP!
                RemoveAdsManager.removeAdsSuccess()
                SKPaymentQueue.default().finishTransaction(transaction)
            case .restored:
                // the user restored their IAP!
                RemoveAdsManager.restoreRemoveAdsSuccess()
                SKPaymentQueue.default().finishTransaction(transaction)
            case .failed:
                // The transaction failed!
                RemoveAdsManager.removeAdsFailure()
                // finish the transaction
                SKPaymentQueue.default().finishTransaction(transaction)
            case .deferred:
                // This happens when the IAP needs an external action
                // in order to proceeded, like Ask to Buy
                RemoveAdsManager.removeAdsDeferred()
                break
            }
        }
    }

}

할 수 있는 하고 전화를 합니다.RemoveAdsManager.removeAds()하고 restore를 호출합니다.RemoveAdsManager.restoreRemoveAds()디어선가단!앱스토어 가이드라인에 따라 구입을 복원하기 위한 버튼을 제공해야 합니다.

리뷰를 위해 제출하다

앱스토어 커넥트 리뷰를 위해 IAP를 제출하는 것은 마지막입니다.상세한 순서에 대해서는, 「Submiting for review(검토를 위한 제출)」헤더의 「Objective-C」답변 마지막 부분을 참조해 주세요.

RMStore는 앱 내 구매를 위한 경량 iOS 라이브러리입니다.StoreKit API를 랩하여 비동기 요청을 위한 편리한 블록을 제공합니다.제품 구입은 단일 메서드를 호출하는 것만큼 쉽습니다.

고급 사용자를 위해 이 라이브러리는 영수증 확인, 컨텐츠 다운로드 및 트랜잭션 지속성도 제공합니다.

이 글을 올리기에 늦은 건 알지만 IAP 모델의 요령을 배웠을 때 비슷한 경험을 공유합니다.

앱 내 구매는 Storekit 프레임워크에 의해 구현된 iOS에서 가장 포괄적인 워크플로우 중 하나입니다.참고 읽으면 문서 전체가 매우 명확하지만 기술적인 측면에서는 다소 진보되어 있습니다.

요약:

1 - 제품 요청 - SKProductRequest 및 SKProductRequestDelegate 클래스를 사용하여 제품 ID 요청을 발행하고 고객님의 itunesconnect 스토어에서 다시 받습니다.

이러한 SKProduct는 사용자가 특정 제품을 구매하기 위해 사용할 수 있는 매장 UI를 채우기 위해 사용해야 합니다.

2 - 결제요청 발행 - SKPayment & SKPaymentQueue를 사용하여 결제큐에 추가합니다.

3 - 상태 업데이트 트랜잭션 대기열 모니터링 - SKPaymentTransactionObserver Protocol의 updatedTransactions 메서드를 사용하여 상태를 모니터링합니다.

SKPaymentTransactionStatePurchasing - don't do anything
SKPaymentTransactionStatePurchased - unlock product, finish the transaction
SKPaymentTransactionStateFailed - show error, finish the transaction
SKPaymentTransactionStateRestored - unlock product, finish the transaction

4 - restore 버튼의 흐름 - SKPaymentQueue의 restore CompletedTransactions를 사용하여 이 작업을 수행합니다.다음은 스텝 3과 SKPaymentTransactionObserver의 다음 메서드가 함께 처리됩니다.

paymentQueueRestoreCompletedTransactionsFinished
restoreCompletedTransactionsFailedWithError

튜토리얼에 대해 설명하는 단계별 튜토리얼을 소개합니다(자신의 이해 시도로 작성).마지막으로 직접 사용할 수 있는 코드 샘플도 제공합니다.

여기 텍스트만이 더 잘 설명할 수 있는 것들을 설명하기 위해 제가 만든 또 다른 것이 있습니다.

언급URL : https://stackoverflow.com/questions/19556336/how-do-you-add-an-in-app-purchase-to-an-ios-application

반응형