Google ile Giriş API'sinin desteğinin sonlandırılmasının ardından, 2026'da Games v1 SDK'sını kaldırıyoruz. Şubat 2025'ten sonra games v1 SDK'sıyla yeni entegre edilen oyunları Google Play'de yayınlayamayacaksınız. Bunun yerine games v2 SDK'sını kullanmanızı öneririz.
Önceki Games v1 entegrasyonlarına sahip mevcut uygulamalar birkaç yıl daha çalışmaya devam edecek olsa da
Haziran 2025'ten itibaren
v2'ye geçiş yapmanız
önerilir.
Bu kılavuz, Play Games Hizmetleri v1 SDK'sının kullanımıyla ilgilidir. En son SDK sürümü hakkında bilgi için v2 belgelerine bakın.
Bu kılavuzda, Google Play Games Hizmetleri tarafından sağlanan anlık görüntüler API'sini kullanarak kaydedilmiş oyunlar özelliğini nasıl uygulayacağınız gösterilmektedir. API'leri com.google.android.gms.games.snapshot
ve com.google.android.gms.games
paketlerinde bulabilirsiniz.
Başlamadan önce
Henüz yapmadıysanız Kayıtlı Oyunlar oyun kavramlarını incelemeniz faydalı olabilir.
- Google Play Console'da oyununuz için kaydedilmiş oyunlar desteğini etkinleştirdiğinizden emin olun.
- 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.getSnapshotsClient()
yöntemini çağırıp etkinliği ve mevcut oyuncu için GoogleSignInAccount
değerini ileterek yapabilirsiniz. Oyuncu hesabı bilgilerini nasıl alacağınızı öğrenmek için Android oyunlarında oturum açma başlıklı makaleyi inceleyin.
Drive kapsamını belirtme
Anlık görüntüler API'si, kaydedilmiş oyunların depolanması için Google Drive API'yi kullanır. Drive API'ye erişmek için uygulamanız, Google ile oturum açma istemcisini oluştururken Drive.SCOPE_APPFOLDER
kapsamını belirtmelidir.
Oturum açma etkinliğiniz için onResume()
yönteminde bunu nasıl yapacağınızla ilgili bir örneği aşağıda bulabilirsiniz:
private GoogleSignInClient mGoogleSignInClient; @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 } } }); }
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, belirlenen kaydetme/geri yükleme noktalarında böyle bir seçenek gösterebilir veya oyuncuların ilerlemeyi istedikleri zaman kaydetmelerine ya da geri yüklemelerine izin verebilir.
Oyuncular oyununuzda kaydetme/geri yükleme seçeneğini belirlediğinde oyununuz, oyuncuları yeni bir kayıtlı oyun için bilgi girmeye veya 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, varsayılan bir kayıtlı oyun seçimi kullanıcı arayüzü (UI) sağlar. Bu arayüzü hemen kullanabilirsiniz. Kayıtlı oyun 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 ö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()
numaralı telefonu arayarakIntent
isteyin. startActivityForResult()
numaralı telefonu arayın veIntent
kodunu iletin. Arama başarılı olursa oyunda, belirttiğiniz seçeneklerle birlikte kayıtlı oyun seçimi kullanıcı arayüzü gösterilir.
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 bulabilirsiniz:
private static final int RC_SAVED_GAMES = 9009; private void showSavedGamesUI() { SnapshotsClient snapshotsClient = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(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ü, Google Play Games Hizmetleri'ne istek gönderir. İstek başarılı olursa Google 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 ç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()
ile eşzamansız olarak anlık görüntü açın. Ardından,SnapshotsClient.DataOrConflict.getData()
işlevini çağırarak görev sonucundanSnapshot
nesnesini alın.SnapshotsClient.SnapshotConflict
üzerindenSnapshotContents
örneğini 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. Yöntem çağrısında oyununuz, Google Play Games Hizmetleri'ne bu kayıtlı oyunu oyunculara nasıl sunacağını bildirmek için isteğe bağlı olarak 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 = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(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 Google Play Games Hizmetleri, kayıtlı oyun verilerini cihazda yerel olarak saklar. Cihaz yeniden bağlandığında Google 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 eşzamansız olarak anlık görüntü açın. Ardından,SnapshotsClient.DataOrConflict.getData()
işlevini çağırarak görev sonucundanSnapshot
nesnesini alın. Alternatif olarak, oyununuz Kayıtlı 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üyü de alabilir.SnapshotContents
örneğiniSnapshotsClient.SnapshotConflict
üzerinden alın.- Anlık görüntünün içeriğini okumak için
SnapshotContents.readFully()
numarasını arayı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 = Games.getSnapshotsClient(this, GoogleSignIn.getLastSignedInAccount(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ğlandığında, oyuncunun yerel cihazında depolanan kayıtlı oyunun Google'ın sunucularında depolanan uzak sürümüyle 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.
Google 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ü: Google Play Games Hizmetleri'nin, oyuncunun cihazı için doğru olduğunu bildiği en güncel sürüm ve
- Yerel sürüm: Oyuncunun 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.DataOrConflict.getConflict()
numaralı telefonu arayarakSnapshotsClient.snapshotConflict
örneğini alın.- Algılanan ç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
SnapshotsClient.resolveConflict()
yöntemine iletin.
Aşağıdaki snippet'te, en son değiştirilen kayıtlı oyunu kaydedilecek son sürüm olarak seçerek oyununuzun kayıtlı oyun çakışmasını 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 Games.getSnapshotsClient(theActivity, GoogleSignIn.getLastSignedInAccount(this)) .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"); } } }); }
Çakışma çözümü için kayıtlı oyunları değiştirme
Birden fazla kayıtlı oyundan gelen verileri birleştirmek veya mevcut bir Snapshot
dosyasını değiştirerek çö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
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
nesnesi almak içinSnapshotContents
numaralı telefonu arayın. SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
veSnapshotsClient.SnapshotConflict.getSnapshot()
kaynaklarındaki verileri ö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ıyla daha önce değiştirdiğinizSnapshotMetadataChange
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çılır.
- Çakışma varsa