什么是华为游戏服务?

游戏服务是华为向开发者提供的能够快速开发游戏应用的服务。通过华为游戏服务,开发者可以使用用户的华为帐号登录游戏,从而迅速推广游戏,共享华为庞大的用户价值。
另外,为了激励玩家深入发掘游戏并提高其游戏水平,游戏可以提供成就功能。华为游戏服务能够帮助开发者快速展示成就、管理成就。

您将建立什么?

在本次Codelab中,您将建立一个能够具备简单游戏交互功能的Android应用程序,您的应用程序将包含:

您将学到什么

您需要什么?

开发环境及技能要求:

运行终端要求:

集成HUAWEI HMS能力,需要完成以下准备工作

具体操作,请按照《HMS 3.0集成准备》中详细说明来完成。

打开游戏服务

  1. 在AppGallery Connect的应用页面中点击"开发"页签,点击"概览"后的图标,选择"API管理"。
  2. 点击"In-App Purchase"、"Huawei ID"和"Game Services"后面的开关打开支付、帐号和游戏服务。

集成SDK

针对Android Studio开发环境,华为提供了maven仓集成方式的HMS SDK包,开发游戏前需集成SDK到您的Android Studio项目中。

  1. 在AppGallery Connect的应用页面中点击"开发"页签,选择"概览"。
  2. 单击"应用"栏下的"agconnect-services.json"下载配置文件。
  3. 将"agconnect-services.json"文件拷贝到应用级根目录下。
  4. 打开Android Studio项目级build.gradle文件。
  5. 在build.gradle文件的对应位置配置以下内容。
    allprojects { repositories { google() jcenter() //配置如下地址 maven {url 'http://developer.huawei.com/repo/'} } } buildscript { repositories { google() jcenter() //配置如下地址 maven {url 'http://developer.huawei.com/repo/'} } } buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.4.0' //配置如下地址 classpath 'com.huawei.agconnect:agcp:1.0.0.300' } }
  6. 打开Android Studio应用级build.gradle文件。
  7. 在对应位置配置以下内容,其中{version}替换为HMS SDK版本号,当前为3.0.2.300。
    //配置如下地址 apply plugin: 'com.huawei.agconnect' dependencies { //配置如下地址 implementation 'com.huawei.hms:hwid:{version}' implementation 'com.huawei.hms:iap:{version}' implementation 'com.huawei.hms:game:{version}' }
  8. 点击界面上的"Sync Now"链接同步已完成的配置。

配置混淆脚本

  1. 打开Android Studio工程的混淆配置文件proguard-rules.pro。
  2. 加入混淆配置。
    -ignorewarning -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.**{*;}

游戏应用与华为游戏服务交互的功能主要涉及游戏登录和游戏成就,本次Codelab中您可以在您的Android Studio工程中创建一个布局页面,参照下图进行UI设计。

步骤1 引入游戏相关类。

import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hmf.tasks.Task; import com.huawei.hms.R; import com.huawei.hms.api.HuaweiApiClient; import com.huawei.hms.auth.api.signin.HuaweiIdSignIn; import com.huawei.hms.auth.api.signin.HuaweiIdSignInResult; import com.huawei.hms.common.ApiException; import com.huawei.hms.game.achievement.AchievementListActivity; import com.huawei.hms.jos.AppUpdateClient; import com.huawei.hms.jos.JosApps; import com.huawei.hms.jos.JosAppsClient; import com.huawei.hms.jos.games.AchievementsClient; import com.huawei.hms.jos.games.Games; import com.huawei.hms.jos.games.Player; import com.huawei.hms.jos.games.PlayersClient; import com.huawei.hms.support.api.client.PendingResult; import com.huawei.hms.support.api.client.ResultCallback; import com.huawei.hms.support.api.client.Status; import com.huawei.hms.support.api.entity.core.CommonCode; import com.huawei.hms.support.api.game.CertificateIntentResult; import com.huawei.hms.support.api.game.HuaweiGame; import com.huawei.hms.support.api.game.PlayerCertificationInfo; import com.huawei.hms.support.api.game.ShowFloatWindowResult; import com.huawei.hms.support.api.hwid.HuaweiIdSignInOptions; import com.huawei.hms.support.api.hwid.SignInHuaweiId;

步骤2 在Application的onCreate方法中添加注册Activity的回调监听。

public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); HuaweiMobileServicesUtil.setApplication(this); } @Override public void onTerminate() { super.onTerminate(); } }

步骤3 启动时初始化游戏SDK。

@OnClick(R.id.btn_init) public void init() { JosAppsClient appsClient = JosApps.getJosAppsClient(this, getSignInHuaweiId()); appsClient.init(); showLog("init success"); }

步骤4 显示登录。

