Oyun İçi satın alımlar

Kullanıcıların oyun içi satın alma yapmasına izin vererek gelir elde edebilirsiniz. Örneğin, bir seviyeyi tamamlamak için ekstra süre veya oyun karakteri için aksesuarlar. Bunun için:

Dikkat

Satın alımları, tüketimlerini bağladıktan sonra test edebilirsiniz. Aksi takdirde işlenmemiş ödemeler ortaya çıkabilir, bu da moderasyon sürecini geçilmesini imkansız kılabilir.

Bağlantı şartları

Satın alma eklendikten ve taslak oyunu yayınladıktan sonra games-partners@yandex-team.ru adresine satın almanın etkinleştirilmesini talep eden bir e-posta gönderin. E-postanıza oyunun adını ve tanımlayıcısını (ID) eklediğinizden emin olun.

games-partners@yandex-team.ru adresinden satın alma işlemlerine izin verildiğini onaylayan bir yanıt geldikten sonra gerekli ayarları ve testleri yapabilirsiniz.

Başlatma

Oyuncuların uygulama içi satın alımlar yapabilmesi için payments nesnesini kullanabilirsiniz. İki seçeneğiniz var:

  • Doğrudan ysdk.payments üzerinden erişim. Satın alma işlemleri, nesnenin herhangi bir metoduna ilk çağrı yapıldığında başlatılır, bu nedenle ilk çağrı biraz daha yavaş olabilir.

  • ysdk.getPayments() metodu ile nesneyi başlatın. Bu yöntem, payments metodları için gerekli verileri önceden yükler. Böylece ilk çağrıda gecikme yaşanmaz.

Dikkat

YaGames.init() ve ysdk.getPayments() fonksiyonlarına, isteğe bağlı signed: boolean parametresi geçirilebilir. Bu parametre sahtekarlığa karşı koruma için kullanılır. Değer seçimi, ödemelerin nerede işlendiğine bağlıdır:

  • İstemci tarafında işleniyorsa — metotları parametresiz çağırın veya signed: false geçirin. Satın alma metodları verileri açık şekilde döndürür.

  • Sunucu tarafında işleniyorsa — signed: true geçirin. Bu durumda payments.getPurchases() ve payments.purchase() metodlarının yanıtlarında tüm veriler yalnızca şifrelenmiş şekilde _signature parametresinde döndürülür.

Varsayılan parametre ile başlatma (signed: false).

Yöntem 1: Basit Kullanım

YaGames.init() // Veya YaGames.init({ signed: false }).
    .then(ysdk => {
        // Satın alma metodlarına ysdk.payments üzerinden erişilebilir.
        console.log(ysdk.payments);
    }).catch(err => {
        // Satın alımlar kullanılamıyor.
    });

Yöntem 2: getPayments() ile ön yükleme

var payments = null;
YaGames.init()
    .then(ysdk => {
        ysdk.getPayments()
            .then(_payments => {
                // Satın alma metodlarına payments üzerinden erişilebilir.
                payments = _payments;
                console.log(payments);
            }).catch(err => {
                // Satın alımlar kullanılamıyor.
            });
    });

signed: true parametresi ile başlatma.

Yöntem 1: SDK başlatılırken

YaGames.init({ signed: true }) // Satın alımlar için imza desteğini etkinleştirir.
    .then(ysdk => {
        // Satın alma metodlarına ysdk.payments üzerinden erişilebilir.
        console.log(ysdk.payments);
    }).catch(err => {
        // Satın alımlar kullanılamıyor.
    });

Yöntem 2: getPayments() ile detaylı yapılandırma

var payments = null;
YaGames.init()
    .then(ysdk => {
        ysdk.getPayments({ signed: true })
            .then(_payments => {
                // Satın alma metodlarına payments üzerinden erişilebilir.
                payments = _payments;
                console.log(payments);
            }).catch(err => {
                // Satın alımlar kullanılamıyor.
            });
    });

 

Satın alma sürecinin etkinleştirilmesi

