Hoşgeldin. Soru sormak veya cevaplamak için hemen üye ol.
0 oy
2.0k kez görüntülendi
ios development kategorisinde tarafından
Merhabalar sandbox ortamında oluşturduğum kullanıcı ile test işlemlerini yapıyorum. Satın alma işlemleri gerçekleşiyor. Daha sonra bu satın alma işlemlerini takip edebilmek istiyorum bunları apple portalında nerde güncel olarak takip edebilirim bir ping süresi var mıdır ?

Birde kullanıcıya oyun parası eklemeye çalışıyorum, kullanıcı bir satın alma geçekleştirdiğinde bunu veritabanında filanca kullanıcı 5000 oyun parası diye kaydetmek istiyorum ki, oyun içinde harcama yaptrabiliyim veya kullanıcı oyunu silip tekrar yüklediğinde var olan bir aplle id ile satın almaya çalışıyorsa, ve parası bitmemişse tekrar kullanıcıdan satın almıyım.

Bunları yapabilmek, yani kısaca satın alan kullanıcıyı takip edip loglayabilmek için ne yapmalıyım. Yardımınızı rica ediyorum, herkese şimdiden çok teşekkürler.

1 cevap

+1 oy
tarafından
tarafından seçilmiş
 
En İyi Cevap

kullanıcı satın almayı gerçekleştirdikten sonra itunes verifyReceipt sunucusuna bağlanarak gerçekleşen transaction'u alabilir ve kendi veritabanınızda bu işlemle ilgili bir kayıt tutabilirsiniz.
sandbox'da: https://sandbox.itunes.apple.com/verifyReceipt
production'da: https://buy.itunes.apple.com/verifyReceipt
sunucu adreslerini kullanıyoruz.
puschase işlemini kontrol ettiğimiz delegate metodu olan
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!)
içerisinde SKPaymentTransactionState.Purchased veya SKPaymentTransactionState.Restored olarak gerçekleştiğinde bu validate işlemini yapmalıyız.

kendi yazdığım ReceiptValidation class'ını aşağıda paylaşıyorum

class ReceiptValidation:NSObject {

    private class func getReceiptInJsonFormat() -> NSData! {
        var jsonData:NSData! = nil
        if let receiptURL:NSURL = NSBundle.mainBundle().appStoreReceiptURL {
            if let receipt:NSData = NSData(contentsOfURL: receiptURL) {
                let encodedReceipt:NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
                let jsonStructure:NSDictionary = ["receipt-data":encodedReceipt]
                jsonData = NSJSONSerialization.dataWithJSONObject(jsonStructure, options: NSJSONWritingOptions.allZeros, error: nil)!
            }
        }
        return jsonData
    }

    class func validateReceipt(completionHandler:(data: NSDictionary!) -> Void) {
        if let receiptValidationData:NSData = getReceiptInJsonFormat() {
            let baseURL:NSURL = NSURL(string:"https://sandbox.itunes.apple.com/verifyReceipt")!
//            let baseURL:NSURL = NSURL(string:"https://buy.itunes.apple.com/verifyReceipt")! // ********* change receipt validation address when app in production *********************
            let request:NSMutableURLRequest = NSMutableURLRequest(URL: baseURL)
            request.HTTPMethod = "POST"
            request.HTTPBody = receiptValidationData
            let operation:AFHTTPRequestOperation = AFHTTPRequestOperation(request: request)
            operation.responseSerializer = AFHTTPResponseSerializer() as AFHTTPResponseSerializer
            operation.setCompletionBlockWithSuccess({ (operation:AFHTTPRequestOperation!, data:AnyObject!) -> Void in
                let convertedData:NSData = data as! NSData
                var receivedData:NSDictionary = NSJSONSerialization.JSONObjectWithData(convertedData, options: NSJSONReadingOptions.MutableLeaves, error: nil) as! NSDictionary
                completionHandler(data: receivedData)
                }, failure: { (operation:AFHTTPRequestOperation!, error:NSError!) -> Void in
                    completionHandler(data: nil)
            })
            operation.start()
        }
    }

} 

aşağıdaki örnekte'de func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) içerisinde bu class'ın nasıl handle edildiğini görebilirsiniz.

func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
        for transaction in transactions as! [SKPaymentTransaction] {
            switch transaction.transactionState {
            case SKPaymentTransactionState.Purchased:
                println("purchase complete")
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
                purchased(false)
                break
            case SKPaymentTransactionState.Failed:
                println("purchase failed with error:\(transaction.error.localizedDescription)")
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
                break
            case SKPaymentTransactionState.Restored:
                println("restore complete")
                SKPaymentQueue.defaultQueue().finishTransaction(transaction)
                purchased(true)
                break
            case SKPaymentTransactionState.Purchasing:
                println("purchasing in progress")
                break
            default:
                break
            }
        }
    }



    func purchased(isRestored:Bool) {
        println("purchase validation has started")

        ReceiptValidation.validateReceipt { (data) -> Void in
            if data != nil {
                if let status:Int = data["status"] as? Int {
                    if status == 0 {
                        let receiptString:String = String(format: "%@", data) //aldığımız validation string'i. Bunu sunucumuza gönderebiliriz.

                        if isRestored {
                            println("restore action validated")
                        } else {
                            println("purchase action validated")
                        }
                    } else {
                        println("purchase validation error:\(status)")
                    }
                } else {
                    println("purchase validation error")
                }
            } else {
                println("purchase validation error")
            }
        }
    }