@OnClick(R.id.btn_sign_in) public void signIn() { HuaweiIdSignInOptions huaweiIdSignInOptions = new HuaweiIdSignInOptions.Builder(HuaweiIdSignInOptions.DEFAULT_GAMES_SIGN_IN).build(); Task<SignInHuaweiId> signInHuaweiIdTask = HuaweiIdSignIn.getClient(GameApiActivity.this, huaweiIdSignInOptions).silentSignIn(); signInHuaweiIdTask.addOnSuccessListener(new OnSuccessListener<SignInHuaweiId>() { @Override public void onSuccess(SignInHuaweiId signInHuaweiId) { showLog("signIn success"); showLog("displayName:" + signInHuaweiId.getDisplayName()); mSignInHuaweiId = signInHuaweiId; } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException apiException = (ApiException) e; showLog("silentSignIn failed:" + apiException.getStatusCode()); showLog("start signIn in new way launch signIn page"); signInNewWay(); } } }); } public void signInNewWay() { HuaweiIdSignInOptions huaweiIdSignInOptions = new HuaweiIdSignInOptions.Builder(HuaweiIdSignInOptions.DEFAULT_GAMES_SIGN_IN).build(); Intent intent = HuaweiIdSignIn.getClient(GameApiActivity.this, huaweiIdSignInOptions).getSignInIntent(); startActivityForResult(intent, SIGN_IN_INTENT); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (SIGN_IN_INTENT == requestCode) { handleSignInResult(data); } else { showLog("unknown requestCode in onActivityResult"); } } private void handleSignInResult(Intent data) { if (null == data) { showLog("signIn inetnt is null"); return; } String jsonSignInResult = data.getStringExtra("HUAWEIID_SIGNIN_RESULT"); if (TextUtils.isEmpty(jsonSignInResult)) { showLog("signIn result is empty"); return; } try { HuaweiIdSignInResult signInResult = new HuaweiIdSignInResult().fromJson(jsonSignInResult); if (0 == signInResult.getStatus().getStatusCode()) { showLog("signIn success."); showLog("signIn result: " + signInResult.toJson()); mSignInHuaweiId = signInResult.getSignInHuaweiId(); } else { showLog("signIn failed: " + signInResult.getStatus().getStatusCode()); mSignInHuaweiId = null; } } catch (JSONException var7) { showLog("Failed to convert json from signInResult."); mSignInHuaweiId = null; } }

步骤5 获取玩家信息。

