Servicios y logros de juegos (Kotlin)
Tags: android, huawei, hmscore, kotlin
Published: 2021-02-26 18:49:29

Los logros son una excelente manera de aumentar la participación del jugador dentro de su juego y de brindarle un mayor incentivo para continuar jugando.
En este tutorial, trabajaremos en los pasos que debe seguir para agregar logros usando Kotlin en un proyecto simple de Android Studio.

Primero, integre el núcleo de HMS: https://developer.huawei.com/consumer/en/codelab/HMSPreparation/index.html#0
Después de integrar HMS Core, habilite Game Service y Account Kit

![Alt Text](https://miro.medium.com/max/1050/1*t3qnODL4ezAquF787hLfNg.png)
Ahora vaya a Mis aplicaciones y seleccione Operar -> Logros
![Alt Text](https://miro.medium.com/max/807/1*bT1R0jYYPKv3BIHiljT0Xg.png)
![Alt Text](https://miro.medium.com/max/629/1*8guolAzPWMyuRcxgWCR6FA.png)

Haga clic en Crear
![Alt Text](https://miro.medium.com/max/1050/1*8GZeBA-uUaetKclt2mlx5A.png)
![Alt Text](https://miro.medium.com/max/1050/1*Gs7g5P16RAc0NO538w0GRA.png)
![Alt Text](https://miro.medium.com/max/834/1*PmkIj2WavDzI887e6XCTSA.png)

ID: Una cadena única generada por AppGallery Connect para identificar un logro.
Name: Un nombre corto para el logro que define durante la configuración del logro (máximo de 100 caracteres).
Description: Una descripción concisa del logro. Por lo general, esto le indica al jugador cómo obtener el logro (máximo de 500 caracteres).
Icon: Se muestra después de obtener un logro. El icono debe ser de 512x512 px y en formato png o jpg. Evite utilizar palabras de su idioma local en el icono. HMS SDK generará automáticamente un ícono de versión en escala de grises basado en este ícono y lo usará para los logros desbloqueados.
State: Un logro puede estar en uno de los tres estados diferentes de un juego.
— Hidden: Un logro oculto significa que los detalles sobre el logro están ocultos al jugador. Estos logros están equipados con un icono y una descripción de marcador de posición genéricos mientras están en estado oculto. Si un logro contiene un spoiler sobre tu juego que no te gustaría revelar, puedes configurar el logro como oculto y revelarlo al pagador después de que el juego alcance una determinada etapa.
— Revealed: Un logro revelado significa que el jugador conoce el logro, pero aún no lo ha obtenido. Si desea mostrar el logro al jugador al comienzo del juego, puede configurarlo en este estado.
— Unlocked: Un logro desbloqueado significa que el jugador ha obtenido el logro con éxito. Este estado no es configurable y debe ser obtenido por el jugador. Una vez que el jugador alcanza este estado, aparecerá una ventana emergente en la parte superior de la página del juego. HMS SDK permite desbloquear un logro sin conexión. Cuando un juego vuelve a estar en línea, se sincroniza con el servidor de juegos de Huawei para actualizar el estado desbloqueado del logro.
Steps: Los logros se pueden designar como estándar o incrementales. Un logro incremental implica que un jugador complete una serie de pasos para desbloquear el logro. Este número predefinido de pasos se conoce como pasos de logro.
List order: El orden en el que aparece el logro actual entre todos los logros. Se designa durante la configuración de logros.
Después de crear sus logros, podemos hacer clic en Liberar para ver los logros en su aplicación (esto toma alrededor de 5 horas para ser aprobado) o también puede usar una cuenta de prueba de sandbox.

![Alt Text](https://miro.medium.com/max/1050/1*0WBTb9Bh9ika6T23qqyUZA.png)

En Android Studio Project, agregue el kit de cuenta y el kit de servicio de juegos para build.gradle y Sync
```
implementation'com.huawei.hms:hwid:5.0.3.301'
implementation'com.huawei.hms:game:5.0.3.301'
```
Cree la clase de aplicación y agregue habilitar HuaweiMobileService
```
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        HuaweiMobileServicesUtil.setApplication(this)
    }
}
```
Actualice el manifest y agregue esta línea a la etiqueta de la aplicación
```
<application
    android:name=".MyApplication"
```
Agregue esta línea al método OnCreate en MainActivity
```
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    JosApps.getJosAppsClient(this).init()
}
```
Antes de utilizar los Servicios de juego y obtener Logros u otros datos de Servicios de juego, debemos iniciar sesión con la cuenta del jugador. Para hacer esto, crearemos un nuevo SignInActivity para iniciar sesión e iniciar sesión.

```
package com.hector.hmscore.signin

import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import androidx.annotation.Nullable
import androidx.appcompat.app.AppCompatActivity
import com.hector.hmscore.R
import com.huawei.hmf.tasks.Task
import com.huawei.hms.common.ApiException
import com.huawei.hms.jos.games.Games
import com.huawei.hms.jos.games.player.Player
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.HuaweiIdAuthResult
import org.json.JSONException

class SigninActivity : AppCompatActivity() {
    val TAG = "signinactivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_signin)

        signIn()
    }

    /**
     * When a player signs in, you need to call the HUAWEI ID sign-in verification API. If the verification is successful, call the getcurrentPlayer API to obtain player information.
     * 1. Call the silent sign-in API of the HUAWEI ID sign-in API so that the sign-in page will not be displayed for a game to which a player has already signed in.
     * 2. When silent sign-in fails, it indicates that this is the player's first sign-in and authorization from the player is required. In this case, in the callback, the explicit sign-in API is called to display the sign-in authorization page for sign-in verification.
     * The sign-in API is called in onActivity. Then you can call the API for obtaining player information.
     */
    private fun signIn() {
        val authHuaweiIdTask = HuaweiIdAuthManager.getService(this, getHuaweiIdParams()).silentSignIn()
        authHuaweiIdTask.addOnSuccessListener { authHuaweiId ->
            Log.i(TAG, "silentsignIn success")
            Log.i(TAG, "display:" + authHuaweiId.displayName)
            login()
        }.addOnFailureListener { e ->
            if (e is ApiException) {
                Log.i(TAG, "signIn failed:" + e.statusCode)
                Log.i(TAG, "start getSignInIntent")
                val service = HuaweiIdAuthManager.getService(
                    this@SigninActivity,
                    getHuaweiIdParams()
                )
                startActivityForResult(service.signInIntent, 6013)
            }
        }
    }

    /**
     * Obtain player information.
     */
    private fun login() {
        val  playersClient = Games.getPlayersClient(this)
        val playerTask: Task<Player> = playersClient.currentPlayer
        playerTask.addOnSuccessListener { player ->
            val playerID = player.playerId
            Toast.makeText(this@SigninActivity, "Player ID $playerID", Toast.LENGTH_LONG).show()
            Log.i(TAG, "getPlayerInfo Success, player info: " + player.playerId)
        }.addOnFailureListener { e -> //  Failed to obtain player information.
            if (e is ApiException) {
                Log.e(TAG, "getPlayerInfo failed, status: " + e.statusCode)
                Toast.makeText(this@SigninActivity, "getPlayerInfo failed, status: " + e.statusCode, Toast.LENGTH_LONG).show()
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 6013) {
            if (null == data) {
                Toast.makeText(this@SigninActivity, "signIn inetnt is null", Toast.LENGTH_LONG).show()
                return
            }

            val jsonSignInResult = data.getStringExtra("HUAWEIID_SIGNIN_RESULT")
            if (TextUtils.isEmpty(jsonSignInResult)) {
                Toast.makeText(this@SigninActivity, "signIn result is empty", Toast.LENGTH_LONG).show()
                return
            }
            try {

                val signInResult = HuaweiIdAuthResult().fromJson(jsonSignInResult)
                if (0 == signInResult.status.statusCode) {
                    Log.i(TAG, "signIn success.")
                    Log.i(TAG, "signIn result: " + signInResult.toJson())
                    Toast.makeText(this@SigninActivity, "signIn result: " + signInResult.toJson(), Toast.LENGTH_LONG).show()
                } else {
                    Log.i(TAG, "signIn failed: " + signInResult.status.statusCode)
                    Toast.makeText(this@SigninActivity, "signIn failed: " + signInResult.status.statusCode, Toast.LENGTH_LONG).show()
                }
            } catch (var7: JSONException) {
                Log.i(TAG, "Failed to convert json from signInResult.")
                Toast.makeText(this@SigninActivity, "Failed to convert json from signInResult.", Toast.LENGTH_LONG).show()
            }
        }
    }

    private fun getHuaweiIdParams(): HuaweiIdAuthParams? {
        return HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM_GAME).setIdToken().createParams()
    }
}
```
Ahora podemos conseguir los Logros, crearemos AchievementsActivity
```
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.hector.hmscore.databinding.ActivityAchievementsBinding
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.games.AchievementsClient
import com.huawei.hms.jos.games.Games
import com.huawei.hms.jos.games.achievement.Achievement

class AchievementsActivity : AppCompatActivity() {
    lateinit var achievementsClient: AchievementsClient
    lateinit var binding: ActivityAchievementsBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAchievementsBinding.inflate(layoutInflater)
        setContentView(binding.root)

        achievementsClient = Games.getAchievementsClient(this)

        getAchievementList()
    }

    private fun getAchievementList(){
        val task: Task<List<Achievement>> = achievementsClient.getAchievementList(true)
        task.addOnSuccessListener(OnSuccessListener { data ->
            if (data == null) {
                Log.w("Achievement", "achievement list is null")
                return@OnSuccessListener
            }
            var achievementText = ""
            for (achievement in data) {
                Log.w("Achievement", "achievement id" + achievement.id)
                achievementText += "id: ${achievement.id} \n displayName: ${achievement.displayName} \n\n"
            }
            binding.textViewAchievements.text = achievementText
        }).addOnFailureListener { e ->
            if (e is ApiException) {
                val result = "rtnCode:" +
                        (e as ApiException).statusCode
                Log.e("Achievement", result)
            }
        }
    }
}
```
Nota: Para mantener el código simple, estamos mostrando los datos de logros en un TextView usando viewBinding.
Además, podemos reemplazar el método getAchievementList con el siguiente método para solicitar la página de logros, pero esta página solo muestra los logros si la aplicación se lanza en AppGallery.
```
//Only works when the application is on release
private fun getShowAchievementListIntent(){
        val task: Task<Intent> = achievementsClient.showAchievementListIntent
        task.addOnSuccessListener { intent ->
            if (intent == null) {
                Log.w("Achievement", "intent = null")
            } else {
                try {
                    startActivityForResult(intent, 1)
                } catch (e: java.lang.Exception) {
                    Log.e("Achievement", "Achievement Activity is Invalid")
                }
            }
        }.addOnFailureListener { e ->
            if (e is ApiException) {
                val result = ("rtnCode:" + e.statusCode)
                Log.e("Achievement", "result:$result")
            }
        }
    }
```
Ahora puedes ver la lista de logros disponibles.
Para ver todos los detalles sobre los logros, vaya a: https://developer.huawei.com/consumer/en/doc/development/HMS-Guides/game-achievement
En el próximo post, aprenderemos cómo interactuar y progresar con los logros.