Panduan ini menunjukkan cara menerapkan game game tersimpan menggunakan
snapshot API yang disediakan oleh layanan game Google Play. API ini dapat ditemukan dalam paket
com.google.android.gms.games.snapshot
dan com.google.android.gms.games
.
Sebelum memulai
Jika Anda belum melakukannya, sebaiknya tinjau Konsep game Game tersimpan.
- Pastikan untuk mengaktifkan dukungan game tersimpan untuk game Anda di Konsol Google Play.
- Download dan tinjau contoh kode game tersimpan di halaman contoh Android.
- Pahami rekomendasi yang dijelaskan dalam Checklist Kualitas.
Mendapatkan klien snapshot
Untuk mulai menggunakan snapshot API, game Anda harus mendapatkan
objek SnapshotsClient
terlebih dahulu. Anda dapat melakukannya dengan memanggil
Games.getSnapshotsClient()
dan meneruskan
dan GoogleSignInAccount
untuk pemutar saat ini. Untuk mempelajari cara
melihat informasi akun pemain,
Login di Game Android.
Menentukan cakupan Drive
Snapshot API mengandalkan Google Drive API untuk penyimpanan game tersimpan. Kepada
mengakses Drive API, aplikasi Anda harus menetapkan
Drive.SCOPE_APPFOLDER
cakupan saat membuat klien login dengan Google.
Berikut adalah contoh cara melakukannya di metode
onResume()
untuk aktivitas login Anda:
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 } } }); }
Menampilkan game tersimpan
Anda dapat mengintegrasikan snapshot API di mana pun game Anda menyediakan opsi kepada pemain untuk menyimpan atau memulihkan progresnya. Game Anda mungkin menampilkan opsi tersebut di titik penyimpanan/pemulihan yang ditentukan, atau memungkinkan pemain untuk menyimpan atau memulihkan progres kapan saja.
Setelah pemain memilih opsi simpan/pulihkan dalam game, game Anda dapat secara opsional menampilkan layar yang meminta pemain untuk memasukkan informasi game tersimpan yang baru atau memilih game tersimpan yang sudah ada untuk dipulihkan.
Untuk menyederhanakan pengembangan, snapshot API menyediakan antarmuka pengguna (UI) pilihan game tersimpan default yang dapat Anda gunakan secara langsung. UI pilihan game tersimpan memungkinkan pemain membuat game tersimpan baru, melihat detail tentang game tersimpan yang ada, dan memuat game tersimpan sebelumnya.
Untuk meluncurkan UI Game Tersimpan default:
- Panggil
SnapshotsClient.getSelectSnapshotIntent()
untuk mendapatkanIntent
untuk meluncurkan default UI pemilihan game tersimpan. - Panggil
startActivityForResult()
dan teruskanIntent
tersebut. Jika panggilan berhasil, game akan menampilkan UI pilihan game tersimpan, beserta opsi yang Anda tentukan.
Berikut adalah contoh cara meluncurkan UI pilihan game tersimpan default:
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); } }); }
Jika pemain memilih untuk membuat game tersimpan baru atau memuat game tersimpan yang sudah ada,
UI mengirimkan permintaan ke layanan game Google Play. Jika permintaan berhasil,
Layanan game Google Play menampilkan informasi untuk membuat atau memulihkan game tersimpan melalui
onActivityResult()
. Game Anda dapat mengganti callback ini untuk memeriksa apakah terjadi error selama permintaan.
Cuplikan kode berikut menunjukkan contoh implementasi
onActivityResult()
:
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 // ... } } }
Menulis game tersimpan
Untuk menyimpan konten ke game tersimpan:
- Buka snapshot secara asinkron melalui
SnapshotsClient.open()
. Lalu, ambil objekSnapshot
dari hasil tugas dengan memanggilSnapshotsClient.DataOrConflict.getData()
. - Ambil instance
SnapshotContents
melaluiSnapshotsClient.SnapshotConflict
. - Panggil
SnapshotContents.writeBytes()
untuk menyimpan data pemutar dalam format byte. - Setelah semua perubahan ditulis, panggil
SnapshotsClient.commitAndClose()
untuk mengirim perubahan ke server Google. Dalam panggilan metode, Secara opsional, game Anda dapat memberikan informasi tambahan untuk memberi tahu layanan game Google Play cara menyajikan game tersimpan ini kepada pemain. Informasi ini ditampilkan dalamSnapshotMetaDataChange
, yang dibuat game Anda menggunakanSnapshotMetadataChange.Builder
.
Cuplikan berikut menunjukkan cara game Anda dapat melakukan perubahan pada game tersimpan:
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); }
Jika perangkat pemutar tidak terhubung ke jaringan saat aplikasi Anda melakukan panggilan
SnapshotsClient.commitAndClose()
, Layanan game Google Play menyimpan data game tersimpan secara lokal di
perangkat. Setelah perangkat dihubungkan kembali, layanan game Google Play menyinkronkan game tersimpan yang di-cache secara lokal
perubahan pada server Google.
Memuat game tersimpan
Untuk mengambil game tersimpan dari pemain yang saat ini login:
- Buka snapshot secara asinkron melalui
SnapshotsClient.open()
. Lalu, ambil objekSnapshot
dari hasil tugas dengan memanggilSnapshotsClient.DataOrConflict.getData()
. Atau, game juga dapat mengambil snapshot tertentu melalui UI pilihan game tersimpan, seperti yang dijelaskan dalam Menampilkan Game Tersimpan. - Ambil instance
SnapshotContents
melaluiSnapshotsClient.SnapshotConflict
. - Panggil
SnapshotContents.readFully()
untuk membaca konten snapshot.
Cuplikan berikut menunjukkan cara memuat game tersimpan tertentu:
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. // ... } }); }
Menangani konflik game tersimpan
Saat menggunakan snapshot API dalam game, beberapa perangkat dapat melakukan pembacaan dan penulisan di game tersimpan yang sama. Jika koneksi jaringan terputus untuk sementara dan kemudian terhubung kembali, hal ini dapat menyebabkan konflik data saat game tersimpan yang disimpan di perangkat lokal pemain tidak sinkron dengan versi jarak jauh yang tersimpan di server Google.
Snapshot API memberikan mekanisme resolusi konflik yang menyajikan serangkaian game tersimpan yang mengalami konflik pada waktu baca dan memungkinkan Anda menerapkan strategi penyelesaian yang sesuai untuk game Anda.
Saat layanan game Google Play mendeteksi konflik data,
Metode SnapshotsClient.DataOrConflict.isConflict()
menampilkan nilai true
. Dalam peristiwa ini, metode
Class SnapshotsClient.SnapshotConflict
menyediakan dua versi game tersimpan:
- Versi server: Versi terbaru yang diketahui oleh layanan game Google Play agar akurat untuk perangkat pemain; dan
- Versi lokal: Versi modifikasi yang terdeteksi di salah satu perangkat pemain yang berisi konten atau metadata yang bertentangan. Versi ini mungkin tidak sama dengan versi yang Anda coba simpan.
Game Anda harus menentukan cara menyelesaikan konflik dengan memilih salah satu versi yang disediakan atau menggabungkan data dari kedua versi game tersimpan.
Untuk mendeteksi dan menyelesaikan konflik game tersimpan:
- Panggil
SnapshotsClient.open()
. Hasil tugas berisi classSnapshotsClient.DataOrConflict
. - Panggil metode
SnapshotsClient.DataOrConflict.isConflict()
. Jika hasilnya benar, Anda memiliki konflik yang harus diselesaikan. - Panggil
SnapshotsClient.DataOrConflict.getConflict()
untuk mengambil InstanceSnaphotsClient.snapshotConflict
. - Panggil
SnapshotsClient.SnapshotConflict.getConflictId()
untuk mengambil ID konflik yang secara unik mengidentifikasi konflik yang terdeteksi. Game Anda memerlukan nilai ini untuk mengirim permintaan penyelesaian konflik nanti. - Panggil
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
untuk mendapatkan versi lokal. - Panggil
SnapshotsClient.SnapshotConflict.getSnapshot()
untuk mendapatkan versi server. - Untuk menyelesaikan konflik game tersimpan, pilih versi yang ingin Anda simpan ke server sebagai
versi final, lalu meneruskannya ke metode
SnapshotsClient.resolveConflict()
.
Cuplikan berikut menunjukkan dan memberikan contoh cara game Anda dapat menangani konflik game tersimpan dengan memilih game tersimpan yang terakhir diubah sebagai versi final untuk disimpan:
private static final int MAX_SNAPSHOT_RESOLVE_RETRIES = 10; TaskS<napshot >processSnapshotOpenResult(SnapshotsClient.DataOrConflictS<napshot >result, final int retryCount) { if (!result.isConflict()) { // There was no conflict, so return the result of the source. TaskCompletionSourceS<napshot >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.DataOrConflictS<napshot,> TaskS<napshot(>>) { @Override public TaskS<napshot >then( @NonNull TaskS<napshotsClient.DataOrConflictS<napshot >>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(C"ould not resolve snapshot conflicts)"; } } }); }
Memodifikasi game tersimpan untuk menyelesaikan konflik
Jika Anda ingin menggabungkan data dari beberapa game tersimpan atau mengubah Snapshot
yang ada
untuk menyimpan ke server sebagai versi final yang telah diselesaikan, ikuti langkah-langkah berikut:
- Panggil
SnapshotsClient.open()
. - Panggil
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
untuk mendapatkan ObjekSnapshotContents
. - Gabungkan data dari
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
danSnapshotsClient.SnapshotConflict.getSnapshot()
ke objekSnapshotContents
dari langkah sebelumnya. - Secara opsional, buat instance
SnapshotMetadataChange
jika ada perubahan pada metadata kolom. - Panggil
SnapshotsClient.resolveConflict()
. Dalam panggilan metode, teruskanSnapshotsClient.SnapshotConflict.getConflictId()
sebagai argumen pertama, dan ObjekSnapshotMetadataChange
danSnapshotContents
yang sebelumnya Anda ubah sebagai objek kedua dan argumen ketiga. - Jika panggilan
SnapshotsClient.resolveConflict()
berhasil, API akan menyimpanSnapshot
ke server dan mencoba membuka objek Snapshot di perangkat lokal Anda.- Jika ada konflik,
SnapshotsClient.DataOrConflict.isConflict()
akan menampilkantrue
. Dalam hal ini, game Anda harus kembali ke langkah 2 dan mengulangi langkah-langkah untuk mengubah snapshot hingga konflik terselesaikan. - Jika tidak ada konflik,
SnapshotsClient.DataOrConflict.isConflict()
akan menampilkanfalse
dan objekSnapshot
terbuka untuk diubah game Anda.
- Jika ada konflik,