iOSアプリにアプリ内購入をどのように追加しますか?詳細は何ですか?サンプルコードはありますか?
これは、iOSアプリにアプリ内購入を追加する方法のあらゆる種類のキャッチであることを意味します
iOSアプリにアプリ内購入をどのように追加しますか?詳細は何ですか?サンプルコードはありますか?
これは、iOSアプリにアプリ内購入を追加する方法のあらゆる種類のキャッチであることを意味します
回答:
Swiftユーザーは、この質問に対するMy Swift Answerを確認できます。
または、このObjective-CコードをSwiftに変換するYedidya Reissの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
Tier 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を使用している場合は、この質問のMy Swift Answerをここでフォローできます。または、アプリ内購入コードにObjective-Cを使用したいが、アプリでSwiftを使用している場合は、次のようにできます。 :
新しい作成.h
に行くことによって(ヘッダ)ファイルをFile
> New
> File...
(Command ⌘+ N)。このファイルは.h
、チュートリアルの残りの部分では「あなたのファイル」と呼ばれます
プロンプトが表示されたら、[ Create Bridging Header ]をクリックします。これがブリッジヘッダーファイルになります。メッセージが表示されない場合は、手順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"
をブリッジヘッダーファイルに追加します。
新しいObjective-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;
}
}
}
ここで、ユーザーがトランザクションを完了したときに何が起こるかについてコードを追加する必要があります。このチュートリアルでは、addingを削除します。バナービューが読み込まれたときに何が起こるかについて、独自のコードを追加する必要があります。
- (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
ファイルに移動し、2つのボタンを追加します。1つは購入、もう1つは復元です。作成tapsRemoveAds
IBAction
した購入ボタンとrestore
IBAction
復元ボタンに接続します。このrestore
アクションは、ユーザーが以前にアプリ内購入を購入したかどうかを確認し、まだ持っていない場合は無料でアプリ内購入を提供します。
次に、App Store Connectに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で使用するものです。ここで支払いをキャンセルします。
さて、に行くのApp Storeに接続、その後に行きます、My Apps
> the app you have the In-app purchase on
> In-App Purchases
。次に、アプリ内購入をクリックし、アプリ内購入の詳細の下にある[編集]をクリックします。それが完了したら、iPhoneで撮影した写真をコンピューターにインポートし、レビュー用のスクリーンショットとしてアップロードします。次に、レビューのメモに、テストユーザーの電子メールとパスワードを入力します。これはアップルのレビュープロセスに役立ちます。
これが完了したら、iOSデバイスのアプリケーションに戻り、まだテストユーザーアカウントとしてログインして、購入ボタンをクリックします。今回は、支払いを確認します。心配する必要はありません。アカウントにお金が請求されることはありません。ユーザーアカウントですべてのアプリ内購入を無料でテストしてください起こります。そうでない場合は、doRemoveAds
メソッドのエラーになります。繰り返しますが、アプリ内購入のテストでは背景を青に変更することをお勧めしますが、これは実際のアプリ内購入ではありません。すべてが機能し、問題がなければ、App Store Connectにアップロードするときに、アプリ内購入を新しいバイナリに含めるようにしてください。
記録: No Products Available
これは次の4つのことを意味します。
kRemoveAdsProductIdentifier
上記のコードのIDの場合)初めて動作しない場合でも、イライラしないでください!あきらめないで!これが機能するようになるまでに約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")
}
}
}
}
これは、Swiftユーザー向けのObjective-Cの回答を補足して、Objective-Cの回答が大きくなりすぎないようにするためのものです。
まず、appstoreconnect.apple.comでアプリ内購入を設定します。手順については、Objective-Cの回答の最初の部分(App Store Connectヘッダーの下の手順1〜13 )に従ってください。
製品IDがApp Store Connectに登録されるまで数時間かかる場合があるため、しばらくお待ちください。
App Store Connectでアプリ内購入情報を設定したので、アプリ内購入用のAppleのフレームワークをアプリに追加する必要がありますStoreKit
。
Xcodeプロジェクトに移動し、アプリケーションマネージャーに移動します(アプリのファイルが配置されている左のバーの上部にある青いページのようなアイコン)。左側のターゲットの下にあるアプリをクリックし(最初のオプションにする必要があります)、上部の[機能]に移動します。リストに「アプリ内購入」というオプションが表示されます。この機能をオンにすると、XcodeがStoreKit
プロジェクトに追加されます。
それでは、コーディングを始めましょう!
まず、すべてのアプリ内購入を管理する新しいSwiftファイルを作成します。私はそれを呼ぶつもりですIAPManager.swift
。
このファイルでIAPManager
は、a SKProductsRequestDelegate
およびと呼ばれる新しいクラスを作成します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を管理するための新しいユーティリティクラスを追加しましょう。このコードはすべて1つのクラスに含めることができますが、複数にすることで、コードが少しすっきりします。と呼ばれる新しいクラスを作成し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を送信することです!それを行うための詳細な手順については、「Submitting for review」ヘッダーの下にある私のObjective-C回答の最後の部分をたどることができます。
RMStoreは、アプリ内購入用の軽量iOSライブラリです。StoreKit APIをラップし、非同期リクエスト用の便利なブロックを提供します。製品の購入は、単一のメソッドを呼び出すのと同じくらい簡単です。
上級ユーザー向けに、このライブラリはレシート検証、コンテンツのダウンロード、トランザクションの持続性も提供します。
私はこれを投稿するのがかなり遅いことを知っていますが、IAPモデルのロープを学んだときにも同様の経験を共有します。
アプリ内購入は、Storekitフレームワークによって実装されるiOSの最も包括的なワークフローの1つです。全体のドキュメントは、あなたが忍耐、それを読み取ることがあれば、非常に明確であるが、やや専門的に自然の中で進んでいます。
要約する:
1-製品を要求する-SKProductRequestおよびSKProductRequestDelegateクラスを使用して、製品IDの要求を発行し、独自のitunesconnectストアからそれらを受け取ります。
これらのSKProductsは、ユーザーが特定の製品を購入するために使用できるストアUIに入力するために使用する必要があります。
2-支払い要求を発行する-SKPaymentとSKPaymentQueueを使用して、支払いをトランザクションキューに追加します。
3-ステータスの更新についてトランザクションキューを監視する-SKPaymentTransactionObserverプロトコルの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
これを説明するステップバイステップのチュートリアル(私が理解しようとした自分の試みの結果として私が作成した)は、次のとおりです。最後に、直接使用できるコードサンプルも提供します。
これは、テキストだけでより適切に説明できる特定のことを説明するために作成したもう1つの例です。