Mobil Programlama

iOS

Kod Tarafında Gereken Geliştirmeler

Lisans: Creative Commons 11.12.2020 tarihinde güncellendi
Bakabileceğiniz Etiketler: Eğitmen: Geleceği Yazanlar Ekibi

Eğitimin bu kısmında uygulama içi satın alma için yaptığımız eklentileri kod içine nasıl ekleyeceğimizi göreceğiz. 

Projenin içinde uygulama içi satın alma özelliğini kullanmak için StoreKit adlı Framework’ü projenize eklemeniz gerekir.

Bu adımdan sonra artık projenizde uygulama içi satın alma özelliğini kullanabilirsiniz. StoreKit içinde gelen ürün yönetimi ve satın alma işlemlerini rahat yönetebilmek için ilk olarak StoreHelper adında bir yardımcı sınıf oluşturacağız. Bu sınıf bize ürünlerimizin listesini verecek ve kullanıcı satın alma işlemi yaptığında ücretin alınması ile ilgili metodları içerecek.

StoreHelper.h dosyası aşağıdaki gibi verilmiştir;

 



#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
#define kFirstProduct @"com.turkcell.ilkurun"
#define kSecondProduct @"com.turkcell.ikinciurun"
#define kNotificationKey @"StoreHelperNotification"

@interface StoreHelper : NSObject <SKRequestDelegate, SKProductsRequestDelegate, SKPaymentTransactionObserver>
+ (id) sharedStoreHelper;
- (void) requestProductList;
- (void) purchaseProduct:(SKProduct *)product;
@end

 

StoreHelper sınıfımız yapılan işlemlerin sonuçlarını öğrenebilmek için StoreKit içinde yer alan SKRequestDelegate, SKProductsRequestDelegate ve SKPaymentTransactionObserver temsilcilerini içeriyor. sharedStoreHelper sınıfımızı Singleton hale getirmek amacıyla oluşturduğumuz metoddur. requestProductList ise iTunes Connect içerisinde tanımladığımız ürünleri listeleme görevini üslenir. Kullanıcı bir ürün almak istediğinde ise purchaseProduct: metodu ile satın alma işlemini gerçekleştireceğiz.

 



#import "StoreHelper.h"

@implementation StoreHelper

static StoreHelper *sharedStoreHelper = nil;

+ (id)sharedStoreHelper {
    @synchronized(self) {
        if (sharedStoreHelper == nil)
            sharedStoreHelper = [[self alloc] init];
        [[SKPaymentQueue defaultQueue] addTransactionObserver:sharedStoreHelper];
    }
    return sharedStoreHelper;
}

 

StoreHelper sınıfından programın hayatı boyunca sadece bir kopya olmasını istediğimizden (Singleton obje) bu sınıfa sharedStoreHelper metodu üzerinden erişeceğiz. Bu metod içerisinde ise bir adet StoreHelper objesi oluşturup bunu static bir değişken içerisinde saklayacağız. Kullanıcının satın alma işlemlerini takip edebilmek içinse SKPaymentQueue içerisinde yer alan addTransactionHelper metoduyla izleyici olarak StoreHelper'ı gösteriyoruz. 

 



- (void) requestProductList {
    NSSet *productIdentifiers = [NSSet setWithObjects:kFirstProduct,kSecondProduct,nil];
    SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}

- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    NSArray * skProducts = response.products;
    for (SKProduct * skProduct in skProducts) {
        NSLog(@"Found product: %@ %@ %0.2f",
              skProduct.productIdentifier,
              skProduct.localizedTitle,
              skProduct.price.floatValue);
    }   
    NSDictionary *userInfo = [NSDictionary dictionaryWithObject:skProducts forKey:kProductList];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationKey object:self userInfo:userInfo];
}

- (void) requestDidFinish:(SKRequest *)request {
    
}

-(void) request:(SKRequest *)request didFailWithError:(NSError *)error {
    
}

 