Oyun içi satın almayı etkinleştirmek için, payments.purchase({ id, developerPayload }) metodunu kullanın.

  • id: string – geliştirici konsolunda belirlenmiş olan ürün ID'si.
  • developerPayload: string – isteğe bağlı parametre. Satın alma hakkında sunucunuza iletmek istediğiniz ek bilgiler (signature parametresinde iletilecektir).

Metot, ödeme ağ geçidini içeren bir çerçeve açar.

Varsayılan parametre ile Başlatma (signed: false).

Promise<Purchase> döner.

Purchase: object — satın alma bilgileri. Aşağıdaki özellikleri içerir:

  • productID: string — ürün ID'si.
  • purchaseToken: string — satın alma kullanımı için token.
  • developerPayload: string — satın alma hakkında ek veriler.

Başlatma parametre ile signed: true.

Promise<{ signature }> döner.

signature: string — oyuncunun kimliğini doğrulamak için satın alma verileri ve imzası şifrelenmiştir.

Oyuncu başarılı bir şekilde satın alma işlemini gerçekleştirdikten sonra, Promise "resolved" durumuna geçer. Oyuncu satın alma işlemi yapmamış ve pencereyi kapatmışsa, Promise "rejected" durumuna geçer.

Dikkat

İnternet bağlantısı kötüyse, oyuncunun bir satın alma işlemi yaptığı ancak bunun oyunda görüntülenemediği durumlar olabilir. Bunu önlemek için, satın alımları işlemek üzere İşlenmemiş satın almaları kontrol etme ve Satın almaları ve oyun içi para birimini işleme bölümlerinde açıklanan yöntemleri kullanın.

Bu talimatlara uyulmaması, uygulama içinde oyun içi satın almaların devre dışı bırakılmasına veya uygulamanın yayından kaldırılmasına neden olabilir.

Kullanıcı, oturum açmadan satın alma işlemi yapabilir, ancak kendisine önceden veya satın alma işlemi sırasında hesabına giriş yapmasını teklif etmenizi öneririz.

Örnek

Genel olarak:

payments.purchase({ id: 'gold500' })
    .then(purchase => {
        // Satın alma işlemi başarıyla tamamlandı!
    }).catch(err => {
        // Satın alma başarısız oldu: Bu id'ye sahip ürün, geliştirici konsoluna eklenmemiş
        // kullanıcı giriş yapmadı, fikrini değiştirdi ve ödeme penceresini kapattı,
        // satın alma için ayrılan süre doldu, yeterli para yok, vb.
    });

developerPayload isteğe bağlı parametresini kullanarak:

payments.purchase({ id: 'gold500', developerPayload: '{serverId:42}' })
    .then(purchase => {
        // purchase.developerPayload === '{serverId:42}'
    });

Satın alınan ürünlerin listesini alma

payments.getPurchases() metodunu kullanarak:

  • oyuncunun daha önce hangi alışverişleri yaptığını öğrenin;

  • işlenmemiş alışverişlerin varlığını kontrol edin;

  • sürekli alışverişleri işleyin.

Varsayılan parametre ile Başlatma (signed: false).

Promise<Purchase[]> döner.

Purchase[]: array — oyuncu tarafından yapılan satın almaların listesi. Listenin şu özelliği var:

  • productID: string — ürün ID'si.
  • purchaseToken: string — satın alma kullanımı için token.
  • developerPayload: string — satın alma hakkında ek veriler.

Örnek

var SHOW_ADS = true;
payments.getPurchases()
    .then(purchases => {
        if (purchases.some(purchase => purchase.productID === 'disable_ads')) {
          SHOW_ADS = false;
        }
    }).catch(err => {
        // Giriş yapmamış kullanıcılar için USER_NOT_AUTHORIZED istisnası gösteriliyor.
    });

Başlatma parametre ile signed: true.

Promise<{ signature }> döner.

signature: string — oyuncunun kimliğini doğrulamak için satın alma verileri ve imzası şifrelenmiştir.

Örnek

payments.getPurchases()
  .then(purchases => {
      fetch('https://your.game.server?purchase', {
          method: 'POST',
          headers: { 'Content-Type': 'text/plain' },
          body: purchases.signature
      });
  });

 

