游戏存档是指把玩家的游戏进度存储至华为云空间中,即使用户之前的设备丢失、损毁或换了新设备,只要用户使用相同的华为帐号登录,就可以从华为云空间取得之前的游戏进度继续游戏。
一个存档主要由2部分组成:
属性 | 说明 |
存档ID | 存档在该游戏中的唯一标识,在提交存档文件后由华为游戏服务器生成。 |
存档名称 | 存档保存的文件名,在提交存档文件后由华为游戏服务器生成。 |
存档描述 | 存档用于展示给玩家的描述信息,在提交存档文件时由您自行定义,最多1000个字符。 |
上次修改时间 | 服务器生成的时间戳(以毫秒为单位),表示上次更新保存的游戏的时间。 |
游戏时长 | 您在提交存档文件时提供的玩家在该存档上游戏总时间(以毫秒为单位)。 |
游戏进度 | 您在提交存档文件时提供的玩家在该存档上的游戏进度,由您自行定义。比如第几关等,用整数进行识别。 |
封面图片 | 您在提交存档文件时提供的存档封面图像,一般来说为游戏存档时的截图,若未提供,则为系统默认图片,最大200KB,支持JPG或PNG格式,长宽比为16:9。 |
在本次codelab中,您将建立一个具备简单游戏交互功能的Android应用程序,您的应用程序将包含以下功能:
集成HUAWEI HMS Core能力,需要完成以下准备工作:
Android Studio的代码库配置在Gradle插件7.0以下版本、7.0版本和7.1及以上版本有所不同。请根据您当前的Gradle插件版本,选择对应的配置过程。
7.0以下版本 | 7.0版本 | 7.1及以上版本 |
buildscript{
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
// 增加agcp插件配置,推荐您使用最新版本的agcp插件。
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
allprojects {
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
buildscript{
repositories {
google()
jcenter()
// 配置HMS Core SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
// 增加agcp插[最新版本](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550)推荐您使用最新版本的agcp插件。
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
dependencyResolutionManagement {
...
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
buildscript{
dependencies {
...
// 增加agcp插[最新版本](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550)推荐您使用最新版本的agcp插件。
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
// 配置HMS Core SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
dependencyResolutionManagement {
...
repositories {
google()
mavenCentral()
// 配置HMS Core SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
apply plugin: 'com.huawei.agconnect'
plugins {
id 'com.android.application'
// 添加如下配置
id 'com.huawei.agconnect'
}
编译APK前需要添加混淆配置,避免功能异常。配置步骤如下:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
-keep class com.huawei.gamebox.plugin.gameservice.**{*;}
-keep interface com.huawei.hms.analytics.type.HAEventType{*;}
-keep interface com.huawei.hms.analytics.type.HAParamType{*;}
-keep class com.huawei.hms.analytics.HiAnalyticsInstance{*;}
-keep class com.huawei.hms.analytics.HiAnalyticsInstance{*;}
-keep class com.huawei.hms.analytics.HiAnalytics{*;}
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/hms_download_progress,@drawable/screen_off,@layout/upsdk*,@drawable/c_buoycircle*,@drawable/hms_game*,@layout/c_buoycircle*,@layout/hms_game*,@strings/hms_game*,@strings/c_buoycircle*"
tools:shrinkMode="strict" />
本次Codelab中您可以在Android Studio工程中创建一个主页面,布局参照下图进行UI设计,新增四个Button。"init"点击后调用初始化接口,初始化接口调用成功后自动调用登录接口,"createArchive"点击后调用跳转到创建存档页面,"displayByAppAssistant"点击后跳转到华为应用助手展示存档列表页面, "displayUserSelf"点击后跳转到自定义展示存档列表页面,点击列表条目时,可以实现打开游戏存档的功能,具体页面展示和布局代码在10 开发展示游戏存档列表功能时再详细介绍,此处不展示。
// 布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_init"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="init"/>
<Button
android:id="@+id/btn_createArchive"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="createArchive"/>
<Button
android:id="@+id/btn_displayByAppAssistant"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="displayByAppAssistant"/>
<Button
android:id="@+id/btn_displayUserSelf"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="displayUserSelf"/>
</LinearLayout>
public class MyApplication extends Application {
@Override
public void onCreate(){
super.onCreate();
HuaweiMobileServicesUtil.setApplication(this);
}
}
private void init(){
AccountAuthParams params = AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME;
JosAppsClient appsClient = JosApps.getJosAppsClient(this);
// 设置防沉迷提示语的context
ResourceLoaderUtil.setmContext(this);
Task<Void> initTask = appsClient.init(new AppParams(params, new AntiAddictionCallback() {
@Override
public void onExit() {
// System.exit(0);
// 该回调会在如下两种情况下返回:
// 1.未成年人实名帐号在白天登录游戏,华为会弹框提示玩家不允许游戏,玩家点击"确定",华为返回回调
// 2.未成年实名帐号在国家允许的时间登录游戏,到晚上9点,华为会弹框提示玩家已到时间,玩家点击"知道了",华为返回回调
// 您可在此处实现游戏防沉迷功能,如保存游戏、调用帐号退出接口或直接游戏进程退出(如System.exit(0)) }}));
initTask.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
showLog("init success");
hasInit = true;
// 一定要在init成功之后,才可以调用登录接口
signIn();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
int statusCode = apiException.getStatusCode();
if (statusCode == JosStatusCodes.JOS_PRIVACY_PROTOCOL_REJECTED) {
// 错误码为7401时表示用户未同意华为联运隐私协议
showLog("has reject the protocol");
// 此处您需禁止玩家进入游戏
} else if (statusCode == GamesStatusCodes.GAME_STATE_NETWORK_ERROR) {
// 错误码7002表示网络异常
showLog("network error");
// 此处您可提示玩家检查网络,请不要重复调用init接口,否则断网情况下可能会造成手机高耗电。
} else if (statusCode == 907135003) {
// 907135003表示玩家取消HMS Core升级或组件升级
showLog("init statusCode=" + statusCode);
init();
} else {
// 在此处实现其他错误码的处理
}
}
}
});
}
/**
* 登录,返回已登录此应用的华为帐号登录信息(或者错误信息)
*/
List<Scope> scopes = new ArrayList<>();
scopes.add(GameScopes.DRIVE_APP_DATA);
AccountAuthParams mAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).setScopeList(scopes).createParams();
private void signIn(){
showLog("begin login and current hasInit=" + hasInit);
// 一定要在init成功后,才可以调用登录接口
Task<AuthAccount> authAccountTask = AccountAuthManager.getService(this, mAuthParams).silentSignIn();
authAccountTask.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
@Override
public void onSuccess(AuthAccount authAccount) {
showLog("signIn success");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
int statusCode = apiException.getStatusCode();
if (2002 == statusCode){
showLog("start getSignInIntent");
signInNewWay();
}else {
showLog("signIn failed:" + statusCode);
}
}
}
});
}
/**
* 获取到华为帐号登录授权页面的Intent,并通过调用startActivityForResult(Intent, int)打开华为帐号登录授权页面。
*/
private void signInNewWay() {
Intent intent = AccountAuthManager.getService(MainActivity.this, mAuthParams).getSignInIntent();
startActivityForResult(intent, SIGN_IN_INTENT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null){
return;
}
if (SIGN_IN_INTENT == requestCode) {
handleSignInResult(data);
}else {
showLog("unknown requestCode in onActivityResult");
}
}
/**
* 登录授权的结果响应处理方法
* @param data Data
*/
private void handleSignInResult(Intent data) {
String jsonSignInResult = data.getStringExtra("HUAWEIID_SIGNIN_RESULT");
if (TextUtils.isEmpty(jsonSignInResult)) {
showLog("SignIn result is empty");
return;
}
try {
AccountAuthResult signInResult = new AccountAuthResult().fromJson(jsonSignInResult);
if (0 == signInResult.getStatus().getStatusCode()) {
showLog("Sign in success.");
} else {
showLog("Sign in failed: " + signInResult.getStatus().getStatusCode());
}
} catch (JSONException var7) {
showLog("Failed to convert json from signInResult.");
}
}
private static final String TAG = "MainActivity";
/**
* 打印日志
* @param msg
*/
private void showLog(String msg){
Log.d(TAG,msg);
}
在使用游戏存档接口的能力前都需要先调用Games.getArchiveClient获取ArchivesClient实例。示例代码如下:
ArchivesClient client = Games.getArchiveClient(this);
字段名称 | 字段描述 |
description | 存档描述。 |
playedTime | 游戏时长。 |
progress | 游戏进度。 |
isCache | 是否支持本地缓存。选中"YES"表示支持本地缓存,选中"NO"表示不支持本地缓存。 |
hasImage | 是否有封面图面,此处显示的是一个固定的图片,可以根据实际业务需求修改。选中"YES"表示有封面图片,选中"NO"表示没有封面图片。 |
submit | 点击此按钮,调用新建存档接口。 |
// 布局代码
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="@+id/tv_des"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="description:"/>
<EditText
android:id="@+id/et_des"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/tv_des"
android:layout_toRightOf="@+id/tv_des"
android:hint="Please enter the description."
android:textSize="16sp" />
<TextView
android:id="@+id/tv_playedTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/et_playedTime"
android:text="playedTime:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_playedTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/et_des"
android:layout_alignLeft="@+id/et_des"
android:layout_marginTop="20dp"
android:hint="Please enter the playedTime."
android:textSize="16sp" />
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/et_progress"
android:textSize="16sp"
android:text="progress:"/>
<EditText
android:id="@+id/et_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/et_playedTime"
android:layout_alignLeft="@+id/et_des"
android:layout_marginTop="20dp"
android:hint="Please enter the progress."
android:textSize="16sp" />
<TextView
android:id="@+id/tv_isSupportCache"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/rg_isCache"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:text="isCache:"/>
<RadioGroup
android:id="@+id/rg_isCache"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_des"
android:layout_below="@+id/et_progress"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_cache_yes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="YES"/>
<RadioButton
android:id="@+id/rb_cache_no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="NO"/>
</RadioGroup>
<TextView
android:id="@+id/tv_hasImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/rg_hasImage"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:text="hasImage:"/>
<RadioGroup
android:id="@+id/rg_hasImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_des"
android:layout_below="@+id/rg_isCache"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_hasImage_yes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="YES"/>
<RadioButton
android:id="@+id/rb_hasImage_no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="NO"/>
</RadioGroup>
<ImageView
android:id="@+id/iv_cover_pic"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="@+id/rg_hasImage"
android:layout_centerHorizontal="true"
android:src="@mipmap/cover_picture" />
<Button
android:id="@+id/submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/iv_cover_pic"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="submit"/>
</RelativeLayout>
</ScrollView>
String description = etDes.getText().toString();
long playedTime = Long.parseLong(TextUtils.isEmpty(etPlayedTime.getText().toString()) ? "0": etPlayedTime.getText().toString());
long progress = Long.parseLong(TextUtils.isEmpty(etProgress.getText().toString()) ? "0" : etProgress.getText().toString());
ArchiveDetails archiveDetails = new ArchiveDetails.Builder().build();
archiveDetails.set((progress + description + playedTime).getBytes());
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.cover_picture);
ArchiveSummaryUpdate.Builder builder = new ArchiveSummaryUpdate.Builder();
builder.setActiveTime(playedTime)
.setCurrentProgress(progress)
.setDescInfo(description);
ArchiveSummaryUpdate archiveSummaryUpdate;
if (hasImage){
archiveSummaryUpdate = builder.setThumbnail(bitmap)
.setThumbnailMimeType("png").build();
}else {
archiveSummaryUpdate = builder.build();
}
Task<ArchiveSummary> archiveSummaryTask = client.addArchive(archiveDetails, archiveSummaryUpdate, isCache);
archiveSummaryTask.addOnSuccessListener(new OnSuccessListener<ArchiveSummary>() {
@Override
public void onSuccess(ArchiveSummary archiveSummary) {
if (archiveSummary != null){
String fileName = archiveSummary.getFileName();
String archiveId = archiveSummary.getId();
String descInfo = archiveSummary.getDescInfo();
showLog("create archive success descInfo:" + descInfo + ",fileName:" + fileName+ ",archiveId:" + archiveId);
finish();
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException){
ApiException apiException = (ApiException) e;
int statusCode = apiException.getStatusCode();
if(statusCode == 7216){
Log.e(TAG,"Check whether the format of the archive cover image is correct.");
}else if(statusCode == 7218){
Log.e(TAG,"The game service is disabled.");
}else if(statusCode == 7013){
// 未登录华为帐号 You have not logged in to your Huawei ID.
signIn();
}else if(statusCode == 7213){
//存档个数达到上限 The number of archived files has reached the upper limit.
Log.e(TAG,"The number of archived files has reached the upper limit.");
}else{
Log.e(TAG,"statusCode:"+ statusCode);
}
}
}
});
private static final String TAG = "CreateArchiveActivity";
/**
* Print logs
* 打印日志
* @param msg
*/
private void showLog(String msg){
Log.d(TAG,msg);
}
玩家可以在存档入口选择浏览存档记录,此时游戏需要展示所有的存档记录供用户选择。存档记录选择界面的展示方法分为2种:
Task<Intent> showArchiveListIntentTask = mClient.getShowArchiveListIntent("游戏存档", true, true, -1);
showArchiveListIntentTask.addOnSuccessListener(new OnSuccessListener<Intent>() {
@Override
public void onSuccess(Intent intent) {
if (intent != null){
startActivityForResult(intent,1);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException){
ApiException apiException = (ApiException) e;
Log.e(TAG, "statusCode:" + apiException.getStatusCode());
}
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null){
return;
}
if (1 == requestCode){
if (data.hasExtra(ArchiveConstants.ARCHIVE_SELECT)){
Bundle bundle = data.getParcelableExtra(ArchiveConstants.ARCHIVE_SELECT);
Task<ArchiveSummary> archiveSummaryTask = mClient.parseSummary(bundle);
archiveSummaryTask.addOnSuccessListener(new OnSuccessListener<ArchiveSummary>() {
@Override
public void onSuccess(ArchiveSummary archiveSummary) {
if (archiveSummary != null){
String archiveId = archiveSummary.getId();
String descInfo = archiveSummary.getDescInfo();
String fileName = archiveSummary.getFileName();
showLog("get archive info success archiveId:" + archiveId + ",fileName:" + fileName+ ",descInfo:" + descInfo);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException){
ApiException apiException = (ApiException) e;
Log.e(TAG, "statusCode:" + apiException.getStatusCode()); }
}
});
}else if (data.hasExtra(ArchiveConstants.ARCHIVE_ADD)){
// 调用addArchive添加存档
}
}else {
showLog("unknown requestCode in onActivityResult");
}
}
private static final String TAG = "MainActivity";
/**
* Print logs
* 打印日志
* @param msg
*/
private void showLog(String msg){
Log.d(TAG,msg);
}
// 主界面布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_archive"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
// 列表中每个条目的布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="15dp"
android:paddingVertical="10dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_archive_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/tv_archive_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/black"
android:layout_marginLeft="15dp"/>
</LinearLayout>
Task<List<ArchiveSummary>> archiveSummaryListTask = mArchivesClient.getArchiveSummaryList(false);
archiveSummaryListTask.addOnSuccessListener(new OnSuccessListener<List<ArchiveSummary>>() {
@Override
public void onSuccess(List<ArchiveSummary> archiveSummaries) {
if (archiveSummaries != null){
mSummaries = archiveSummaries;
Log.i(TAG, " archiveSummaries size" + archiveSummaries.size());
mArchiveAdapter = new ArchiveAdapter(archiveSummaries,DisplayArchiveUserselfActivity.this,DisplayArchiveUserselfActivity.this);
rcv_archive.setAdapter(mArchiveAdapter);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException){
ApiException apiException = (ApiException) e;
Log.e(TAG, "statusCode:" + apiException.getStatusCode()); }
}
});
// 适配器代码截取数据处理部分
ArchiveSummary archiveSummary = summaries.get(position);
holder.tv_archive_desc.setText(archiveSummary.getDescInfo());
if (archiveSummary.hasThumbnail()){
Task<Bitmap> thumbnailTask = mClient.getThumbnail(archiveSummary.getId());
thumbnailTask.addOnSuccessListener(new OnSuccessListener<Bitmap>() {
@Override
public void onSuccess(Bitmap bitmap) {
holder.iv_archive_icon.setImageBitmap(bitmap);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException){
ApiException apiException = (ApiException) e;
Log.e("ArchiveAdapter","statusCode:" + apiException.getStatusCode());
}
}
});
}
打开游戏存档是指玩家进入游戏后加载之前提交的存档继续进行游戏。如果您打开华为应用助手展示的存档,华为应用助手会自动加载打开游戏存档功能;如果您打开自行展示的存档,请参考本章节完成打开游戏存档功能。建议调用ArchivesClient.getArchiveSummaryList方法获取的存档,不要打开本地缓存的存档。
在游戏存档时可能存在同一个帐号在多个设备中同时存档的情况,如果设备因网络问题存档延时,则可能会发生数据冲突。当更新存档或打开存档时发现两份存档的存档属性对比存在不一致时,华为游戏服务器会返回对应的冲突结果给您,并允许您选择使用其中某份存档作为最终使用的存档,或者也允许您自主混合存档数据作为最终使用的存档。
mArchiveAdapter.setOnItemClickListener(new ArchiveAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
ArchiveSummary archiveSummary = mSummaries.get(position);
Task<OperationResult> operationResultTask = mArchivesClient.loadArchiveDetails(archiveSummary, ArchiveConstants.STRATEGY_TOTAL_PROGRESS);
operationResultTask.addOnSuccessListener(new OnSuccessListener<OperationResult>() {
@Override
public void onSuccess(OperationResult operationResult) {
Log.i(TAG, "isDifference:" + ((operationResult == null) ? "" : operationResult.isDifference()));
if (operationResult != null && !operationResult.isDifference()) {
Archive archive = operationResult.getArchive();
if (archive != null && archive.getSummary() != null) {
ArchiveSummary summary = archive.getSummary();
String archiveId = summary.getId();
String descInfo = summary.getDescInfo();
String fileName = summary.getFileName();
Log.i(TAG, "get archive info success archiveId:" + archiveId + ",fileName:" + fileName+ ",descInfo:" + descInfo);
}
} else {
//处理冲突
Log.i(TAG, "Handling Conflicts");
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
Log.e(TAG, "statusCode:" + apiException.getStatusCode());
}
}
});
}
});
archive.getDetails().get();
恭喜您,您已经成功完成了Codelab并学到了:
您可以阅读下面链接,了解更多相关的信息。
本Codelab中所用API请参考游戏服务的存档相关API介绍
游戏存档官方文档介绍,请参考存档
相关错误码说明,请参考错误码
源码下载地址:源码下载