tarafından
Anladım. Yardımınız için çok teşekkür ederim.  Hemen test etmeye başlıyorum. Tekrar teşekkürler.
tarafından
+1
rica ederim.
cevabıma en son yaptığım eklemeyi de inceleyebilir,
ReceiptValidation class'ını nasıl kullanmanız gerektiğini de görebilirsiniz.
kolay gelsin. :)
tarafından
düzeltmeniz için çok teşekkürler, ufak bir şey daha sormak istiyorum benim öğrenmiş olduğum örnekte restore işlemi

paymentQueueRestoreCompletedTransactionsFinished{ }

fonksyonu içinde yakalanıp değerlendirilmiş, sizin örneğinizde ise

SKPaymentTransactionState.Restored gibi bir case bloğu içinde benim yaptığım şekilde paymentQueueRestoreCompletedTransactionsFinished fonksıyonu içinde yakalamam yanlış mıdır ? Birde ben restore işlemini daha önce satın alınan bir ürünün tekrar satınalınma işleminin tamamlnaması ihtimali olarak değerlendirdim, doğrumudur ?
tarafından
+1
paymentQueueRestoreCompletedTransactionsFinished kullanılabilir tabi ama sadece o an gerçekleşen restore işlemine ait transaction'ı alırsınız.
updatedTransactions ile uygulamaya ait gerçekleşmiş ve güncellenmiş tüm transaction'ları alabilirsiniz.
dikkat ederseniz verdiğim örnekte updatedTransactions metodu içerisinde, bir den fazla transaction olabilmesi ihtimaline karşın bir for döngüsü kullanıyoruz.
hangisini kullanmak istediğiniz size kalmış tabi. :)
tarafından
anladım, tekrardan çok teşekkürler.
tarafından
Yasin Bey Selam,

Birşey daha sorup biraz daha vaktinizi alacağım :)

Bu işlem sonucunda, Success nesnesini altından uniqe olarak transaction_id yi görüyorum, bunun dışında kullanıcın itunes hesabını temsil eden bir değer var mı, veritabanına kullanıcı bu ürünü almış diye kaydedebilmek için kullanıcağım. Zira kulanıcıların uygulma içinde kendine özel bir hesaplar onları tanımlayabilceğim bir idleri yok.  Bildiğim kadarıyla device id de her uygulama yüklendiğinde değişiyor.

Bende kullancının itunes hesap aıdnı veya bunu temsil eden uniqe bir değeri alabilirsem bunlar ürünlerini ilişkilendirip veri tabanında tutarım diye düşünmüştüm.

transaction_id değilde bunu yapan kullanıcıyı temsil edebilecek bir değer var mı ?

Eğer saçmalıyorsamda affedin, çalışma mantığını anlamaya çalışıyorum :D
tarafından
tarafından yeniden gösterildi
+1
ios6 ya kadar device unique Id'si obtain edilebiliyordu. Fakat apple kullanıcı gizliliğini öne sürerek cihaza özel tüm tespit edilebilir unique tanımlayıcıları gizledi. Buna cihaz network interface’lerinin mac adresleri dahil.
Bu nedenle uygulamayı indiren kullanıcıları (daha doğrusu cihazları) şaşmaz bir doğrulukla takip etmek artık güç. ama yinede bir yol var.
bu yol da, uygulama cihaza ilk defa kurulduğunda örneğin NSUUID().UUIDString’yi kullanarak veya hash algoritmalarıyla unique id’ler oluşturmak ve bunları cihaza kaydetmek.
tabi NSUserDafults’a kaydetmek, uygulama silinir ve tekrar yüklenirse bu id’lerin her seferinde yeniden oluşturulacağı anlamına geldiği için bu id’leri keychain’e kaydetmek şu an kullanabileceğiniz tek etkili çözüm.
keycahin’e kaydettiğiniz uniqueId, kullanıcı uygulamayı silip tekrar yüklese dahi aynı kalır. yani Keycahin dataları uygulama cihazdan kaldırılsa bile silinmezler. Sadece cihaz kullanıcı tarafından resetlendiği zaman silineceklerdir ki, bu da oldukça makul bir handikap.
tarafından
Apple daki, amcaların böyle birşey isteyebileceğini tahmin edebiliyordum, ama belki satın alma bilgilerinde bir e posta donerler diye beklemiştim. Şansızlık.

Keychain, kaydetmek hakkında hiçbir fikrim yok. Nasıl kaydedildiğiğini tarif edebilir misniz  ?
tarafından
+1
ben sorununuzu en başından beri yapılan satın alma işleminin doğruluğunu kontrol edebileceğiniz bir yöntem arıyormuşsunuz gibi algıladığım için boşu boşuna gereksiz detaylarla kafanızı karıştırdım sanırım. Pardon. :)
dediğim gibi keychain’e kendi ürettiğiniz uniquId’leri kaydetmek en iyi yöntem. Data’larınızı keychain’e kaydetmek için kendinizde özel class yazabilirsiniz elbet ama buna hiç gerek yok, çünkü keychain kullanımına ilişkin hazırlanmış bir sürü hazır class var. git’de aratarak ulaşabilirsiniz.

keyclip’i önerebilirim.
https://github.com/s-aska/KeyClip

şöyle kullanabilirsiniz mesela;


var myCurrentAppId:String = “"
if KeyClip.exists(“myAppID") {

            if let myAppId:String = KeyClip.load("myAppID") {

                myCurrentAppId = myAppId

            }

        } else {

            myCurrentAppId = NSUUID().UUIDString

            KeyClip.save("myAppID", string: myCurrentAppId, failure: { (error) -> Void in

                println("keyChainUniqueAppIDCreationError:\(error.localizedDescription)")

            })

        }
tarafından
Benim için diğerini öğrenmekte, çok iyi oldu. Yardımlarınız için çok teşekkürler.
...