Tüm ürünlerin kataloğunu alma

Mevcut satın almaların ve fiyatlarının bir listesini almak için payments.getCatalog() yöntemini kullanın.

Metot Promise<Product[]> döndürür.

Product[]: array — kullanıcının kullanabileceği ürünlerin listesi. Geliştirici konsolunun In-app purchases sekmesindeki tablodan oluşturulmuştur. Her Product şu özellikleri içerir:

  • id: string — ürün tanımlayıcısı.
  • title: string – ad.
  • description: string – açıklama.
  • imageURI: string — görüntünün URL'si.
  • price: string — ürünün <price> <currency code> biçimindeki fiyatı.
  • priceValue: string — ürünün <price> biçimindeki maliyeti.
  • priceCurrencyCode: string — para birimi kodu.

Product.getPriceCurrencyImage(size) — Para birimi ikonunun adresini almak için kullanılan yöntem.

  • size: string — isteğe bağlı parametre. Olası değerler:

    • small (varsayılan) — küçük bir simge alınır.

    • medium — orta boyutlu bir ikon alınması.

    • svg — vektör ikon alınması.

Metot string döndürür — ikon adresi, örneğin //yastatic.net/s3/games-static/static-data/images/payments/sdk/currency-icon-s@2x.png.

Örnek

var gameShop = []
payments.getCatalog()
    .then(products => {
        gameShop = products;
    });

Portal Para Birimi Gösterimi

Oyun içinde portal para biriminin ismini ve ikonunu göstermek için SDK'nın imkanlarından faydalanın:

  • Product.price: string — para birimi kodu ile birlikte fiyat.
  • Product.priceCurrencyCode: string — para birimi kodu.
  • Product.getPriceCurrencyImage() string döndürür — para birimi ikonunun adresi.

Product objesi hakkında daha fazla bilgi için Tüm Ürünlerin Katalogunu Alma bölümüne bakın.

Satın almaların işlenmesi ve oyun içi para biriminin hesaba yüklenmesi

İki tür satın alma vardır, kalıcı (reklamları devre dışı bırakma gibi) ve kullanılan (oyun içi para birimi gibi).

Kalıcı satın almaları işlemek için payments.getPurchases() yöntemini uygulayın.

Kullanılan satın almaları işlemek için payments.consumePurchase() yöntemini uygulayın.

payments.consumePurchase()

Yöntem, işlem başarılı olduysa Promise öğesini "resolved" durumunda veya hata oluştuysa "rejected" durumunda döndürür.

Dikkat

Payments.consumePurchase() yöntemi çağrıldıktan sonra, işlenen satın alma işlemi hiçbir kurtarma olasılığı olmadan silinir. Bu nedenle önce oyuncu verilerini player.setStats() veya player.incrementStats() yöntemleriyle değiştirin ve ardından satın alma işlemini gerçekleştirin.

Örnek

payments.purchase({ id: 'gold500' })
    .then(purchase => {
        // Satın alma işlemi başarıyla tamamlandı!
        // Bakiyeye 500 altın yüklüyoruz ve satın alma işlemini kullanıyoruz.
        addGold(500).then(() => payments.consumePurchase(purchase.purchaseToken));
    });

function addGold(value) {
    return player.incrementStats({ gold: value });
    // Daha fazla ayrıntı için Oyuncu verileri bölümüne bakın.
}

purchaseToken: stringpayments.purchase() ve payments.getPurchases() yöntemleriyle döndürülen token.

İşlenmemiş satın almaların doğrulanması

Oyun içi satın alma işlemi sırasında kullanıcının internet bağlantısı kesilirse veya sunucunuz kullanılamazsa, satın alma işlemi gerçekleştirilemeyebilir. Bu durumdan kaçınmak için, örneğin oyunu her çalıştırdığınızda payments.getPurchases() yöntemini kullanarak işlenmemiş satın almaları kontrol edin.

Dikkat

Satın alımları ekleyebilmeniz için, lütfen işlenmemiş ödemeleri kontrol etme ayarını yapın.

