Bu kılavuzda, Google Play Games Hizmetleri tarafından sağlanan anlık görüntüler API'si kullanılarak kayıtlı 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 için Kaydedilmiş Oyunlar'a 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()işlevini çağırarakIntentalın. 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ün nasıl başlatılacağına dair bir örneği 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 bilgi döndürür. Oyununuz, istek sırasında hata oluşup oluşmadığını kontrol etmek için bu geri aramayı 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 kaydedilmiş bir 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 sonucundanSnapshotnesnesini alın.SnapshotContentsörneğiniSnapshotsClient.SnapshotConflictile alma.Oyuncunun verilerini bayt biçiminde depolamak için
SnapshotContents.writeBytes()işlevini çağırın.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ı oyunu oyunculara nasıl sunacağını bildirmek için ek bilgiler sağlayabilir. Bu bilgiler, oyununuzunSnapshotMetadataChange.Builderkullanarak oluşturduğu birSnapshotMetaDataChangenesnesinde gösterilir.
Aşağıdaki snippet'te, oyununuzun kaydedilmiş bir oyunda değişiklikleri nasıl işleyebileceği gösterilmektedir:
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ınmış kayıtlı oyun değişikliklerini Google'ın sunucularıyla senkronize eder.
Kayıtlı oyunları yükleme
Kimliği doğrulanmış oyuncu için kayıtlı oyunları almak üzere:
SnapshotsClient.open()ile bir anlık görüntüyü eşzamansız olarak açın.Snapshotnesnesini,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.SnapshotConflictile alın.Anlık görüntünün içeriğini okumak için Call
SnapshotContents.readFully()işlevini kullanı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ını geçici olarak kaybetmesi ve 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.DataOrConflictsı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.Çakışmayı benzersiz şekilde tanımlayan çakışma kimliğini almak için
SnapshotsClient.SnapshotConflict.getConflictId()işlevini çağırı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 nihai sürüm olarak sunucuya kaydetmek istiyorsanız aşağıdaki adımları uygulayın:
SnapshotsClient.open()numaralı telefonu arayın.Yeni bir
SnapshotContentsnesnesi almak içinSnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()numaralı telefonu arayın.SnapshotsClient.SnapshotConflict.getConflictingSnapshot()veSnapshotsClient.SnapshotConflict.getSnapshot()verilerini önceki adımdakiSnapshotContentsnesnesinde 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ıyla daha önce değiştirdiğinizSnapshotMetadataChangeveSnapshotContentsnesnelerini iletin.SnapshotsClient.resolveConflict()çağrısı başarılı olursa API,Snapshotnesnesini sunucuda depolar ve yerel cihazınızda Snapshot nesnesini açmaya çalışır.- Çakışma varsa,
SnapshotsClient.DataOrConflict.isConflict()truedeğ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()falsedeğerini döndürür veSnapshotnesnesi, oyununuzun değiştirmesi için açıktır.
- Çakışma varsa,