@OnClick(R.id.btn_get_player) public void getCurrentPlayer() { PlayersClient client = Games.getPlayersClient(this, getSignInHuaweiId()); Task<Player> task = client.getCurrentPlayer(); task.addOnSuccessListener(new OnSuccessListener<Player>() { @Override public void onSuccess(Player player) { String result = "displayName:" + player.getDisplayName() + "\n" + "playerId:" + player.getPlayerId() + "\n" + "playerlevel:" + player.getLevelInfo().getCurrentLevel().getLevelNumber() + "\n" + "ts:" + player.getSignTs() + "\n" + "playerSign:" + player.getPlayerSign(); showLog(result); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }

创建成就

  1. 登录AppGallery Connect 网站,选择"我的应用"。
  2. 点击对应的应用进入应用开发界面。
  3. 选择"运营"页签,在左侧导航栏选择"产品运营 > 游戏成就",点击"新建"。
  4. 配置成就信息,完成后点击"保存"。
    语言:根据实际情况选择。
    名称:成就名称。
    说明:成就的简要说明。
    图标:上传一个512x512px的png或jpg图片。
    分步成就:选中"用户解锁成就之前,需要完成预设步骤",然后在"设置步骤"栏输入成就的步数。
    初始状态:可选"显示"或"隐藏状态"。
    列表顺序:当前成就在所有成就中排列的顺序。
  5. 在成就列表中的"ID"列获取成就ID。

开发步骤

步骤1 拉起应用助手的成就列表页面。

@OnClick(R.id.btn_get_achieve_intent) public void getAchievementIntent() { AchievementsClient client = Games.getAchievementsClient(this, getSignInHuaweiId()); Task<Intent> task = client.getAchievementsIntent(); task.addOnSuccessListener(new OnSuccessListener<Intent>() { @Override public void onSuccess(Intent intent) { if (intent == null) { showLog("intent = null"); } else { try { startActivityForResult(intent, 1); } catch (Exception e) { showLog("Achievement Activity is Invalid"); } } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }

步骤2 APP自行加载当前玩家所有成就数据。
跳转到自定义的成就展示页面AchievementListActivity。

@OnClick(R.id.btn_load_achievement) public void loadAchievement() { loadAchievement(true); } private void loadAchievement(boolean forceReload) { if (mSignInHuaweiId == null) { showLog("please signIn first"); return; } String jString; try { jString = mSignInHuaweiId.toJson(); } catch (JSONException e) { showLog("mSignInHuaweiId toJson error"); return; } Intent intent = new Intent(GameApiActivity.this, AchievementListActivity.class); intent.putExtra("forceReload", forceReload); intent.putExtra("mSign", jString); startActivity(intent); }

AchievementListActivity中加载成就数据示例代码如下:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_achievement_list); mContext = this; ButterKnife.bind(mContext); initData(); requestData(); } private void initData() { Intent intent = getIntent(); forceReload = intent.getBooleanExtra("forceReload", false); String mSignString =intent.getStringExtra("mSign"); try { signInHuaweiId =SignInHuaweiId.fromJson(mSignString); } catch (JSONException e) { showLog("SignInHuaweiId.fromJson error"); } client = Games.getAchievementsClient(this, signInHuaweiId); } private void requestData() { Task<AnnotatedData<AchievementBuffer>> task = client.load(forceReload); task.addOnSuccessListener(new OnSuccessListener<AnnotatedData<AchievementBuffer>>() { @Override public void onSuccess(AnnotatedData<AchievementBuffer> data) { AchievementBuffer achievementBuffer = data.get(); if (achievementBuffer == null) { showLog("achievementBuffer is null"); return; } Iterator<Achievement> iterator = achievementBuffer.iterator(); achievements.clear(); while (iterator.hasNext()) { Achievement achievement = iterator.next(); achievements.add(achievement); } LinearLayoutManager layoutManager = new LinearLayoutManager(mContext); recyclerView.setLayoutManager(layoutManager); AchievementListAdapter adapter = new AchievementListAdapter(mContext, achievements, mContext); recyclerView.setAdapter(adapter); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }

点击成就后展示成就详情。

@Override public void onItemClick(int postion) { Intent intent = new Intent(this, AchievementDetailActivity.class); Achievement achievement = achievements.get(postion); intent.putExtra("achievementName",achievement.getName()); intent.putExtra("achievementDes",achievement.getDescription()); intent.putExtra("unlockedImageUri",achievement.getUnlockedImageUri()); intent.putExtra("rvealedImageUri",achievement.getRevealedImageUri()); startActivity(intent); }

步骤3 揭秘隐藏成就。

@Override public void reveal(String achievementId, boolean isChecked) { if (!isChecked){ client.reveal(achievementId); }else { performRevealImmediate(client,achievementId); } } private void performRevealImmediate(AchievementsClient client, String achievementId) { Task<Void> task = client.revealImmediate(achievementId); task.addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void v) { showLog("revealAchievemen isSucess"); requestData(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog("can not reveal:"+result); } } }); }

步骤4 增加成就当前已完成的步数。

@Override public void increment(String achievementId, boolean isChecked) { if (!isChecked){ client.increment(achievementId,1); }else { performIncrementImmediate(client,achievementId,1); } } private void performIncrementImmediate(AchievementsClient client, String achievementId, int stepsNum) { Task<Boolean> task = client.incrementImmediate(achievementId, stepsNum); task.addOnSuccessListener(new OnSuccessListener<Boolean>() { @Override public void onSuccess(Boolean isSucess) { if (isSucess) { showLog("incrementAchievement isSucess"); requestData(); }else { showLog("achievement can not increment"); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog("achievement has unlocked:"+result); } } }); }

步骤5 设置成就当前已完成的步数。

@Override public void setStep(String achievementId, boolean isChecked) { if (!isChecked){ client.setSteps(achievementId,3); }else { performSetStepsImmediate(client,achievementId,3); } } private void performSetStepsImmediate(AchievementsClient client, String achievementId, int stepsNum) { Task<Boolean> task = client.setStepsImmediate(achievementId, stepsNum); task.addOnSuccessListener(new OnSuccessListener<Boolean>() { @Override public void onSuccess(Boolean isSucess) { if (isSucess) { showLog("setAchievementSteps isSucess"); } else { showLog("achievement can not setSteps"); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog("achievement has unlocked: "+result); } } }); }

步骤6 解锁成就。

@Override public void Unlock(String achievementId, boolean isChecked) { if (!isChecked){ client.unlock(achievementId); }else { performUnlockImmediate(client,achievementId); } } private void performUnlockImmediate(AchievementsClient client, String achievementId) { Task<Void> task = client.unlockImmediate(achievementId); task.addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void v) { showLog("UnlockAchievemen isSucess"); requestData(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog("achievement has unlocked:"+result); } } }); }
  1. 参考创建测试帐号添加您的华为帐号作为测试帐号。
  2. 运行Android Studio工程生成APK包,并在测试手机中安装APK包。
  3. 测试登录功能。
  4. 在应用首页中依次点击"Init"、"SignIn"和"GetCurrentPlayer",检查是否能够运行成功。

  5. 测试成就功能。
  6. 在首页点击"LoadAchievement"按钮,测试是否能够展示成就列表。

    点击成就图标,测试是否能够展示成就详情。

    点击"Unlock"、"IncrementSteps"、"SetSteps",测试成就其他功能。

祝贺您,您已经成功地构建了您的第一个游戏应用程序,并学到了:

成就的概念介绍

游戏服务的相关API介绍
本Codelab中所用demo源码下载地址如下:

源码下载

已复制代码