Bu kontrol, moderasyon sürecinden geçebilmek için zorunludur, bu yüzden test satın alımları için bile onu ayarlamak önemlidir. Eğer oyuna satın alımlar eklenir ve tüketim ayarları yapılmadan test edilirse, testler sonrasında işlenmemiş ödemeler kalabilir ve bu da moderasyon sürecinden geçilmesini imkansız hale getirebilir.

Varsayılan parametre ile Başlatma (signed: false).

Örnek

payments.getPurchases().then(purchases => purchases.forEach(consumePurchase));

function consumePurchase(purchase) {
    if (purchase.productID === 'gold500') {
        player.incrementStats({ gold: 500 })
            .then(() => {
                payments.consumePurchase(purchase.purchaseToken)
            });
    }
}

Başlatma parametre ile signed: true.

Örnek

payments.getPurchases()
    .then(purchases => {
        fetch('https://your.game.server?purchase', {
            method: 'POST',
            headers: { 'Content-Type': 'text/plain' },
            body: purchases.signature
        });
    });

 

Hileye karşı koruma

Oyun içinde olası hileli istatistik artışlarından korunmak için, satın alımları sunucu tarafında işleyin:

  1. YaGames.init() veya ysdk.getPayments() fonksiyonlarını { signed: true } parametresi ile başlatın.
  2. payments.purchase() ve payments.getPurchases() yanıtlarında alınan imzayı kendi sunucunuza gönderin ve gizli anahtarınızı kullanarak bu imzayı deşifre edin.
  3. Kendi sunucunuzda, oyuncuya oyun içinde kazandığı eşyaları tahsis edin.
// Satın almaların { signed: true } parametresiyle başlatıldığından emin olun

payments.purchase({ id: 'gold500' })
    .then(purchase => {
        // Satın alma başarıyla tamamlandı!
        // Sunucuda 500 altını hesaba yüklüyoruz...
        serverPurchase(purchase.signature); // Oyuncuya verileri doğrulayıp tanımlıyoruz.
    });

function serverPurchase(signature) {
    return fetch('https://your.game.server?purchase', {
            method: 'POST',
            headers: { 'Content-Type': 'text/plain' },
            body: signature
        });
}

Sunucuya iletilen signature parametresi satın alma verilerini ve imzayı içerir. base64: <imza>.<satın alma verileriyle JSON> kodlamasında iki dizeyi temsil eder.

Signature örneği

hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0=

Satın alma ile ilgili iletilen veriler örneği (JSONbiçiminde)

serverPurchase(signature) işlevindeki signature parametresi veri formatının payments.getPurchases() yönteminde kullanılandan farklı olduğunu unutmayın.

payments.getPurchases() yönteminde, signature parametresi data alanında bir dizi satın alma nesnesi içerir. serverPurchase(signature) işlevinde satın alma nesnesidir.

{
  "algorithm": "HMAC-SHA256",
  "issuedAt": 1571233371,
  "requestPayload": "qwe",
  "data": {
    "token": "d85ae0b1-9166-4fbb-bb38-6d2a4ca4416d",
    "status": "waiting",
    "errorCode": "",
    "errorDescription": "",
    "url": "https://yandex.ru/games/sdk/payments/trust-fake.html",
    "product": {
      "id": "noads",
      "title": "Reklam yok",
      "description": "Oyunda reklamı devre dışı bırak",
      "price": {
        "code": "YAN",
        "value": "49"
      },
      "imagePrefix": "https://avatars.mds.yandex.net/get-games/1892995/2a0000016d1c1717bd7a0149ccadc86078a1/"
    },
    "developerPayload": "TEST DEVELOPER PAYLOAD"
  }
}

Gizli anahtar örneği

t0p$ecret

İmza doğrulama için gizli anahtar oyuna özgüdür. Geliştirici konsolunda satın almalar oluşturulurken, bu da otomatik olarak oluşturulur. Satın alma tablosu altında yayınlanmıştır.

Sunucuda imza doğrulama örneği

import hashlib
import hmac
import base64
import json

usedTokens = {}

key = 't0p$ecret' # Anahtarı gizli tutun.
secret = bytes(key, 'utf-8')
signature = 'hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0='

