Overview

In accordance with the latest notice issued by National Press and Publication Administration, all online game providers in the Chinese mainland should integrate the identity verification system for the game addiction prevention function, offer online game services to minors only from 20:00 to 21:00 on Fridays, weekends, and legal holidays, and set an upper limit on the payment and top-up amounts for minors.
Huawei provides a complete set of control logics for you to easily implement the game addiction prevention function. This codelab will show you a hands-on example of how to sign in to a game using Account Kit, and efficiently build the game addiction prevention function for the game.

What You Will Create

In this codelab, you will create a simple Android game. The game will:

What You Will Learn

In this codelab, you will learn how to:

Hardware Requirements

Software Requirements

Required Knowledge

To integrate HMS Core capabilities, you must complete the following preparations:

  1. In AppGallery Connect, click My projects, click your project card, and go to Project settings > Manage APIs.
  2. Toggle the switches for Account Kit and Game Service on. You are advised to test the functions of Game Service after 15 minutes after the switch is enabled.

Adding the AppGallery Connect Configuration File of Your App

  1. In AppGallery Connect, click My projects, and select your app.
  2. Go to Project settings > General information. In the App information area, download the agconnect-services.json file.
  3. Copy the agconnect-services.json file to the app-level directory of your Android Studio project.

Configuring the Maven Repository Address for the HMS Core SDK

The procedure for configuring the Maven repository address in Android Studio is different for Gradle plugin earlier than 7.0, Gradle plugin 7.0, and Gradle plugin 7.1 or later. Click a relevant link below to find the configuration procedure for the specific Gradle plugin version.

Gradle plugin earlier than 7.0

Gradle plugin 7.0

Gradle plugin 7.1 or later

Adding Build Dependencies

  1. Open the build.gradle file in the app-level directory.
  2. Add the dependencies in the dependencies block.
    dependencies { implementation 'com.huawei.hms:hwid:{version}' implementation 'com.huawei.hms:game:{version}' }
  3. Add the AppGallery Connect plugin configuration using either of the following method:
    Method 1: Add the following information under the declaration in the file header:
    apply plugin: 'com.huawei.agconnect'

    Method 2: Add the plugin configuration in the plugins block.

    plugins { id 'com.android.application' // Add the following configuration. id 'com.huawei.agconnect' }
  4. Click Sync Now to synchronize the configuration.

Configuring Obfuscation Scripts

Before compiling your app, configure the obfuscation scripts as follows:

  1. Open the obfuscation configuration file proguard-rules.pro of your Android Studio project.
  2. Add the obfuscation configurations.
    -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{*;}
  3. Configure the keep.xml file as follows to keep layout resources if you have enabled R8 resource shrinking (with shrinkResources being set to true in the project-level build.gradle file) and strict reference checks (with shrinkMode being set to strict in the res/raw/keep.xml file). Not keeping layout resources will lead to app rejection during release to AppGallery.
    <?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" />

In this codelab, you can create the following layout page, with three buttons required: Init for calling the initialization API, SignIn for calling the sign-in API, and GetGamePlayer for calling the API for obtaining player information.

<!--Layout code--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:id="@+id/init_btn" android:layout_width="match_parent" android:layout_height="@dimen/btn_height" android:background="@color/btn_background" android:gravity="center" android:text="@string/init_text" android:textColor="@color/text_color" android:textSize="@dimen/button_size"/> <TextView android:id="@+id/login_btn" android:layout_width="match_parent" android:layout_height="@dimen/btn_height" android:background="@color/btn_background" android:layout_marginTop="@dimen/margin_top" android:gravity="center" android:text="@string/login_text" android:textColor="@color/text_color" android:textSize="@dimen/button_size" /> <TextView android:id="@+id/player1_btn" android:layout_width="match_parent" android:layout_height="@dimen/btn_height" android:background="@color/btn_background" android:gravity="center" android:layout_marginTop="@dimen/margin_top" android:text="@string/game_player" android:textColor="@color/text_color" android:textSize="@dimen/button_size" /> </LinearLayout>

If you have requested the identity verification system, and obtained the game registration identifier (bizID), configure the game registration identifier. in AppGallery Connect. Huawei will automatically connect the system and enable the forcible identity verification function.

  1. Register a callback listener for the activity in the onCreate method of Application.

    The code is as follows:

    public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); HuaweiMobileServicesUtil.setApplication(this); } }
  2. Call the JosAppsClient.init method to initialize the Game Service SDK in the first started Activity, and pass AntiAddictionCallback as a parameter to the init API. You need to implement the game progress saving or game exit function in the onExit() method for the following cases:
    • If a minor who has passed the identity verification signs in to your game beyond the allowed time period, Game Service will display a pop-up, indicating that the player is currently not allowed to enter the game, and the player has to tap OK.
    • If a minor who has passed identity verification signs in to your game within the allowed time period, Game Service will display a pop-up to notify the player at 21:00 that the allocated time expires, and the player has to tap OK.

    The code is as follows:

    public void init() { AccountAuthParams params = AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME; JosAppsClient appsClient = JosApps.getJosAppsClient(this); // Set the anti-addiction prompt context, this line must be added // Set the game addiction prevention message context. ResourceLoaderUtil.setmContext(this); Task<Void> initTask = appsClient.init(new AppParams(params, new AntiAddictionCallback() { @Override public void onExit() { // Implement the game addiction prevention function, such as saving the game and invoking the account exit interface. // Implement the game addiction prevention function in this method, such as saving game progress or calling the sign-out API. showLog("onExit"); } })); initTask.addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { showLog("init success"); playersClient = Games.getPlayersClient(MainActivity.this); // The login interface can be invoked only after the init is successful. Otherwise, error code 7018 is displayed. // Call the sign-in API after successful initialization. Otherwise, the res**7018**code 7018 is returned. // signIn(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { showLog("init failed, " + e.getMessage()); if (e instanceof ApiException) { ApiException apiException = (ApiException) e; int statusCode = apiException.getStatusCode(); // Error code 7401 indicates that the user did not agree to Huawei joint operations privacy agreement // Res**7401**code 7401 indicates that the user does not agree to Huawei's joint operations privacy agreement. if (statusCode == JosStatusCodes.JOS_PRIVACY_PROTOCOL_REJECTED) { showLog("has reject the protocol"); // You can exit the game or re-call the init interface. // Exit the game or re-call the initialization API. } // Handle other error codes. // Process other result codes. } } }); } /** * Log output * Log output */ public void showLog(String logLine) { StringBuffer sbLog = new StringBuffer(); DateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:SS", Locale.ENGLISH); String time = format.format(new Date()); sbLog.append(time).append(":").append(logLine); Log.i(TAG, sbLog.toString()); }
  1. Call the sign-in API after successful initialization.
  2. Call the getService method of AccountAuthManager to initialize the AccountAuthService object, and call the silentSignIn method of AccountAuthService for silent sign-in. Call the getSignInIntent method of AccountAuthService to bring up the authorization screen upon failed silent sign-in, and display the sign-in result in the onActivityResult callback.
    /** * Call the sign-in API first, and then call getCurrentPlayer or getGamePlayer to obtain player information. * 1. Call the silent sign-in API. If a player has authorized your game and signed in, the authorization or sign-in screen will not display. * 2.If the silent sign-in fails, call the sign-in API in the callback listener to display the authorization screen for players to sign in. * The sign-in result will be returned in the onActivityResult callback. After that, call the API to obtain player information. */ public void signIn() { Task<AuthAccount> authAccountTask = AccountAuthManager.getService(this, getHuaweiIdParams()).silentSignIn(); authAccountTask.addOnSuccessListener( authAccount -> { Toast.makeText(MainActivity.this, "signIn success", Toast.LENGTH_LONG).show(); showLog("signIn success"); }) .addOnFailureListener( new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException apiException = (ApiException) e; Toast.makeText(MainActivity.this, "signIn failed:" + apiException.getStatusCode(), Toast.LENGTH_LONG).show(); showLog("signIn failed:" + apiException.getStatusCode()); signInNewWay(); } } }); } /** * Obtain the Intent object of the HUAWEI ID sign-in authorization screen. The page can be displayed through startActivityForResult(Intent, int). */ public void signInNewWay() { Intent intent = AccountAuthManager.getService(MainActivity.this, getHuaweiIdParams()).getSignInIntent(); startActivityForResult(intent, SIGN_IN_INTENT); } public AccountAuthParams getHuaweiIdParams() { return new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).createParams(); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == SIGN_IN_INTENT) { if (null == data) { showLog("signIn intent 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"); } else { showLog("signIn failed: " + signInResult.getStatus().getStatusCode()); } } catch (JSONException var7) { showLog("Failed to convert json from signInResult."); } } }

