Bu kılavuzda, Google Play Games Hizmetleri tarafından sağlanan anlık görüntü API'sini kullanarak kayıtlı oyunların nasıl uygulanacağı gösterilmektedir. API'ler com.google.android.gms.games.snapshot
ve com.google.android.gms.games
paketlerinde bulunabilir.
Başlamadan önce
Bu özellik hakkında bilgi edinmek için Kaydedilmiş Oyunlara genel bakış sayfasını inceleyin.
- Google Play Console'da oyununuz için kayıtlı oyun desteğini etkinleştirin.
- Android örnekleri sayfasından kaydedilmiş oyunlar kod örneğini indirip inceleyin.
- Kalite Kontrol Listesi'nde açıklanan önerilere aşina olun.
Anlık görüntü istemcisini alma
Snapshot API'yi kullanmaya başlamak için oyununuzun önce bir SnapshotsClient
nesnesi edinmesi gerekir. Bunu, Games.getSnapshotsClient()
yöntemini çağırarak ve etkinliği ileterek yapabilirsiniz.
Drive kapsamını belirtme
Snapshot API, kaydedilen oyunların depolanması için Google Drive API'yi kullanır. Drive API'ye erişmek için uygulamanızın Google ile Oturum Açma istemcisini oluştururken Drive.SCOPE_APPFOLDER
kapsamını belirtmesi gerekir.
Oturum açma etkinliğiniz için onResume()
yönteminde bunu nasıl yapacağınıza dair bir örneği aşağıda bulabilirsiniz:
@Override protected void onResume() { super.onResume(); signInSilently(); } private void signInSilently() { GoogleSignInOptions signInOption = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN) // Add the APPFOLDER scope for Snapshot support. .requestScopes(Drive.SCOPE_APPFOLDER) .build(); GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOption); signInClient.silentSignIn().addOnCompleteListener(this, new OnCompleteListener<GoogleSignInAccount>() { @Override public void onComplete(@NonNull Task<GoogleSignInAccount> task) { if (task.isSuccessful()) { onConnected(task.getResult()); } else { // Player will need to sign-in explicitly using via UI } } }); }
Kaydedilmiş oyunları gösterme
Oyununuzun oyunculara ilerlemelerini kaydetme veya geri yükleme seçeneği sunduğu her yerde Snapshot API'sini entegre edebilirsiniz. Oyununuz belirlenen kaydetme/geri yükleme noktalarında böyle bir seçenek gösterebilir veya oyuncuların istedikleri zaman ilerleme durumunu kaydetmelerine veya geri yüklemelerine izin verebilir.
Oyuncular oyununuzda kaydet/geri yükleme seçeneğini belirlediğinde, oyununuz isteğe bağlı olarak oyuncuların yeni kayıtlı oyun için bilgi girmelerini veya geri yüklemek üzere mevcut bir oyunu seçmelerini isteyen bir ekran açabilir.
Snaps API, geliştirmenizi basitleştirmek için kullanıma hazır bir şekilde kullanabileceğiniz varsayılan bir kayıtlı oyun seçimi kullanıcı arayüzü (UI) sağlar. Kaydedilen oyunlar seçimi 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 önceden kaydedilmiş 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
Intent
numaralı telefonu almak üzereSnapshotsClient.getSelectSnapshotIntent()
numaralı telefonu arayın. startActivityForResult()
numarasını arayın veIntent
kartınızı geçirin. Çağrı başarılı olursa oyun, belirttiğiniz seçeneklerle birlikte kaydedilmiş oyun seçimi kullanıcı arayüzünü görüntüler.
Kaydedilmiş oyun seçimi için varsayılan kullanıcı arayüzünün nasıl başlatılacağına dair bir örneği aşağıda bulabilirsiniz:
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ğırması aracılığıyla kayıtlı oyunu oluşturmak veya geri yüklemek için gereken 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 // ... } } }
Kaydedilmiş oyunları yaz
Kaydedilmiş bir oyunda içerik depolamak için:
SnapshotsClient.open()
üzerinden bir anlık görüntüyü eşzamansız olarak açın.SnapshotsClient.DataOrConflict.getData()
yöntemini çağırarak görevin sonucundanSnapshot
nesnesini alın.SnapshotsClient.SnapshotConflict
ile birSnapshotContents
örneği alın.Oynatıcının verilerini bayt biçiminde depolamak için
SnapshotContents.writeBytes()
çağrısı yapın.Tüm değişiklikleriniz yazıldıktan sonra değişikliklerinizi Google'ın sunucularına göndermek için
SnapshotsClient.commitAndClose()
çağrısı yapın. Yöntem çağrısında, oyununuz isteğe bağlı olarak Play Games Hizmetleri'ne kaydedilen bu oyunu oyunculara nasıl sunacağını bildirmek için ek bilgiler sağlayabilir. Bu bilgiler, oyununuzunSnapshotMetadataChange.Builder
kullanarak oluşturduğu birSnapshotMetaDataChange
nesnesinde temsil edilir.
Aşağıdaki snippet'te, oyununuzun kayıtlı bir oyunda nasıl değişiklik yapabileceğ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()
çağrısı yaptığında oyuncunun cihazı bir ağa bağlı değilse Play Games Hizmetleri, kaydedilen oyun verilerini cihazda yerel olarak depolar. Cihaz yeniden bağlandıktan sonra Play Games Hizmetleri, yerel olarak önbelleğe alınmış kayıtlı oyun değişikliklerini Google'ın sunucularıyla senkronize eder.
Kaydedilmiş oyunları yükle
Şu anda oturum açmış olan oyuncunun kayıtlı oyunlarını almak için:
Bir anlık görüntüyü
SnapshotsClient.open()
ile eşzamansız olarak açın.SnapshotsClient.DataOrConflict.getData()
yöntemini çağırarak görevin sonucundanSnapshot
nesnesini alın. Alternatif olarak, oyununuz Kaydedilmiş Oyunları Görüntüleme bölümünde açıklandığı gibi, kayıtlı oyunlar seçim kullanıcı arayüzü aracılığıyla belirli bir anlık görüntü alabilir.SnapshotContents
örneğiniSnapshotsClient.SnapshotConflict
ile alın.Anlık görüntünün içeriğini okumak için
SnapshotContents.readFully()
çağrısı yapın.
Aşağıdaki snippet'te belirli bir kayıtlı oyunu nasıl yükleyebileceğiniz 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. // ... } }); }
Kaydedilmiş oyun çakışmalarını ele alma
Oyununuzda Snapshot API'sini kullanırken birden fazla cihaz, kaydedilen aynı oyun üzerinde okuma ve yazma işlemleri gerçekleştirebilir. Bir cihazın ağ bağlantısını geçici olarak kaybedip daha sonra yeniden bağlanması halinde bu durum, oyuncunun yerel cihazında depolanan kayıtlı oyunun, Google'ın sunucularında depolanan uzak sürümle senkronize edilmemesine ve dolayısıyla veri çakışmalarına neden olabilir.
Snapshot API'si, çakışan kaydedilmiş oyun gruplarının her ikisini de okuma sırasında sunan ve oyununuz için uygun bir çözüm stratejisi uygulayabilmenizi sağlayan bir çakışma çözüm mekanizması sağlar.
Play Games Hizmetleri bir veri çakışması tespit ettiğinde SnapshotsClient.DataOrConflict.isConflict()
yöntemi true
değerini döndürür. Bu durumda SnapshotsClient.SnapshotConflict
sınıfı, kaydedilen oyunun iki sürümünü sunar:
Sunucu sürümü: Play Oyun 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 barındıran değiştirilmiş bir sürüm. Bu, kaydetmeye çalıştığınız sürümle aynı olmayabilir.
Oyununuz, sağlanan sürümlerden birini seçerek veya kaydedilen iki oyun sürümünün verilerini birleştirerek çakışmanın nasıl çözüleceğine karar vermelidir.
Kaydedilmiş oyun çakışmalarını tespit edip çözmek için:
SnapshotsClient.open()
numaralı telefonu arayın. Görev sonucu birSnapshotsClient.DataOrConflict
sınıfı içeriyor.SnapshotsClient.DataOrConflict.isConflict()
yöntemini çağırın. Sonuç doğruysa çözmeniz gereken bir anlaşmazlık vardır.SnaphotsClient.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
SnapshotsClient.SnapshotConflict.getConflictId()
çağrısı yapın. Oyununuz daha sonra çakışma çözümü isteği göndermek için bu değere ihtiyaç duyar.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.Kaydedilmiş oyun çakışmasını çözmek için sunucuya son sürüm olarak kaydetmek istediğiniz sürümü seçip
SnapshotsClient.resolveConflict()
yöntemine iletin.
Aşağıdaki snippet'te, en son değiştirilen oyunun kaydedileceği son sürüm olarak seçilerek kaydedilen bir oyun çakışmasını nasıl ele alabileceği 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"); } } }); }
Kaydedilmiş oyunları değiştirme
Kaydedilmiş birden fazla oyundaki verileri birleştirmek veya mevcut bir Snapshot
dosyasını çözülmüş son sürüm olarak sunucuya kaydetmek için değiştirmek isterseniz aşağıdaki adımları uygulayın:
SnapshotsClient.open()
numaralı telefonu arayın.Yeni bir
SnapshotContents
nesnesi almak içinSnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
çağrısı yapın.SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
veSnapshotsClient.SnapshotConflict.getSnapshot()
verilerini önceki adımda bulunanSnapshotContents
nesnesiyle birleştirin.İsteğe bağlı olarak, meta veri alanlarında herhangi bir değişiklik varsa bir
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()
ve daha önce değiştirdiğinizSnapshotMetadataChange
veSnapshotContents
nesnelerini sırasıyla ikinci ve üçüncü bağımsız değişken olarak iletin.SnapshotsClient.resolveConflict()
çağrısı başarılı olursa API,Snapshot
nesnesini sunucuya depolar ve yerel cihazınızda Anlık Görüntü nesnesini açmayı dener.- Bir ç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üde değişiklik yapmak için bu adımları tekrarlamalıdır. - Çakışma yoksa
SnapshotsClient.DataOrConflict.isConflict()
,false
değerini döndürür veSnapshot
nesnesi, oyununuzda değişiklik yapılması için açıktır.
- Bir çakışma varsa