iOS 앱에 인앱 구매를 어떻게 추가합니까? 모든 세부 사항은 무엇이며 샘플 코드가 있습니까?
이것은 iOS 앱에 인앱 구매를 추가하는 방법에 대한 모든 종류의 것입니다.
iOS 앱에 인앱 구매를 어떻게 추가합니까? 모든 세부 사항은 무엇이며 샘플 코드가 있습니까?
이것은 iOS 앱에 인앱 구매를 추가하는 방법에 대한 모든 종류의 것입니다.
답변:
Swift 사용자는 이 질문에 대한 My Swift Answer를 확인할 수 있습니다 .
또는 이 Objective-C 코드를 Swift로 변환 하는 Yedidya Reiss 's Answer를 확인하십시오 .
이 답변의 나머지 부분은 Objective-C로 작성되었습니다.
My Apps
구매를 추가하려는 앱을 클릭 한 다음 클릭Features
머리글을 클릭 한 다음 In-App Purchases
왼쪽에서+
중간에 있는 아이콘을 클릭하십시오non-consumable
. 실제 항목을 사용자에게 보내거나 두 번 이상 구입할 수있는 항목을 제공하려는 경우을 선택합니다 consumable
.tld.websitename.appname.referencename
경우 가장 잘 작동하므로 예를 들어com.jojodmo.blix.removeads
cleared for sale
하고 가격 계층 등의 1 (99 ¢)을 선택합니다. 2 단계는 1.99 달러, 3 단계는 2.99 달러입니다. view pricing matrix
계층 1을 사용하는 것이 좋습니다. 를 클릭하면 전체 목록을 볼 수 있습니다. 일반적으로 모든 사람이 광고를 제거하기 위해 지불하는 비용이 가장 많기 때문입니다.add language
버튼을 클릭하고 정보를 입력하십시오. 모두 고객에게 표시되므로 원하지 않는 것을 넣지 마십시오.hosting content with Apple
선택하십시오screenshot for review
지금을 , 모든 우리는 우리가 다시 올 것이다 건너 뜁니다.제품 ID가에 등록하는 데 몇 시간이 걸릴 수 App Store Connect
있으므로 인내심을 가지십시오.
App Store Connect에서 인앱 구매 정보를 설정 했으므로 Xcode 프로젝트로 이동 한 다음 응용 프로그램 관리자 (메서드 및 헤더 파일이있는 맨 위에있는 파란색 페이지와 같은 아이콘)로 이동하십시오. 대상 아래의 앱 (첫 번째 대상이어야 함)을 일반으로 이동하십시오. 하단에 linked frameworks and libraries
작은 더하기 기호를 클릭하고 프레임 워크를 추가하는 StoreKit.framework
것이 표시됩니다. 이렇게하지 않으면 인앱 구매가 작동 하지 않습니다 !
앱의 언어로 Objective-C를 사용하는 경우이 5 단계를 건너 뛰어야합니다 . 그렇지 않으면 Swift를 사용 하는 경우이 질문에 대해 내 Swift 답변을 따르 거나 여기 에서 In-App 구매 코드에 Objective-C를 사용하고 싶지만 앱에서 Swift를 사용하려는 경우 다음을 수행 할 수 있습니다. :
새로운 만들기 .h
로 이동하여 (헤더) 파일을 File
> New
> File...
( Command ⌘+ N). 이 파일은 .h
나머지 튜토리얼에서 "Your file" 이라고합니다.
프롬프트가 표시되면 브리징 헤더 작성을 클릭 하십시오 . 이것이 브리징 헤더 파일이 될 것입니다. 당신이 경우 되지 하라는 메시지가, 당신이 경우 3 단계로 이동 하는 메시지, 3 단계를 건너 뛰고 4 단계로 바로 이동합니다.
기본 프로젝트 폴더에 .h
이름이 지정된 다른 파일 Bridge.h
을 만든 다음 응용 프로그램 관리자 (파란색 페이지 모양 아이콘)로 이동 한 다음 Targets
섹션 에서 앱을 선택하고을 클릭 Build Settings
합니다. Swift Compiler-Code Generation 이라는 옵션을 찾은 다음 Objective-C Bridging Header 옵션을Bridge.h
브리징 헤더 파일에서, 행을 추가하십시오 #import "MyObjectiveCHeaderFile.h"
. 여기서 MyObjectiveCHeaderFile
1 단계에서 작성한 헤더 파일의 이름입니다. 예를 들어 헤더 파일 이름을 InAppPurchase.h 로 지정하면 #import "InAppPurchase.h"
브리지 헤더 파일에 행 을 추가 합니다.
새로운 목표 - C 방법 (만들기 .m
로 이동하여) 파일을 File
> New
> File...
( Command ⌘+ N). 1 단계에서 작성한 헤더 파일과 동일한 이름을 지정하십시오. 예를 들어, 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
방금 만든 것을 구매 버튼과를 restore
IBAction
복원 버튼. 이 restore
작업은 사용자가 이전에 인앱 구매를 구매했는지 확인하고 아직 구매하지 않은 경우 무료로 인앱 구매를 제공합니다.
다음으로 이동 앱 스토어에 연결 을 클릭 Users and Access
클릭 한 후 Sandbox Testers
헤더를 다음 클릭 +
밝히는 왼쪽에 기호를 Testers
. 이름과성에 임의의 항목을 넣을 수 있으며 전자 메일은 실제 일 필요는 없습니다. 전자 메일 만 기억하면됩니다. 암호를 입력하고 (기억해야 할) 나머지 정보를 입력하십시오. Date of Birth
사용자를 18 세 이상으로 만드는 날짜를 만드는 것이 좋습니다 . App Store Territory
HAS 올바른 국가에있을 수 있습니다. 다음으로, 기존 iTunes 계정에서 로그 아웃하십시오 (이 자습서 후에 다시 로그인 할 수 있음).
당신이 시뮬레이터를 실행하려고하면 지금, 당신의 iOS 장비에서 응용 프로그램을 실행 구입이됩니다 항상 오류, 당신은 해야 iOS 기기에서 실행합니다. 앱이 실행되면 구매 버튼을 누릅니다. iTunes 계정에 로그인하라는 메시지가 표시되면 방금 만든 테스트 사용자로 로그인하십시오. 다음으로 99 ¢의 구매 또는 가격 계층을 설정 한 것을 확인하라는 메시지가 표시되면 스크린 샷을 찍어screenshot for review
App Store Connect에서 사용 하십시오. 이제 결제를 취소하십시오.
이제 이동 앱 스토어 연결 로 이동 한 다음, My Apps
> the app you have the In-app purchase on
> In-App Purchases
. 그런 다음 인앱 구매를 클릭하고 인앱 구매 세부 사항에서 편집을 클릭하십시오. 그런 다음 iPhone에서 방금 찍은 사진을 컴퓨터로 가져 와서 검토 할 수 있도록 스크린 샷으로 업로드 한 다음 검토 메모에 테스트 사용자 이메일과 비밀번호를 입력하십시오. 이것은 검토 과정에서 사과를 도울 것입니다.
이 작업을 마친 후에는 iOS 장치의 응용 프로그램으로 돌아가서 여전히 테스트 사용자 계정으로 로그인 한 다음 구매 버튼을 클릭하십시오. 이번에는 지불 확인 걱정하지 마십시오. 계정에 돈이 청구되지 않습니다. 테스트 사용자 계정은 모든 인앱 구매를 무료로 얻습니다 . 결제를 확인한 후 사용자가 실제로 제품을 구입할 때 어떤 일이 발생하는지 확인하십시오 발생합니다. 그렇지 않은 경우 doRemoveAds
메서드에 오류가 발생합니다 . 다시 한 번 인앱 구매를 테스트하기 위해 배경을 파란색으로 변경하는 것이 좋습니다. 실제 인앱 구매는 아닙니다. 모든 것이 효과가 있고 나면 좋을 것입니다! App Store Connect에 업로드 할 때 새로운 바이너리에 인앱 구매를 포함시켜야합니다!
기록 : No Products Available
이것은 네 가지를 의미 할 수 있습니다.
kRemoveAdsProductIdentifier
위 코드 의 식별자)처음으로 작동하지 않으면 좌절하지 마십시오! 포기하지 마십시오! 이 작업을 수행하기 전에 약 5 시간이 걸렸으며 올바른 코드를 검색하는 데 약 10 시간이 걸렸습니다! 위의 코드를 정확하게 사용하면 정상적으로 작동합니다. 질문이 있으시면 언제든지 의견을 보내 주십시오.
iOS 앱에 인앱 구매를 추가하려는 모든 사람들에게 도움이되기를 바랍니다. 건배!
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")
}
}
}
}
이것은 Objective-C 답변이 너무 커지지 않도록 Swift 사용자 를 위해 내 Objective-C 답변 을 보충하기위한 것 입니다.
먼저 appstoreconnect.apple.com 에서 인앱 구매를 설정하십시오 . 이에 대한 지침은 Objective-C 답변 의 시작 부분 ( App Store Connect 헤더 아래의 1-13 단계 )을 따르십시오.
제품 ID가 App Store Connect에 등록 되려면 몇 시간이 걸릴 수 있으므로 기다려주십시오.
App Store Connect에서 인앱 구매 정보를 설정 했으므로 인앱 구매를위한 Apple의 프레임 워크를 앱에 추가해야 StoreKit
합니다.
Xcode 프로젝트로 이동하여 응용 프로그램 관리자 (앱 파일이있는 왼쪽 막대 상단의 파란색 페이지와 같은 아이콘)로 이동하십시오. 왼쪽의 타겟 아래에서 앱을 클릭 한 다음 (첫 번째 옵션이어야 함) 상단의 "기능"으로 이동하십시오. 목록에 "앱 내 구매"옵션이 표시됩니다. 이 기능을 켜면 Xcode가 StoreKit
프로젝트에 추가 됩니다.
이제 코딩을 시작하겠습니다!
먼저 모든 인앱 구매를 관리 할 새로운 신속한 파일을 만드십시오. 나는 그것을 부를 것이다 IAPManager.swift
.
이 파일에서 우리는 새로운 클래스 인 create IAPManager
a SKProductsRequestDelegate
and 를 만들 것 SKPaymentTransactionObserver
입니다. 상단에 반드시 가져 만든다 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()
를 시작하고 RemoveAdsManager.restoreRemoveAds()
어딘가에 버튼과 같은 복원 및 통화 를 시작할 수있는 방법을 추가해야합니다 ! App Store 지침에 따라 구매를 어딘가에 복원 할 수있는 버튼을 제공해야합니다.
마지막으로 App Store Connect에서 검토를 위해 IAP를 제출하십시오! 이를 수행하는 방법에 대한 자세한 지침은 Objective-C answer 의 마지막 부분 인 제출을 위해 제출 헤더 아래를 참조하십시오 .
RMStore 는 인앱 구매를위한 간단한 iOS 라이브러리입니다. StoreKit API를 래핑하고 비동기 요청을위한 편리한 블록을 제공합니다. 제품 구입은 단일 방법을 호출하는 것만 큼 쉽습니다.
고급 사용자를 위해이 라이브러리는 영수증 확인, 컨텐츠 다운로드 및 트랜잭션 지속성을 제공합니다.
나는 이것을 게시하기에 꽤 늦었지만 IAP 모델의 로프를 배울 때 비슷한 경험을 공유합니다.
인앱 구매는 Storekit 프레임 워크로 구현 된 iOS에서 가장 포괄적 인 워크 플로우 중 하나입니다. 전체 문서는 당신이 인내심을 읽을 경우 매우 분명하다,하지만 다소 전문적 자연에서 진행된다.
요약:
1-제품 요청-SKProductRequest 및 SKProductRequestDelegate 클래스를 사용하여 제품 ID 요청을 발행하고 자신의 itunesconnect 상점에서 다시 수신하십시오.
이 SKProducts는 사용자가 특정 제품을 구매하는 데 사용할 수있는 상점 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-복원 단추 플로우-SKPaymentQueue의 restoreCompletedTransactions를 사용하여이를 수행하십시오.-3 단계는 SKPaymentTransactionObserver의 다음 메소드와 함께 나머지를 처리합니다.
paymentQueueRestoreCompletedTransactionsFinished
restoreCompletedTransactionsFailedWithError
다음 은 단계별 자습서 (자신의 이해 시도의 결과로 저에게 작성)를 설명하는 단계별 자습서입니다. 마지막으로 직접 사용할 수있는 코드 샘플도 제공합니다.
다음 은 텍스트 만 더 잘 설명 할 수있는 특정 사항을 설명하기 위해 만든 것입니다.