sign, data = signature.split('.')
message = base64.b64decode(data)

purchaseData = json.loads(message)
result = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
if result.decode('utf-8') == sign:
  print('Signature check ok!')

  if not purchaseData['data']['token'] in usedTokens:
    usedTokens[purchaseData['data']['token']] = True; # Veritabanını kullanın.
    print('Double spend check ok!')

    print('Apply purchase:', purchaseData['data']['product'])
    # Burada satın aldıklarınızı güvenle hesaba geçirebilirsiniz.
const crypto = require('crypto');

const usedTokens = {};

const key = 't0p$ecret'; // Anahtarı gizli tutun.
const signature = 'hQ8adIRJWD29Nep+0P36Z6edI5uzj6F3tddz6Dqgclk=.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZEF0IjoxNTcxMjMzMzcxLCJyZXF1ZXN0UGF5bG9hZCI6InF3ZSIsImRhdGEiOnsidG9rZW4iOiJkODVhZTBiMS05MTY2LTRmYmItYmIzOC02ZDJhNGNhNDQxNmQiLCJzdGF0dXMiOiJ3YWl0aW5nIiwiZXJyb3JDb2RlIjoiIiwiZXJyb3JEZXNjcmlwdGlvbiI6IiIsInVybCI6Imh0dHBzOi8veWFuZGV4LnJ1L2dhbWVzL3Nkay9wYXltZW50cy90cnVzdC1mYWtlLmh0bWwiLCJwcm9kdWN0Ijp7ImlkIjoibm9hZHMiLCJ0aXRsZSI6ItCR0LXQtyDRgNC10LrQu9Cw0LzRiyIsImRlc2NyaXB0aW9uIjoi0J7RgtC60LvRjtGH0LjRgtGMINGA0LXQutC70LDQvNGDINCyINC40LPRgNC1IiwicHJpY2UiOnsiY29kZSI6IlJVUiIsInZhbHVlIjoiNDkifSwiaW1hZ2VQcmVmaXgiOiJodHRwczovL2F2YXRhcnMubWRzLnlhbmRleC5uZXQvZ2V0LWdhbWVzLzE4OTI5OTUvMmEwMDAwMDE2ZDFjMTcxN2JkN2EwMTQ5Y2NhZGM4NjA3OGExLyJ9fX0=';

const [sign, data] = signature.split('.');
const purchaseDataString = Buffer.from(data, 'base64').toString('utf8');
const hmac = crypto.createHmac('sha256', key);

hmac.update(purchaseDataString);

const purchaseData = JSON.parse(purchaseDataString);

if (sign === hmac.digest('base64')) {
  console.log('Signature check ok!');

  if (!usedTokens[purchaseData.data.token]) {
    usedTokens[purchaseData.data.token] = true; // Veri tabanını kullanın.
    console.log('Double spend check ok!');

    console.log('Apply purchase:', purchaseData.data.product);
    // Burada satın aldıklarınızı güvenle hesaba geçirebilirsiniz.
  }
}

Not

Destek ekibi, hazır oyunu Yandex Oyun platformuna yerleştirmenize yardımcı olur. Geliştirme ve test etme konularındaki uygulamalı sorulara ise diğer geliştiriciler Discord Topluluğu yanıt verir.

Yandex Games SDK kullanırken sorunla karşılaşırsanız veya sorunuz varsa, lütfen destek ekibiyle iletişime geçin:

Sohbete yaz

id: string — geliştirici konsolunda belirlenmiş ürün ID'si.

developerPayload: string — isteğe bağlı parametre. Satın alma hakkında sunucunuza iletmek istediğiniz ek bilgiler (signature parametresinde iletilecektir).

Sunucuya gönderilen isteğin signature parametresi satın alma verilerini ve imzayı içerir. base64: <imza>.<satın alma verileriyle JSON> kodlamasında iki dizeyi temsil eder.

purchaseToken: string — payments.purchase() ve payments.getPurchases() yöntemleriyle döndürülen token.

Eğer satın alımları ysdk.getPayments() ile başlatmadıysanız, doğrudan ysdk.payments kullanabilirsiniz.