什么是华为游戏服务?

游戏服务是华为向开发者提供的能够快速开发游戏应用的服务。通过华为游戏服务,开发者可以使用用户的华为帐号登录游戏,从而迅速推广游戏,共享华为庞大的用户价值。

您将建立什么?

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

您将学会到什么

您需要什么?

开发环境及技能要求:

运行终端要求:

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

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

打开游戏服务

  1. AppGallery Connect主页选择"我的项目",在项目列表中选择刚刚创建的应用,在"项目设置"页面中选择"API管理"。
  2. 点击 "HUAWEI Account"和"Game Service"后面的开关打开帐号和游戏服务。

集成SDK

针对Android Studio开发环境,华为提供了Maven仓集成方式的HMS Core 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 'https://developer.huawei.com/repo/'} } } buildscript { repositories { google() jcenter() //配置如下地址 maven {url 'https://developer.huawei.com/repo/'} } } buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.4.2' //配置如下地址 classpath 'com.huawei.agconnect:agcp:1.4.1.300' } }
  6. 打开Android Studio应用级build.gradle文件。
  7. 在对应位置配置以下内容,其中:
    hwid的{version}替换为最新帐号服务版本号,参见版本更新说明
    game的{version}替换为最新游戏服务版本号,参见版本更新说明
    //配置如下地址 apply plugin: 'com.huawei.agconnect' dependencies { //配置如下地址 implementation 'com.huawei.hms:hwid:{version}' implementation 'com.huawei.hms:game:{version}' }
  8. 点击界面上的"Sync Now"链接同步已完成的配置。

配置混淆脚本

  1. 打开Android Studio工程的混淆配置文件proguard-rules.pro。
  2. 加入混淆配置。
    -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.HiAnalyticsTools{ public static void enableLog(); public static void enableLog(int); } -keep class com.huawei.hms.analytics.HiAnalyticsInstance{*;} -keep class com.huawei.hms.analytics.HiAnalytics{*;}

游戏应用与华为游戏服务交互的功能主要涉及游戏登录和游戏防沉迷,本次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.common.ApiException; import com.huawei.hms.jos.JosApps; import com.huawei.hms.jos.JosAppsClient; import com.huawei.hms.jos.games.Games; import com.huawei.hms.jos.games.PlayersClient; import com.huawei.hms.jos.games.buoy.BuoyClient; import com.huawei.hms.jos.games.player.Player; import com.huawei.hms.jos.games.player.PlayerExtraInfo; import com.huawei.hms.support.hwid.HuaweiIdAuthManager; import com.huawei.hms.support.hwid.request.HuaweiIdAuthParams; import com.huawei.hms.support.hwid.request.HuaweiIdAuthParamsHelper; import com.huawei.hms.support.hwid.result.AuthHuaweiId; import com.huawei.hms.support.hwid.service.HuaweiIdAuthService;

步骤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在应用启动的第一个Activity中,调用JosAppsClient的init方法初始化游戏SDK。

/** * SDK初始化 */ private void init() { JosAppsClient appsClient = JosApps.getJosAppsClient(this); appsClient.init(); showLog("init success"); }

步骤4 调用HuaweiIdAuthManager的getService方法初始化HuaweiIdAuthService对象,并调用HuaweiIdAuthService的silentSignIn方法实现静默登录。如果静默登录失败,调用HuaweiIdAuthService的getSignInIntent方法显式登录。

/** * 游戏登录需要先调用华为账号认证登录完成之后,再调用getcurrentPlayer接口获取游戏玩家信息 * 1.先调用华为账号登录接口的静默登录接口,此接口对于已经授权登录过的应用不会再次拉起登录页面。 * 2.静默登录失败一般是由于需要首次登录需要授权,此时在回调中调用显式登录接口拉起登录授权页面进行登录认证。 * 登录接口会在onActivity生命周期中获取,可在此时调用游戏获取玩家信息接口。 */ public void signIn() { Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.getService(this, getHuaweiIdParams()).silentSignIn(); authHuaweiIdTask.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() { @Override public void onSuccess(AuthHuaweiId authHuaweiId) { Log.i(TAG, "silentsignIn success"); Log.i(TAG, "display:" + authHuaweiId.getDisplayName()); login(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException apiException = (ApiException) e; Log.i(TAG, "signIn failed:" + apiException.getStatusCode()); Log.i(TAG, "start getSignInIntent"); // 显式登录,在生命周期onActivityResult中获取接收登录结果 HuaweiIdAuthService service = HuaweiIdAuthManager.getService(MainActivity.this, getHuaweiIdParams()); startActivityForResult(service.getSignInIntent(), 6013); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 6013) { 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 { HuaweiIdAuthResult signInResult = new HuaweiIdAuthResult().fromJson(jsonSignInResult); if (0 == signInResult.getStatus().getStatusCode()) { showLog("signIn success."); showLog("signIn result: " + signInResult.toJson()); } else { showLog("signIn failed: " + signInResult.getStatus().getStatusCode()); } } catch (JSONException var7) { showLog("Failed to convert json from signInResult."); } } } public HuaweiIdAuthParams getHuaweiIdParams() { return new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).setIdToken().createParams(); }

步骤5 获取玩家信息。

/** * 获取游戏玩家用户信息 */ public void login() { playersClient = Games.getPlayersClient(this); Task<Player> playerTask = playersClient.getCurrentPlayer(); playerTask.addOnSuccessListener(new OnSuccessListener<Player>() { @Override public void onSuccess(Player player) { playerID = player.getPlayerId(); Log.i(TAG, "getPlayerInfo Success, player info: " + player.getPlayerId()); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // 获取玩家信息失败 if (e instanceof ApiException) { Log.e(TAG, "getPlayerInfo failed, status: " + ((ApiException) e).getStatusCode()); } } }); }

步骤1 进入游戏,游戏开始事件上报。

/** * 防沉迷事件开始时间上报。 */ private void timeReportStart() { if (playersClient == null) { Log.i(TAG, "playersClient is null, please init playersClient first"); login(); return; } if (playerID == null) { Log.i(TAG, "playerID is null, please getcurrentPlayer login first"); login(); return; } String uid = UUID.randomUUID().toString(); Task<String> task = playersClient.submitPlayerEvent(playerID, uid, "GAMEBEGIN"); task.addOnSuccessListener(new OnSuccessListener<String>() { @Override public void onSuccess(String jsonRequest) { try { JSONObject data = new JSONObject(jsonRequest); sessionId = data.getString("transactionId"); } catch (JSONException e) { showLog("parse jsonArray meet json exception"); return; } showLog("submitPlayerEvent traceId: " + jsonRequest); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }

步骤2 当游戏结束或暂停时上报结束事件。

/** * 防沉迷事件结束时间上报 * sessionId: 每次Begin上报"开始"事件成功后会在回调中返回此次上报事件的标识,用于"结束"事件的上报闭环统计此段游戏时长。 */ private void timeReportEnd() { if (playersClient == null) { Log.i(TAG, "playersClient is null, please init playersClient first"); login(); return; } if (playerID == null) { Log.i(TAG, "playerID is null, please getcurrentPlayer login first"); login(); return; } if (sessionId == null) { Log.i(TAG, "sessionId is null, please submitPlayerEvent Begin first"); login(); return; } Task<String> task = playersClient.submitPlayerEvent(playerID, sessionId, "GAMEEND"); task.addOnSuccessListener(new OnSuccessListener<String>() { @Override public void onSuccess(String s) { showLog("submitPlayerEvent traceId: " + s); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }

步骤3 游戏定期调用PlayersClient.getPlayerExtraInfo方法查询玩家附加信息。服务器允许的最高频率为10分钟查询一次,一般建议15分钟查询一次。

/** * 查询防沉迷事件上报详情 * 如果玩家未成年,则需使用PlayerExtraInfo.getPlayerDuration查看其当前的累计游戏时长,该游戏 时长为玩家当天最新的累计游戏时长。 * 游戏需要根据累计游戏时长进行未成年玩家的防沉迷监控,具体规则由开发者自行定义。 */ private void getPlayerExfra() { if (playersClient == null) { Log.i(TAG, "playersClient is null, please init playersClient first"); login(); return; } if (sessionId == null) { Log.i(TAG, "sessionId is null, please submitPlayerEvent Begin first"); login(); return; } Task<PlayerExtraInfo> task = playersClient.getPlayerExtraInfo(sessionId); task.addOnSuccessListener(new OnSuccessListener<PlayerExtraInfo>() { @Override public void onSuccess(PlayerExtraInfo extra) { if (extra != null) { showLog("IsRealName: " + extra.getIsRealName() + ", IsAdult: " + extra.getIsAdult() + ", PlayerId: " + extra.getPlayerId() + ", PlayerDuration: " + extra.getPlayerDuration()); } else { showLog("Player extra info is empty."); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { String result = "rtnCode:" + ((ApiException) e).getStatusCode(); showLog(result); } } }); }
  1. 参考创建测试帐号添加您的华为帐号作为测试帐号。
  2. 运行Android Studio工程生成APK包,并在测试手机中安装APK包。
  3. 测试登录功能。
  4. 在应用首页中依次点击"Init"、"SignIn"和"GetCurrentPlayer",检查是否能够运行成功。

  5. 测试防沉迷功能。
  6. 在应用首页中依次点击"Init"、"SignIn"、"GetCurrentPlayer"和"SubmitPlayerEvent_Begin",检查是否能够运行成功。

    点击"SubmitPlayerEvent_End"、"GetPlayerExtraInfo",测试防沉迷其他功能,所有接口均有输出结果日志。

  7. 查看logcat日志。
  8. Tag:Game_codeLab

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

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

源码下载

已复制代码