Call PlayersClient.getGamePlayer() to obtain player information after successful sign-in.

/** * Obtains user information about gamers. * Obtain the player information. */ public void getGamePlayer() { playersClient = Games.getPlayersClient(this); Task<Player> playerTask = playersClient.getGamePlayer(); playerTask.addOnSuccessListener(new OnSuccessListener<Player>() { @Override public void onSuccess(Player player) { showLog("getPlayerInfo Success"); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // Failed to obtain the player information. if (e instanceof ApiException) { showLog("getPlayerInfo failed, status: " + ((ApiException) e).getStatusCode()); if (7400 == ((ApiException) e).getStatusCode() || 7018 == ((ApiException) e).getStatusCode()) { // error code 7400 indicates that the user has not agreed to the joint operations privacy agreement // error code 7018 indicates that the init API is not called. // 7400 indicates that the user has not signed the joint operations agreement. You need to continue to call the init API. // 7018 indicates that initialization fails. You need to continue to call the init API. init(); }else if (GamesStatusCodes.GAME_STATE_NETWORK_ERROR == ((ApiException) e).getStatusCode()) { //Error code 7002 indicates that the network is abnormal. You can prompt the player to check the network. // 7002 indicates that a network exception occurs. You can prompt players to check their network connection. showLog( "Network error"); } } } }); }
  1. Test the initialization function.
    Tap init and check the console logs. Search for Game_codeLab in the Verbose log information, if the initialization succeeds, init success is displayed.
  2. To test the HUAWEI ID sign-in function,
    Tap SignIn. A welcome pop-up will be displayed as follows upon successful sign-in. You can also search for Game_codeLab in the Verbose log information, if the sign-in succeeds, signIn success is displayed.
  3. To test the function for obtaining the player information,
    Tap getGamePlayer or getCurrentPlayer and check the console log. Search for Game_codeLab in the Verbose log information, if the player information is obtained successfully, getPlayerInfo success is displayed.
  4. To test the game addiction prevention function,
    • Sign in to the game using a minor account, and complete the preceding three testing steps during the time that excludes 20:00 to 21:00 on Fridays, weekends and statutory holidays. If a pop-up is displayed, tap OK. Search for Game_codeLab in the Verbose log information, if onExit is displayed, the game addiction prevention function takes effect successfully.
    • Sign in to the game using a minor account, and complete the preceding three testing steps during 20:00 to 21:00 on Fridays, weekends and statutory holidays. If a pop-up is displayed after the allowed time period ends, tap Got it. Search for Game_codeLab in the Verbose log information. If onExit is displayed, it indicates that the game addiction prevention function takes effect successfully.

Well done. You have successfully completed this codelab and learned how to:

For more information, please refer to the following links:

API reference for Game Service

Source code

Code copied