Bir iOS uygulamasına uygulama içi satın alma işlemini nasıl eklersiniz? Tüm detaylar nelerdir ve herhangi bir örnek kod var mı?
Bu, iOS uygulamalarına uygulama içi satın alımların nasıl ekleneceği ile ilgili her şeyi yakalama amaçlıdır
Bir iOS uygulamasına uygulama içi satın alma işlemini nasıl eklersiniz? Tüm detaylar nelerdir ve herhangi bir örnek kod var mı?
Bu, iOS uygulamalarına uygulama içi satın alımların nasıl ekleneceği ile ilgili her şeyi yakalama amaçlıdır
Yanıtlar:
Hızlı kullanıcılar bu soru için Hızlı Yanıtım'a göz atabilir .
Veya bu Objective-C kodunu Swift'e çeviren Yedidya Reiss'in Cevabına bir göz atın .
Bu cevabın geri kalanı Objective-C'de yazılmıştır.
My Apps
sonra sen satın eklemek do istediğiniz uygulamayı tıklayınFeatures
Başlığı tıklayın ve ardından In-App Purchases
sol taraftan seçin+
Ortadaki simgeyi tıklayınnon-consumable
. Kullanıcıya fiziksel bir öğe gönderecek ya da onlara birden fazla satın alabilecekleri bir şey verecek olsaydınız, seçerdiniz consumable
.tld.websitename.appname.referencename
bu en iyi şekilde çalışır, bu nedenle örneğincom.jojodmo.blix.removeads
cleared for sale
ve ardından fiyat katmanını olarak 1 (99 ¢) seçin. Katman 2 1,99 dolar ve katman 3 2,99 dolar olur. Tam liste kullanılabilir seçeneğini tıklarsanız view pricing matrix
, 1. katmanı kullanmanızı öneririm, çünkü bu genellikle reklamları kaldırmak için ödeyecek en çok kişi olur.add language
düğmeyi tıklayın ve bilgileri girin. Bu TÜM müşteriye gösterilecek, bu yüzden görmelerini istemediğiniz hiçbir şeyi koymayınhosting content with Apple
seçinscreenshot for review
ŞİMDİ İÇİN atla, atladığımız her şey geri gelecektir.Ürün kimliğinizin kaydolması birkaç saat sürebilir App Store Connect
, bu yüzden sabırlı olun.
Artık App Store Connect'te uygulama içi satın alma bilgilerinizi ayarladığınıza, Xcode projenize gidin ve uygulama yöneticisine gidin (yöntemlerinizin ve başlık dosyalarınızın bulunduğu yerin üstündeki mavi sayfa benzeri simge) tıklayın uygulamanız hedeflerin altında (birincisi olmalıdır) sonra genel gidin. Alt tarafta, görmelisiniz linked frameworks and libraries
az şey artı simgesini tıklayın ve çerçeve eklemek StoreKit.framework
Bunu yapmazsanız, uygulama içi satın alma olacak DEĞİL çalışır!
Uygulamanızın dili olarak Objective-C kullanıyorsanız, bu beş adımı atlamanız gerekir . Aksi takdirde, Swift kullanıyorsanız, bu soru için Swift Yanıtımı takip edebilirsiniz , burada veya Uygulama İçi Satın Alma kodu için Objective-C kullanmayı tercih ediyorsanız ancak uygulamanızda Swift kullanıyorsanız aşağıdakileri yapabilirsiniz :
Yeni oluştur .h
giderek (başlık) dosyası File
> New
> File...
( Command ⌘+ N). Bu dosyaya .h
öğreticinin geri kalanında "Dosyanız" adı verilecektir
İstendiğinde, Köprüleme Başlığı Oluştur'u tıklayın . Bu köprüleme başlık dosyamız olacak. Eğer varsa değil istendiyse adım 3'e gidin edilir istendiğinde, 3. adımı atlayın ve 4. adımda doğrudan gitmek.
Ana proje klasöründe başka bir .h
dosya oluşturun Bridge.h
, ardından Uygulama Yöneticisi'ne (mavi sayfa benzeri simge) gidin, ardından Targets
bölümde uygulamanızı seçin ve simgesini tıklayın Build Settings
. Diyor seçeneği bulun Swift Compiler - Kod Üretimi ve ardından set Objective-C Bridging Başlık seçeneği içinBridge.h
Senin köprü başlık dosyasında satır ekleyin #import "MyObjectiveCHeaderFile.h"
, MyObjectiveCHeaderFile
adım birinde oluşturulan bu başlık dosyasının adıdır. Örneğin, başlık dosyanızı InAppPurchase.h olarak adlandırdıysanız , satırı #import "InAppPurchase.h"
köprü başlık dosyanıza eklersiniz .
Yeni bir Objective-C Yöntemleri (oluşturun .m
giderek) dosyası File
> New
> File...
( Command ⌘+ N). Bunu 1. adımda oluşturduğunuz başlık dosyasıyla aynı şekilde adlandırın. Örneğin, 1. adımdaki dosyayı InAppPurchase.h'de çağırdıysanız , bu yeni dosyayı InAppPurchase.m olarak adlandırırsınız . Bu dosyaya .m
öğreticinin geri kalanında "Dosyanız" adı verilecektir .
Şimdi asıl kodlamaya gireceğiz. .h
Dosyanıza aşağıdaki kodu ekleyin :
BOOL areAdsRemoved;
- (IBAction)restore;
- (IBAction)tapsRemoveAds;
Daha sonra, StoreKit
çerçeveyi .m
dosyanıza içe aktarmanız ve beyanınızdan sonra SKProductsRequestDelegate
ve SKPaymentTransactionObserver
sonra eklemeniz gerekir @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
ve şimdi .m
dosyanıza aşağıdakileri ekleyin , bu bölüm karmaşıklaşır, bu yüzden koddaki yorumları okumanızı öneririz:
//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;
}
}
}
Artık kullanıcı işlemi bitirdiğinde ne olacağına ilişkin kodunuzu eklemek istiyorsunuz, bu öğretici için eklemeleri kaldırmayı kullanıyoruz, banner görünümü yüklendiğinde ne olacağı için kendi kodunuzu eklemeniz gerekecek.
- (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];
}
Uygulamanızda reklam yoksa, istediğiniz başka bir şey kullanabilirsiniz. Örneğin, arka plan rengini mavi yapabiliriz. Bunu yapmak için kullanmak isteriz:
- (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];
}
Şimdi, viewDidLoad
yönteminizin bir yerinde aşağıdaki kodu eklemek isteyeceksiniz:
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
}
Artık tüm kodu eklediğinize, dosyanıza .xib
veya storyboard
dosyanıza gidin ve biri satın alma ve diğeri geri yükleme diyen iki düğme ekleyin. Bağla tapsRemoveAds
IBAction
sadece yaptığı satın alma düğmesine ve restore
IBAction
geri düğmesine. İşlem restore
, kullanıcının uygulama içi satın alma işlemini daha önce satın alıp almadığını kontrol eder ve henüz satın almadıysa onlara uygulama içi satın alma işlemini ücretsiz verir.
Ardından, App Store Connect'e gidin ve tıklayın, Users and Access
ardından Sandbox Testers
başlığı tıklayın ve ardından +
solda söylediği simgeyi tıklayın Testers
. Sadece ad ve soyadı için rastgele şeyler koyabilirsiniz ve e-postanın gerçek olması gerekmez - hatırlamanız gerekir. Bir şifre girin (hatırlamanız gerekecek) ve bilgilerin geri kalanını doldurun. Date of Birth
Kullanıcıyı 18 veya daha yaşlı kılacak bir tarih yapmanızı tavsiye ederim . App Store Territory
HAS doğru ülkede olmak. Ardından, mevcut iTunes hesabınızdan çıkış yapın (bu eğiticiden sonra tekrar giriş yapabilirsiniz).
Eğer simülatörü üzerinde denemenizi Şimdi, eğer iOS cihazınızda uygulamayı çalıştırmak, satın alınacak her zaman hata, sen ZORUNDA iOS cihazınızda çalıştırın. Uygulama çalıştıktan sonra satın al düğmesine dokunun. İTunes hesabınıza giriş yapmanız istendiğinde, az önce oluşturduğumuz test kullanıcısı olarak giriş yapın. Daha sonra, sizden 99 ¢ satın alma işlemini veya fiyat katmanını ne ayarladığınızı onaylamanızı istediğinde, EKRAN BİR SNAPSHOT ALINscreenshot for review
App Store Connect'iniz için kullanacağınız şey budur . Şimdi ödemeyi iptal edin.
Şimdi, gidin App Store Connect'e sonra gidin My Apps
> the app you have the In-app purchase on
> In-App Purchases
. Ardından, uygulama içi satın alma işleminizi ve uygulama içi satın alma ayrıntılarının altındaki düzenle'yi tıklayın. Bunu yaptıktan sonra, iPhone'unuzda çektiğiniz fotoğrafı bilgisayarınıza alın ve incelenmek üzere ekran görüntüsü olarak yükleyin, ardından inceleme notlarına TEST KULLANICI e-postanızı ve şifrenizi girin. Bu, elmanın inceleme sürecinde yardımcı olacaktır.
Bunu yaptıktan sonra, iOS cihazınızdaki uygulamaya tekrar gidin, yine de test kullanıcı hesabı olarak oturum açın ve satın al düğmesini tıklayın. Bu kez, ödemeyi onaylayın Endişelenmeyin, bu hesabınızdan HERHANGİ bir ücret talep etmeyecektir, test kullanıcı hesapları tüm uygulama içi satın alımları ücretsiz olarak alır Ödemeyi onayladıktan sonra, kullanıcı ürününüzü gerçekten satın aldığında ne olduğundan emin olun olur. Değilse, doRemoveAds
yönteminizle ilgili bir hata olacaktır . Yine, uygulama içi satın almayı test etmek için arka planı mavi olarak değiştirmenizi öneririm, ancak gerçek uygulama içi satın alımınız olmamalıdır. Her şey yolunda giderse ve gitmeye hazırsanız! App Store Connect'e yüklediğinizde yeni ikili dosyaya uygulama içi satın alma işlemini eklemeyi unutmayın!
Giriş yapan kullanıcı: No Products Available
Bu dört anlama gelebilir:
kRemoveAdsProductIdentifier
yukarıdaki koddaki tanımlayıcı için)İlk kez çalışmazsa, sinirlenmeyin! Vazgeçme! Bu işe başlamadan önce yaklaşık 5 saat sürdü ve doğru kodu aramak yaklaşık 10 saat sürdü! Yukarıdaki kodu tam olarak kullanırsanız, düzgün çalışmalıdır. Herhangi bir sorunuz varsa yorum yapmaktan çekinmeyin hiç .
Umarım bu, iOS uygulamalarına bir uygulama içi satın alma eklemeyi umut edenlerin tümüne yardımcı olur. Şerefe!
Jojodmo kodunu Swift'e çevirin:
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")
}
}
}
}
Bu desteklemek için tasarlanmıştır benim Objective-C cevabı çok büyük girmesini Objective-C cevabı tutmak için, Swift kullanıcıları için.
İlk olarak, appstoreconnect.apple.com adresinden uygulama içi satın alma işlemini ayarlayın . Bunu yapmakla ilgili talimatlar için Objective-C cevabımın ( App Store Connect başlığının altındaki 1-13. Adımlar) başlangıç kısmını takip edin .
Ürün kimliğinizin App Store Connect'e kaydolması birkaç saat sürebilir, bu yüzden sabırlı olun.
Uygulama içi satın alma bilgilerinizi App Store Connect'te ayarladığınıza göre, Apple'ın uygulama içi satın almalarla ilgili çerçevesini uygulamaya eklememiz gerekiyor StoreKit
.
Xcode projenize gidin ve uygulama yöneticisine gidin (soldaki çubuğun üst kısmında, uygulamanızın dosyalarının bulunduğu mavi sayfa benzeri simge). Soldaki hedeflerin altındaki uygulamanızı tıklayın (ilk seçenek olmalıdır), ardından üstteki "Yetenekler" e gidin. Listede bir "Uygulama İçi Satın Alma" seçeneği görmeniz gerekir. Bu özelliği AÇIN, Xcode StoreKit
projenize eklenecektir .
Şimdi kodlamaya başlayacağız!
İlk olarak, tüm uygulama içi satın alma işlemlerinizi yönetecek yeni bir hızlı dosya oluşturun. Ben arayacağım IAPManager.swift
.
Bu dosyada, biz denilen yeni bir sınıf oluşturmak için gidiyoruz IAPManager
bir olduğunu SKProductsRequestDelegate
ve SKPaymentTransactionObserver
. Üstte, içe aktardığınızdan Foundation
veStoreKit
import Foundation
import StoreKit
public class IAPManager: NSObject, SKProductsRequestDelegate,
SKPaymentTransactionObserver {
}
Daha sonra, uygulama içi satın alma işlemimizin tanımlayıcısını tanımlamak için bir değişken ekleyeceğiz ( enum
birden fazla IAP'niz varsa bakımı daha kolay olacak bir an da kullanabilirsiniz ).
// 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"
Şimdi sınıfımız için bir başlatıcı ekleyelim:
// 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
}
Şimdi, çalışmak SKProductsRequestDelegate
ve SKPaymentTransactionObserver
çalışmak için gerekli işlevleri ekleyeceğiz :
RemoveAdsManager
Sınıfı daha sonra ekleyeceğiz
// 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
}
}
}
Şimdi bir satın alma işlemini başlatmak veya satın alma işlemlerini geri yüklemek için kullanılabilecek bazı işlevler ekleyelim:
// 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()
}
Ardından, IAP'larımızı yönetmek için yeni bir yardımcı program sınıfı ekleyelim. Bu kodun hepsi bir sınıfta olabilir, ancak birden fazla olması onu biraz daha temiz hale getirir. Yeni bir sınıf yapacağım RemoveAdsManager
ve içine birkaç işlev koyacağım
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()
}
İlk üç fonksiyonlar, removeAds
, restoreRemoveAds
, ve areAdsRemoved
, belirli eylemleri yapmak diyeceğiz o fonksiyonlardır. Son dördü çağrılacak olanlardır IAPManager
.
İlk iki işleve bir kod ekleyelim removeAds
ve 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()
}
Son olarak, son beş işleve biraz kod ekleyelim.
// 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.
}
Hepsini bir araya getirirsek, şöyle bir şey elde ederiz:
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
}
}
}
}
Son olarak, kullanıcının satın alma işlemini başlatması ve bir yerde bir düğme gibi bir RemoveAdsManager.removeAds()
geri yükleme ve arama başlatması için bir yol eklemeniz gerekir RemoveAdsManager.restoreRemoveAds()
! App Store yönergelerine göre, satın alma işlemlerini bir yere geri yüklemek için bir düğme sağlamanız gerektiğini unutmayın.
Yapılacak son şey, IAP'nizi App Store Connect'te incelenmek üzere göndermektir! Bunu yapmakla ilgili ayrıntılı talimatlar için, İnceleme için gönder başlığı altında Objective-C cevabımın son bölümünü takip edebilirsiniz .
RMStore , Uygulama İçi Satın Alımlar için hafif bir iOS kütüphanesidir. StoreKit API'sini sarar ve size eşzamansız istekler için kullanışlı bloklar sağlar. Bir ürünü satın almak, tek bir yöntemi çağırmak kadar kolaydır.
İleri düzey kullanıcılar için bu kütüphane ayrıca makbuz doğrulaması, içerik indirmeleri ve işlemin kalıcılığı da sağlar.
Bunu yayınlamak için çok geç kaldığımı biliyorum, ancak IAP modelinin iplerini öğrendiğimde benzer deneyimleri paylaşıyorum.
Uygulama içi satın alma, iOS'ta Storekit çerçevesi tarafından uygulanan en kapsamlı iş akışlarından biridir. Tüm belgeler size sabır okumak için eğer çok açık olduğunu, ancak biraz teknik bir doğası içinde ilerletilir.
Özetlemek:
1 - Ürünleri talep edin - Ürün Kimlikleri için istek göndermek ve bunları kendi itunesconnect mağazanızdan geri almak için SKProductRequest & SKProductRequestDelegate sınıflarını kullanın.
Bu SKP ürünleri, kullanıcının belirli bir ürünü satın almak için kullanabileceği mağaza kullanıcı arayüzünü doldurmak için kullanılmalıdır.
2 - Ödeme isteği yayınla - işlem kuyruğuna ödeme eklemek için SKPayment & SKPaymentQueue kullanın.
3 - Durum güncellemesi için işlem kuyruğunu izleyin - durumu izlemek için SKPaymentTransactionObserver Protocol'un updatedTransactions yöntemini kullanın:
SKPaymentTransactionStatePurchasing - don't do anything
SKPaymentTransactionStatePurchased - unlock product, finish the transaction
SKPaymentTransactionStateFailed - show error, finish the transaction
SKPaymentTransactionStateRestored - unlock product, finish the transaction
4 - Düğme akışını geri yükle - bunu gerçekleştirmek için SKPaymentQueue'nun restoreCompletedTransactions komutunu kullanın - 3. adım, SKPaymentTransactionObserver'ın aşağıdaki yöntemleriyle birlikte geri kalanı ile ilgilenir:
paymentQueueRestoreCompletedTransactionsFinished
restoreCompletedTransactionsFailedWithError
İşte bunu (kendi anlama girişimlerimin bir sonucu olarak benim tarafımdan yazılan) açıklayan bir adım adım öğretici. Sonunda, doğrudan kullanabileceğiniz kod örneği de sağlar.
İşte sadece metnin daha iyi tanımlayabileceği bazı şeyleri açıklamak için oluşturduğum başka bir örnek.