หลังจากเลิกใช้งาน API ของ Google Sign-In แล้ว เราจะนำ SDK v1 ของเกมออกในปี 2026 หลังจากเดือนกุมภาพันธ์ 2025 คุณจะเผยแพร่
เกมที่เพิ่งผสานรวมกับ SDK v1 ของ Games ใน Google Play ไม่ได้ เราขอแนะนำให้ใช้ SDK v2 ของ Games แทน
แม้ว่าเกมที่มีอยู่ซึ่งผสานรวมกับเกมเวอร์ชัน 1 ก่อนหน้าจะยังคงทำงานได้อีก 2-3 ปี
แต่เราขอแนะนำให้คุณย้ายข้อมูลไปยัง v2
ตั้งแต่เดือนมิถุนายน 2025 เป็นต้นไป
คู่มือนี้มีไว้สำหรับการใช้ SDK บริการเกมของ Play เวอร์ชัน 1 ดูข้อมูล
เกี่ยวกับ SDK เวอร์ชันล่าสุดได้ที่
เอกสารประกอบ v2
คู่มือนี้จะแสดงวิธีใช้งานเกมที่บันทึกไว้โดยใช้
Snapshots API ที่บริการเกมของ Google Play มีให้ คุณจะพบ API ได้ในแพ็กเกจ
com.google.android.gms.games.snapshot
และ com.google.android.gms.games
ก่อนเริ่มต้น
หากยังไม่ได้ดำเนินการ คุณอาจต้องดูแนวคิดเกมที่บันทึกไว้
- โปรดเปิดใช้การรองรับเกมที่บันทึกไว้ สำหรับเกมของคุณใน Google Play Console
- ดาวน์โหลดและตรวจสอบตัวอย่างโค้ดเกมที่บันทึกไว้ในหน้าตัวอย่าง Android
- ทำความคุ้นเคยกับคำแนะนำที่อธิบายไว้ในรายการตรวจสอบคุณภาพ
ดาวน์โหลดไคลเอ็นต์สแนปชอต
หากต้องการเริ่มใช้ Snapshots API เกมของคุณต้องได้รับออบเจ็กต์ SnapshotsClient
ก่อน คุณทำได้โดยการเรียกใช้เมธอด
Games.getSnapshotsClient()
และส่งกิจกรรมและ GoogleSignInAccount
สำหรับผู้เล่นปัจจุบัน ดูวิธี
ดึงข้อมูลบัญชีผู้เล่นได้ที่
การลงชื่อเข้าใช้ในเกม Android
ระบุขอบเขตของไดรฟ์
Snapshots API ใช้ Google Drive API สำหรับพื้นที่เก็บข้อมูลเกมที่บันทึกไว้ หากต้องการเข้าถึง Drive API แอปของคุณต้องระบุขอบเขต Drive.SCOPE_APPFOLDER
เมื่อสร้างไคลเอ็นต์ Google Sign-In
ตัวอย่างวิธีดำเนินการในเมธอด
onResume()
สำหรับกิจกรรมการลงชื่อเข้าใช้มีดังนี้
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 } } }); }
แสดงเกมที่บันทึกไว้
คุณสามารถผสานรวม Snapshots API ได้ทุกที่ที่เกมมีตัวเลือกให้ผู้เล่น บันทึกหรือกู้คืนความคืบหน้า เกมอาจแสดงตัวเลือกดังกล่าวในจุดบันทึก/กู้คืนที่กำหนด หรืออนุญาตให้ผู้เล่นบันทึกหรือกู้คืนความคืบหน้าได้ทุกเมื่อ
เมื่อผู้เล่นเลือกตัวเลือกบันทึก/กู้คืนในเกมของคุณ เกมจะแสดงหน้าจอที่แจ้งให้ผู้เล่นป้อนข้อมูลสำหรับเกมใหม่ที่บันทึกไว้ หรือเลือกเกมที่บันทึกไว้แล้วเพื่อกู้คืน (ไม่บังคับ)
API สแนปชอตมีอินเทอร์เฟซผู้ใช้ (UI) สำหรับการเลือกเกมที่บันทึกไว้เริ่มต้นที่คุณใช้ได้ทันทีเพื่อลดความซับซ้อนในการพัฒนา UI การเลือกเกมที่บันทึกไว้ช่วยให้ผู้เล่น สร้างเกมที่บันทึกไว้ใหม่ ดูรายละเอียดเกี่ยวกับเกมที่บันทึกไว้ที่มีอยู่ และโหลดเกมที่บันทึกไว้ก่อนหน้าได้
วิธีเปิด UI เกมที่บันทึกไว้เริ่มต้น
- โทรหา
SnapshotsClient.getSelectSnapshotIntent()
เพื่อรับIntent
สำหรับเปิดใช้ UI การเลือกเกมที่บันทึกไว้เริ่มต้น - โทรหา
startActivityForResult()
แล้วส่งIntent
หากการเรียกใช้สำเร็จ เกมจะแสดง UI การเลือกเกมที่บันทึกไว้พร้อมกับตัวเลือกที่คุณระบุ
ตัวอย่างวิธีเปิด UI การเลือกเกมที่บันทึกไว้เริ่มต้นมีดังนี้
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); } }); }
หากผู้เล่นเลือกสร้างเกมที่บันทึกไว้ใหม่หรือโหลดเกมที่บันทึกไว้ที่มีอยู่
UI จะส่งคำขอไปยังบริการเกมของ Google Play หากคำขอสำเร็จ บริการเกมของ Google Play จะส่งข้อมูลเพื่อสร้างหรือกู้คืนเกมที่บันทึกไว้ผ่านการเรียกกลับ onActivityResult()
เกมของคุณสามารถลบล้างการเรียกกลับนี้เพื่อตรวจสอบว่าเกิดข้อผิดพลาดใดๆ ขึ้นระหว่างคำขอหรือไม่
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างการใช้งาน 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 // ... } } }
เขียนเกมที่บันทึกไว้
วิธีจัดเก็บเนื้อหาลงในเกมที่บันทึกไว้
- เปิดสแนปชอตแบบไม่พร้อมกันผ่าน
SnapshotsClient.open()
จากนั้นเรียกออบเจ็กต์Snapshot
จากผลลัพธ์ของงานโดยเรียกSnapshotsClient.DataOrConflict.getData()
- เรียกข้อมูลอินสแตนซ์
SnapshotContents
ผ่านSnapshotsClient.SnapshotConflict
- เรียกใช้
SnapshotContents.writeBytes()
เพื่อจัดเก็บข้อมูลของผู้เล่นในรูปแบบไบต์ - เมื่อเขียนการเปลี่ยนแปลงทั้งหมดแล้ว ให้เรียกใช้
SnapshotsClient.commitAndClose()
เพื่อส่งการเปลี่ยนแปลงไปยังเซิร์ฟเวอร์ของ Google ในการเรียกใช้เมธอด เกมของคุณอาจระบุข้อมูลเพิ่มเติมเพื่อบอกบริการเกมของ Google Play ว่าจะ นำเสนอเกมที่บันทึกไว้นี้ต่อผู้เล่นอย่างไร ข้อมูลนี้แสดงในออบเจ็กต์SnapshotMetaDataChange
ซึ่งเกมของคุณสร้างขึ้นโดยใช้SnapshotMetadataChange.Builder
ข้อมูลโค้ดต่อไปนี้แสดงวิธีที่เกมอาจทำการเปลี่ยนแปลงเกมที่บันทึกไว้
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); }
หากอุปกรณ์ของผู้เล่นไม่ได้เชื่อมต่อกับเครือข่ายเมื่อแอปของคุณเรียกใช้ SnapshotsClient.commitAndClose()
บริการเกมของ Google Play จะจัดเก็บข้อมูลเกมที่บันทึกไว้ในอุปกรณ์ เมื่อเชื่อมต่ออุปกรณ์อีกครั้ง บริการเกมของ Google Play จะซิงค์การเปลี่ยนแปลงของเกมที่บันทึกไว้ซึ่งแคชไว้ในเครื่องกับเซิร์ฟเวอร์ของ Google
โหลดเกมที่บันทึกไว้
วิธีดึงข้อมูลเกมที่บันทึกไว้สำหรับผู้เล่นที่ลงชื่อเข้าใช้ในปัจจุบัน
- เปิดสแนปชอตแบบไม่พร้อมกันผ่าน
SnapshotsClient.open()
จากนั้นเรียกออบเจ็กต์Snapshot
จากผลลัพธ์ของงานโดยเรียกSnapshotsClient.DataOrConflict.getData()
หรือเกมของคุณยังสามารถดึงข้อมูลสแนปชอตที่เฉพาะเจาะจงผ่าน UI การเลือกเกมที่บันทึกไว้ได้ด้วย ตามที่อธิบายไว้ในส่วนแสดงเกมที่บันทึกไว้ - ดึงข้อมูลอินสแตนซ์
SnapshotContents
ผ่านSnapshotsClient.SnapshotConflict
- โทรหา
SnapshotContents.readFully()
เพื่ออ่านเนื้อหาของสแนปชอต
ข้อมูลโค้ดต่อไปนี้แสดงวิธีโหลดเกมที่บันทึกไว้โดยเฉพาะ
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. // ... } }); }
จัดการความขัดแย้งของเกมที่บันทึกไว้
เมื่อใช้ Snapshots API ในเกม อุปกรณ์หลายเครื่องจะอ่านและเขียนในเกมที่บันทึกไว้เดียวกันได้ ในกรณีที่อุปกรณ์ขาดการเชื่อมต่อเครือข่ายชั่วคราวและเชื่อมต่ออีกครั้งในภายหลัง อาจทำให้ข้อมูลขัดแย้งกัน ซึ่งเกมที่บันทึกไว้ในอุปกรณ์ของผู้เล่นจะไม่ได้ซิงค์กับเวอร์ชันระยะไกลที่จัดเก็บไว้ในเซิร์ฟเวอร์ของ Google
Snapshots API มีกลไกการแก้ปัญหาความขัดแย้งที่แสดงทั้ง ชุดของเกมที่บันทึกไว้ซึ่งขัดแย้งกันในเวลาอ่าน และช่วยให้คุณใช้กลยุทธ์การแก้ปัญหา ที่เหมาะสมกับเกมของคุณได้
เมื่อบริการเกมของ Google Play ตรวจพบข้อมูลที่ขัดแย้งกัน เมธอด
SnapshotsClient.DataOrConflict.isConflict()
จะแสดงค่าเป็น true
ในกรณีนี้ คลาส
SnapshotsClient.SnapshotConflict
จะมีเกมที่บันทึกไว้ 2 เวอร์ชัน
- เวอร์ชันเซิร์ฟเวอร์: เวอร์ชันล่าสุดที่บริการเกม Google Play ทราบว่าถูกต้อง สำหรับอุปกรณ์ของผู้เล่น และ
- เวอร์ชันในเครื่อง: เวอร์ชันที่แก้ไขแล้วซึ่งตรวจพบในอุปกรณ์เครื่องใดเครื่องหนึ่งของผู้เล่นที่มีเนื้อหาหรือข้อมูลเมตาที่ขัดแย้งกัน ซึ่งอาจไม่ใช่เวอร์ชันเดียวกับที่คุณพยายามบันทึก
เกมของคุณต้องตัดสินใจวิธีแก้ไขข้อขัดแย้งโดยเลือกเวอร์ชันใดเวอร์ชันหนึ่งที่ ระบุไว้ หรือผสานข้อมูลของเกมที่บันทึกไว้ 2 เวอร์ชัน
วิธีตรวจหาและแก้ไขความขัดแย้งของเกมที่บันทึกไว้
- โทรหา
SnapshotsClient.open()
ผลลัพธ์ของงานมีSnapshotsClient.DataOrConflict
คลาส - เรียกใช้เมธอด
SnapshotsClient.DataOrConflict.isConflict()
หากผลลัพธ์เป็นจริง แสดงว่าคุณมี ความขัดแย้งที่ต้องแก้ไข - โทรหา
SnapshotsClient.DataOrConflict.getConflict()
เพื่อเรียกอินสแตนซ์SnapshotsClient.snapshotConflict
- เรียกใช้
SnapshotsClient.SnapshotConflict.getConflictId()
เพื่อดึงรหัสความขัดแย้งที่ระบุความขัดแย้งที่ตรวจพบโดยไม่ซ้ำกัน เกมของคุณต้องมีค่านี้เพื่อส่งคำขอแก้ไขความขัดแย้งในภายหลัง - โทรหา
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
เพื่อรับเวอร์ชันท้องถิ่น - โทรหา
SnapshotsClient.SnapshotConflict.getSnapshot()
เพื่อดูเวอร์ชันเซิร์ฟเวอร์ - หากต้องการแก้ไขความขัดแย้งของเกมที่บันทึกไว้ ให้เลือกเวอร์ชันที่ต้องการบันทึกลงในเซิร์ฟเวอร์เป็น
เวอร์ชันสุดท้าย แล้วส่งไปยังเมธอด
SnapshotsClient.resolveConflict()
ข้อมูลโค้ดต่อไปนี้แสดงตัวอย่างวิธีที่เกมอาจจัดการกับความขัดแย้งของเกมที่บันทึกไว้โดย เลือกเกมที่บันทึกไว้ซึ่งแก้ไขล่าสุดเป็นเวอร์ชันสุดท้ายที่จะบันทึก
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"); } } }); }
แก้ไขเกมที่บันทึกไว้เพื่อแก้ปัญหาความขัดแย้ง
หากต้องการผสานข้อมูลจากเกมที่บันทึกไว้หลายเกมหรือแก้ไข Snapshot
ที่มีอยู่
เพื่อบันทึกลงในเซิร์ฟเวอร์เป็นเวอร์ชันสุดท้ายที่แก้ไขแล้ว ให้ทำตามขั้นตอนต่อไปนี้
- โทรหา
SnapshotsClient.open()
- เรียกใช้
SnapshotsClient.SnapshotConflict.getResolutionSnapshotsContent()
เพื่อรับออบเจ็กต์SnapshotContents
ใหม่ - ผสานข้อมูลจาก
SnapshotsClient.SnapshotConflict.getConflictingSnapshot()
และSnapshotsClient.SnapshotConflict.getSnapshot()
ลงในออบเจ็กต์SnapshotContents
จาก ขั้นตอนก่อนหน้า - หรือจะสร้างอินสแตนซ์
SnapshotMetadataChange
ก็ได้หากมีการเปลี่ยนแปลงฟิลด์ข้อมูลเมตา - โทรหา
SnapshotsClient.resolveConflict()
ในการเรียกเมธอด ให้ส่งSnapshotsClient.SnapshotConflict.getConflictId()
เป็นอาร์กิวเมนต์แรก และออบเจ็กต์SnapshotMetadataChange
และSnapshotContents
ที่คุณแก้ไขก่อนหน้านี้เป็นอาร์กิวเมนต์ที่ 2 และ 3 ตามลำดับ - หากการเรียก
SnapshotsClient.resolveConflict()
สำเร็จ API จะจัดเก็บออบเจ็กต์Snapshot
ไว้ในเซิร์ฟเวอร์และพยายามเปิดออบเจ็กต์ Snapshot ในอุปกรณ์ของคุณ- หากมีข้อขัดแย้ง
SnapshotsClient.DataOrConflict.isConflict()
จะแสดงผลtrue
ในกรณีนี้ เกมควรกลับไปที่ขั้นตอนที่ 2 และทำขั้นตอนซ้ำเพื่อแก้ไขสแนปชอตจนกว่า ความขัดแย้งจะได้รับการแก้ไข - หากไม่มีข้อขัดแย้ง
SnapshotsClient.DataOrConflict.isConflict()
จะแสดงผลfalse
และ ออบเจ็กต์Snapshot
จะเปิดให้เกมของคุณแก้ไขได้
- หากมีข้อขัดแย้ง