Yeni bir ürün isteği gerçekleştirmek için SKProductsRequest sınıfından faydalanırız. Yukarıdaki örnekte tanımladığımız ürün isimlerinin iTunes Store'dan sorgulanmasını sağlıyoruz. start metodu ile sorgu yapılmadan önce delegate olarak aynı sınıfı belirliyoruz ve iTunes'dan gelen cevap bize productsRequest:didReceiveResponse: metodu içerisinde veriliyor. SKProductsRequest içinde yer alan products adındaki NSArray bize ürünlerimiz listesini döndürüyor ve biz bu listeyi bir NSDictionary içerisine koyup NSNotificationCenter aracılığıyla uygulamadaki dinleyici sınıflara gönderiyoruz. Bu noktadan sonra yapacağımız bir ViewController içerisinde bu NSNotification'ı yakalayarak ürünleri bir tablo içinde göstermek olacak. Herhangi bir sorun olduğunda ise request:didFailWithError: metodu uyarılır ve problemin sebebi error değişkeninde belirtilir.

 




#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize myTableView, productArray;

- (void)viewDidLoad
{
    [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
    
    productArray = [NSMutableArray new];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(receiveNotification:)
                                                 name:kNotificationKey
                                               object:nil];
    
    [[StoreHelper sharedStoreHelper] requestProductList];
}

- (void) receiveNotification:(NSNotification *) notification
{
    NSDictionary* userInfo = notification.userInfo;
    NSLog(@"%@",userInfo);
    if([userInfo objectForKey:kProductList]) {
        [productArray addObjectsFromArray:[userInfo objectForKey:kProductList]];       
        [myTableView reloadData];
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ProductCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    
    cell.textLabel.text = [NSString stringWithFormat:@"%@ %@ TL",[[productArray objectAtIndex:indexPath.row] localizedTitle],[[productArray objectAtIndex:indexPath.row] price]];
    return cell;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [productArray count];
}

 

Yukarıdaki ViewController kodunda bir NSNotification geldiğinde receiveNotification: metodu ayağa kalkar ve bir önceki kodda gönderdiğimiz ürün listesi tablonun içerisine doldurulur. Aşağıdaki ekran görüntüsünde tanımladığımız iki ürün fiyatıyla beraber görüntülenmektedir.

Kullanıcı bir ürüne tıkladığında satın alma işlemini gerçekleştirmek içinse ViewController içerisinde aşağıdaki kodu yazabiliriz;

 

#pragma mark UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [[StoreHelper sharedStoreHelper] purchaseProduct:[productArray objectAtIndex:indexPath.row]];
}

 

purchaseProduct: metodunun kodu ise aşağıdaki şekildedir;

 



- (void) purchaseProduct:(SKProduct *)product {
    
    SKPayment * payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction * transaction in transactions) {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                if (transaction.error.code != SKErrorPaymentCancelled)
                {
                    UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                      message:transaction.error.localizedDescription
                                                                     delegate:nil
                                                            cancelButtonTitle:@"OK"
                                                            otherButtonTitles:nil];
                    [message show];
                }
                
                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            default:
                break;
        }
    };
}

SKProduct sınıfı satın alınan ürünü belirtir. Burada hangi ürünü alacağımız SKPayment sınıfı içinden paymentWithProduct: metodu ile bir ödeme isteğine dönüştürülür. Ödeme istekleri de daha sonra bir sıra (queue) içerisine atılır ve Apple sunucularına gönderilir. Sıraya atma işlemi de SKPaymentQueue sınıfı içindeki statik metodlarla gerçekleştirilir. Sıraya konulan ödeme isteklerinin cevaplarını da paymentQueue:updateTransactions: temsilci metodu içerisinde alırız. Bu metod içerisinde transactionState değişkeni bize ödeminin durumunu bildirir. Eğer ödeme sırasında bir problem oluştuysa SKPaymentTransactionStateFailed bloğu içerisinde sorunun kaynağını kullanıcıya bildiririz. Sorunsuz ödemelerde ise SKPaymentTrasnactionStatePurchased bloğu harekete geçer ve kullanıcının ürüne sahip olduğu bilgisi bize gönderilir. Bu noktada kullanıcının ürünü alması durumunda çalıştıracağımız kodları işleriz.