Bu kılavuzda, Google Play Games Hizmetleri tarafından sağlanan anlık görüntüler API'si kullanılarak kaydedilmiş oyunların nasıl uygulanacağı gösterilmektedir. API'leri
com.google.android.gms.games.snapshot
ve
com.google.android.gms.games
paketlerinde bulabilirsiniz.
Başlamadan önce
Özellik hakkında bilgi edinmek için Kaydedilmiş Oyunlara genel bakış başlıklı makaleyi inceleyin.
- Google Play Console'da oyununuz için kaydedilmiş oyunlar desteğini etkinleştirin.
- Android örnekleri sayfasındaki kayıtlı oyunlar kodu örneğini indirip inceleyin.
- Kalite Kontrol Listesi'nde açıklanan öneriler hakkında bilgi edinin.
Anlık görüntüler istemcisini edinme
Anlık görüntüler API'sini kullanmaya başlamak için oyununuzun önce bir
SnapshotsClient
nesnesi alması gerekir. Bunu, Games.getSnapshotsContents()
yöntemini çağırıp etkinliği ileterek yapabilirsiniz.
Kayıtlı oyunları görüntüleme
Anlık görüntüler API'sini, oyununuzda oyunculara ilerlemelerini kaydetme veya geri yükleme seçeneği sunulan her yere entegre edebilirsiniz. Oyununuz, bu seçeneği belirlenen kaydetme veya geri yükleme noktalarında gösterebilir ya da oyuncuların ilerlemeyi istedikleri zaman kaydetmelerine veya geri yüklemelerine izin verebilir.
Oyuncular oyununuzda kaydetme veya geri yükleme seçeneğini belirlediğinde oyununuz, oyuncuları yeni bir kayıtlı oyun için bilgi girmeye ya da geri yüklemek üzere mevcut bir kayıtlı oyunu seçmeye yönlendiren bir ekran gösterebilir.
Geliştirme sürecinizi basitleştirmek için anlık görüntüler API'si, kullanıma hazır olarak kullanabileceğiniz varsayılan bir kayıtlı oyun seçimi kullanıcı arayüzü (UI) sağlar. Kayıtlı oyunlar seçim kullanıcı arayüzü, oyuncuların yeni bir kayıtlı oyun oluşturmasına, mevcut kayıtlı oyunlarla ilgili ayrıntıları görüntülemesine ve önceki kayıtlı oyunları yüklemesine olanak tanır.
Varsayılan Kaydedilmiş Oyunlar kullanıcı arayüzünü başlatmak için:
- Varsayılan kayıtlı oyun seçimi kullanıcı arayüzünü başlatmak için
SnapshotsClient.getSelectSnapshotIntent()
çağrısı yapın.Intent
startActivityForResult()
numaralı telefonu arayınIntent
. Çağrı başarılı olursa oyun, belirtmiş olduğunuz seçeneklerle birlikte kayıtlı oyun seçimi kullanıcı arayüzünü gösterir.
Varsayılan kayıtlı oyun seçimi kullanıcı arayüzünü başlatma örneğini aşağıda görebilirsiniz:
private static final int RC_SAVED_GAMES = 9009; private void showSavedGamesUI() { SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(this); int maxNumberOfSavedGamesToShow = 5; Task<Intent> intentTask = snapshotsClient.getSelectSnapshotIntent( "See My Saves", true, true, maxNumberOfSavedGamesToShow); intentTask.addOnSuccessListener(new OnSuccessListener<Intent>() { @Override public void onSuccess(Intent intent) { startActivityForResult(intent, RC_SAVED_GAMES); } }); }
Oyuncu yeni bir kayıtlı oyun oluşturmayı veya mevcut bir kayıtlı oyunu yüklemeyi seçerse kullanıcı arayüzü, Play Games Hizmetleri'ne bir istek gönderir. İstek başarılı olursa Play Games Hizmetleri, onActivityResult()
geri çağırma işlevi aracılığıyla kayıtlı oyunu oluşturmak veya geri yüklemek için bilgileri döndürür. Oyununuz, istek sırasında hata oluşup oluşmadığını kontrol etmek için bu geri çağırmayı geçersiz kılabilir.
Aşağıdaki kod snippet'inde onActivityResult()
için örnek bir uygulama gösterilmektedir:
private String mCurrentSaveName = "snapshotTemp"; /** * This callback will be triggered after you call startActivityForResult from the * showSavedGamesUI method. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (intent != null) { if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) { // Load a snapshot. SnapshotMetadata snapshotMetadata = intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA); mCurrentSaveName = snapshotMetadata.getUniqueName(); // Load the game data from the Snapshot // ... } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) { // Create a new snapshot named with a unique string String unique = new BigInteger(281, new Random()).toString(13); mCurrentSaveName = "snapshotTemp-" + unique; // Create the new snapshot // ... } } }
Kayıtlı oyunları yazma
İçeriği kayıtlı oyuna depolamak için:
SnapshotsClient.open()
kullanarak bir anlık görüntüyü eşzamansız olarak açın.SnapshotsClient.DataOrConflict.getData()
işlevini çağırarak görevin sonucundanSnapshot
nesnesini alın.SnapshotContents
örneğiniSnapshotsClient.SnapshotConflict
ile alma.Oyuncunun verilerini bayt biçiminde depolamak için Call
SnapshotContents.writeBytes()
kullanılır.Tüm değişiklikleriniz yazıldıktan sonra
SnapshotsClient.commitAndClose()
işlevini çağırarak değişikliklerinizi Google'ın sunucularına gönderin. Oyununuz, yöntem çağrısında isteğe bağlı olarak Play Games Hizmetleri'ne bu kayıtlı oyunun oyunculara nasıl sunulacağını bildirmek için ek bilgiler sağlayabilir. Bu bilgiler, oyununuzunSnapshotMetadataChange.Builder
kullanarak oluşturduğu birSnapshotMetaDataChange
nesnesinde gösterilir.
Aşağıdaki snippet, oyununuzun kayıtlı bir oyunda değişiklikleri nasıl işleyebileceğini gösterir:
private Task<SnapshotMetadata> writeSnapshot(Snapshot snapshot, byte[] data, Bitmap coverImage, String desc) { // Set the data payload for the snapshot snapshot.getSnapshotContents().writeBytes(data); // Create the change operation SnapshotMetadataChange metadataChange = new SnapshotMetadataChange.Builder() .setCoverImage(coverImage) .setDescription(desc) .build(); SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(this); // Commit the operation return snapshotsClient.commitAndClose(snapshot, metadataChange); }
Uygulamanız SnapshotsClient.commitAndClose()
işlevini çağırdığında oyuncunun cihazı bir ağa bağlı değilse Play Games Hizmetleri, kayıtlı oyun verilerini cihazda yerel olarak saklar. Cihaz yeniden bağlandığında Play Games Hizmetleri, yerel olarak önbelleğe alınan kayıtlı oyun değişikliklerini Google'ın sunucularıyla senkronize eder.
Kayıtlı oyunları yükleme
Şu anda oturum açmış oyuncu için kayıtlı oyunları almak üzere:
SnapshotsClient.open()
ile bir anlık görüntüyü eşzamansız olarak açın.Snapshot
nesnesini,SnapshotsClient.DataOrConflict.getData()
işlevini çağırarak görevin sonucundan alın. Alternatif olarak, oyununuz Kayıtlı oyunları görüntüleme bölümünde açıklandığı gibi kayıtlı oyun seçimi kullanıcı arayüzü aracılığıyla da belirli bir anlık görüntüyü alabilir.SnapshotContents
örneğiniSnapshotsClient.SnapshotConflict
ile alın.Anlık görüntünün içeriğini okumak için
SnapshotContents.readFully()
işlevini çağırın.
Aşağıdaki snippet'te, belirli bir kayıtlı oyunun nasıl yüklenebileceği gösterilmektedir:
Task<byte[]> loadSnapshot() { // Display a progress dialog // ... // Get the SnapshotsClient from the signed in account. SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(this); // In the case of a conflict, the most recently modified version of this snapshot will be used. int conflictResolutionPolicy = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED; // Open the saved game using its name. return snapshotsClient.open(mCurrentSaveName, true, conflictResolutionPolicy) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "Error while opening Snapshot.", e); } }).continueWith(new Continuation<SnapshotsClient.DataOrConflict<Snapshot>, byte[]>() { @Override public byte[] then(@NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception { Snapshot snapshot = task.getResult().getData(); // Opening the snapshot was a success and any conflicts have been resolved. try { // Extract the raw data from the snapshot. return snapshot.getSnapshotContents().readFully(); } catch (IOException e) { Log.e(TAG, "Error while reading Snapshot.", e); } return null; } }).addOnCompleteListener(new OnCompleteListener<byte[]>() { @Override public void onComplete(@NonNull Task<byte[]> task) { // Dismiss progress dialog and reflect the changes in the UI when complete. // ... } }); }
Kayıtlı oyun çakışmalarını yönetme
Oyununuzda anlık görüntüler API'sini kullanırken birden fazla cihazın aynı kayıtlı oyunda okuma ve yazma işlemleri yapması mümkündür. Bir cihazın ağ bağlantısı geçici olarak kesilip daha sonra yeniden bağlanması durumunda, oyuncunun yerel cihazında depolanan kayıtlı oyunun Google'ın sunucularında depolanan uzak sürümle senkronize olmaması nedeniyle veri çakışmaları yaşanabilir.
Anlık görüntüler API'si, okuma sırasında çakışan kayıtlı oyunların her ikisini de sunan bir çakışma çözme mekanizması sağlar ve oyununuza uygun bir çözüm stratejisi uygulamanıza olanak tanır.
Play Games Hizmetleri bir veri çakışması algıladığında SnapshotsClient.DataOrConflict.isConflict()
yöntemi true
değerini döndürür. Bu durumda, SnapshotsClient.SnapshotConflict
sınıfı, kayıtlı oyunun iki sürümünü sağlar:
Sunucu sürümü: Play Games Hizmetleri tarafından oyuncunun cihazı için doğru olduğu bilinen en güncel sürüm.
Yerel sürüm: Oynatıcının cihazlarından birinde, çakışan içerik veya meta veri içeren değiştirilmiş bir sürüm algılandı. Bu sürüm, kaydetmeye çalıştığınız sürümle aynı olmayabilir.
Oyununuz, sağlanan sürümlerden birini seçerek veya iki kayıtlı oyun sürümünün verilerini birleştirerek çakışmayı nasıl çözeceğine karar vermelidir.
Kayıtlı oyun çakışmalarını tespit etmek ve çözmek için:
SnapshotsClient.open()
numaralı telefonu arayın. Görev sonucuSnapshotsClient.DataOrConflict
sınıfını içeriyor.SnapshotsClient.DataOrConflict.isConflict()
yöntemini çağırın. Sonuç doğruysa çözmeniz gereken bir çakışma vardır.SnapshotsClient.snapshotConflict
örneğini almak içinSnapshotsClient.DataOrConflict.getConflict()
numaralı telefonu arayın.Algılanan çakışmayı benzersiz şekilde tanımlayan çakışma kimliğini almak için Call
SnapshotsClient.SnapshotConflict.getConflictId()
işlemini kullanın. Oyununuzun daha sonra çakışma çözümü isteği göndermesi için bu değere ihtiyacı vardır.Yerel sürümü edinmek için
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
numaralı telefonu arayın.Sunucu sürümünü almak için
SnapshotsClient.SnapshotConflict.getSnapshot()
numaralı telefonu arayın.Kayıtlı oyun çakışmasını çözmek için sunucuya son sürüm olarak kaydetmek istediğiniz sürümü seçin ve bunu
SnapshotsClient.resolveConflict()
yöntemine iletin.
Aşağıdaki snippet'te, oyununuzun, kaydedilmiş oyun çakışmasını en son değiştirilen kaydedilmiş oyunu son kaydedilecek sürüm olarak seçerek nasıl ele alabileceğine dair bir örnek gösterilmektedir:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; Task<Snapshot> processSnapshotOpenResult(SnapshotsClient.DataOrConflict<Snapshot> result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSource<Snapshot> source = new TaskCompletionSource<>(); source.setResult(result.getData()); return source.getTask(); } // There was a conflict. Try resolving it by selecting the newest of the conflicting snapshots. // This is the same as using RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED as a conflict resolution // policy, but we are implementing it as an example of a manual resolution. // One option is to present a UI to the user to choose which snapshot to resolve. SnapshotsClient.SnapshotConflict conflict = result.getConflict(); Snapshot snapshot = conflict.getSnapshot(); Snapshot conflictSnapshot = conflict.getConflictingSnapshot(); // Resolve between conflicts by selecting the newest of the conflicting snapshots. Snapshot resolvedSnapshot = snapshot; if (snapshot.getMetadata().getLastModifiedTimestamp() < conflictSnapshot.getMetadata().getLastModifiedTimestamp()) { resolvedSnapshot = conflictSnapshot; } return PlayGames.getSnapshotsClient(theActivity) .resolveConflict(conflict.getConflictId(), resolvedSnapshot) .continueWithTask( new Continuation< SnapshotsClient.DataOrConflict<Snapshot>, Task<Snapshot>>() { @Override public Task<Snapshot> then( @NonNull Task<SnapshotsClient.DataOrConflict<Snapshot>> task) throws Exception { // Resolving the conflict may cause another conflict, // so recurse and try another resolution. if (retryCount < MAX_SNAPSHOT_RESOLVE_RETRIES) { return processSnapshotOpenResult(task.getResult(), retryCount + 1); } else { throw new Exception("Could not resolve snapshot conflicts"); } } }); }
Kayıtlı oyunları değiştirme
Birden fazla kayıtlı oyundan verileri birleştirmek veya mevcut bir Snapshot
dosyasını değiştirip çözümlenmiş nihai sürüm olarak sunucuya kaydetmek istiyorsanız aşağıdaki adımları uygulayın:
SnapshotsClient.open()
numaralı telefonu arayın.Yeni bir
SnapshotContents
nesnesi almak içinSnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
numaralı telefonu arayın.SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
veSnapshotsClient.SnapshotConflict.getSnapshot()
verilerini önceki adımdakiSnapshotContents
nesnesinde birleştirin.İsteğe bağlı olarak, meta veri alanlarında değişiklik varsa
SnapshotMetadataChange
örneği oluşturun.SnapshotsClient.resolveConflict()
numaralı telefonu arayın. Yöntem çağrınızda, ilk bağımsız değişken olarakSnapshotsClient.SnapshotConflict.getConflictId()
, ikinci ve üçüncü bağımsız değişkenler olarak da sırasıylaSnapshotMetadataChange
veSnapshotContents
nesnelerini iletin.SnapshotsClient.resolveConflict()
çağrısı başarılı olursa API,Snapshot
nesnesini sunucuda depolar ve yerel cihazınızda Snapshot nesnesini açmaya çalışır.- Çakışma varsa,
SnapshotsClient.DataOrConflict.isConflict()
true
değerini döndürür. Bu durumda, oyununuz 2. adıma geri dönmeli ve çakışmalar çözülene kadar anlık görüntüyü değiştirmek için adımları tekrarlamalıdır. - Çakışma yoksa,
SnapshotsClient.DataOrConflict.isConflict()
false
değerini döndürür veSnapshot
nesnesi, oyununuzun değiştirmesi için açıktır.
- Çakışma varsa,