什么是华为游戏服务?

游戏服务是华为为移动开发者提供的用于满足各种移动游戏开发需求的服务。使用游戏服务,你可轻松地在游戏中实现排行榜、事件、成就、存档等功能。游戏服务有效简化游戏的开发过程,让你可以使用简短有序的代码结构创建游戏项目。

华为游戏服务提供以下开发能力,助力更高效开发游戏:

  •  帐号登录
  • 游戏防沉迷
  • 浮标
  •  成就
  •  事件
  • 排行榜
  • 游戏存档
  • 玩家数据统计
  • 游戏基本信息获取

软件及硬件要求

  • Android Studio 3.X 及以上版本
  • JDK 1.8 及以上版本
  • 你的应用应满足以下条件:minSdkVersion: 17;targetSdkVersion: 29;compileSdkVersion: 29

开发流程

1. 集成HMS Core
首先,你要先注册成为华为开发者,并将HMS Core集成到项目中。 你可以从此链接访问有关该步骤的材料。

 2. 添加依赖
集成HMS Core到项目中并在AGC控制台开启游戏服务之后,将所需依赖的库添加到app目录下的build.gradle文件中,如下所示:

dependencies {
implementation 'com.huawei.agconnect:agconnect-auth:1.5.1.300'
implementation 'com.huawei.hms:base: 5.0.5.300'
implementation 'com.huawei.hms:hwid: 5.2.0.300'
implementation 'com.huawei.hms:iap:5.0.1.300'
implementation 'com.huawei.hms:game: 5.0.4.302'
}

3. 创建Application类
当你的应用启动时,游戏服务由Application类触发启动。游戏服务是在这个类中启动的,而此类和项目一同启动。创建BaseApplication类后,你需要在Manifest文件中定义它。

class BaseApplication : Application(){
    companion object{
        lateinit var instance: BaseApplication
            private set
    }


    override fun onCreate() {
        super.onCreate()

        instance = this

        HuaweiMobileServicesUtil.setApplication(this)

        HwAds.init(this)
    }
}

4. 设计登录页面

在所有权限和库都添加到项目中后,你可以开始为你的游戏开发登录页面。此时就用到了华为认证服务。认证服务使你可以在控制台上查看游戏的所有用户。此外,认证服务还提供了多种登录方式:包含Facebook、Twitter、Google、邮箱、电话号码或华为ID。我将分享一个通用的登录页面设计。以下是一个使用华为ID登录的示例。

你可以在此链接查看认证服务的文档:

<androidx.constraintlayout.motion.widget.MotionLayout
        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"
        app:layoutDescription="@xml/motion_scene_splash"
        android:id="@+id/id_09"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:src="@drawable/background"
            android:alpha="0.7"
            android:id="@+id/id_11"/>
        <ImageView
            android:id="@+id/imgView_logo"
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:layout_marginTop="80dp"
            android:scaleType="centerInside"
            android:src="@drawable/vs_logo"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <ImageView
            android:id="@+id/imgView_logo_rays"
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:layout_marginTop="80dp"
            android:scaleType="centerInside"
            android:src="@drawable/vs_logo"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <ImageView
            android:id="@+id/imgView_cloudLeft"
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:layout_marginTop="16dp"
            android:scaleType="centerInside"
            android:src="@drawable/cloud"
            android:translationX="-20dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:tint="#9E9E9E" />

        <ImageView
            android:id="@+id/imgView_cloudRight"
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:layout_marginTop="120dp"
            android:scaleType="centerInside"
            android:src="@drawable/cloud"
            android:translationX="20dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:tint="#607D8B" />

        <LinearLayout
            android:id="@+id/linlay_inputs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="30dp"
            android:alpha="1"
            android:layout_marginLeft="30dp"
            android:layout_marginEnd="30dp"
            android:layout_marginRight="30dp"
            android:gravity="center"
            android:layout_marginTop="10dp"
            android:orientation="vertical"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/imgView_cloudRight">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/muli_regular"
                android:text="Welcome Back"
                android:textColor="#000000"
                android:textSize="20sp"
                android:id="@+id/id_12" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/muli_regular"
                android:text="Sign in to continue"
                android:textColor="#000000"
                android:textSize="14sp"
                android:id="@+id/id_13" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="30dp"
                android:background="@drawable/et_background"
                android:drawableStart="@drawable/ic_baseline_email_24"
                android:drawableLeft="@drawable/ic_baseline_email_24"
                android:drawablePadding="16dp"
                android:hint="Email"
                android:inputType="textEmailAddress"
                android:padding="16dp"
                android:textSize="14sp"
                android:textColor="#000000"
                android:fontFamily="@font/muli_regular"
                android:id="@+id/id_14"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:background="@drawable/et_background"
                android:drawableStart="@drawable/ic_baseline_lock_24"
                android:drawableLeft="@drawable/ic_baseline_lock_24"
                android:drawableEnd="@drawable/ic_baseline_visibility_24"
                android:drawableRight="@drawable/ic_baseline_visibility_24"
                android:drawablePadding="16dp"
                android:hint="Password"
                android:inputType="textPassword"
                android:padding="16dp"
                android:textSize="14sp"
                android:textColor="#000000"
                android:fontFamily="@font/muli_regular"
                android:id="@+id/id_15"/>

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="30dp"
                android:background="@drawable/button_one"
                android:text="@string/signInButton"
                android:textAllCaps="false"
                android:fontFamily="@font/muli_regular"
                android:textColor="#7E675E"
                android:id="@+id/id_16"/>

        </LinearLayout>

        <TextView
            android:id="@+id/tv_forgotPassword"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:layout_marginEnd="30dp"
            android:alpha="1"
            android:layout_marginRight="30dp"
            android:text="Forgot Password?"
            android:textColor="#7E675E"
            android:textSize="13sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/linlay_inputs" />

        <ImageView
            android:id="@+id/safads"
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:src="@drawable/color_logo"
            app:tint="#9E9E9E"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/linlay_inputs"
            android:visibility="invisible"/>
                </androidx.constraintlayout.motion.widget.MotionLayout>

5. 创建LoginViewModel类
LoginViewModel类将从View类接收、处理数据并将处理过的数据发送到View类。所有的登录操作都将在LoginViewModel类中完成。

首先,在HuaweiIdAuthService对象中创建客户端。

private lateinit var mClient: HuaweiIdAuthService

接下来是开发帐户注销。这样做的目的是结束应用中打开的会话。注销后,我们需要创建login方法。首先,调用logout方法。然后添加startActivityForResult方法,并将其在View类重写。

LoginViewModel类如下所示:

class LoginViewModel(private val context: Context): ViewModel(){

    private lateinit var mClient: HuaweiIdAuthService

    fun login(fragment: Fragment){
        logout()

        val huaweiIdAuthParamsHelper =HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
        val scopeList: MutableList<Scope> = ArrayList()
        scopeList.add(Scope(HwIDConstant.SCOPE.ACCOUNT_BASEPROFILE))
        huaweiIdAuthParamsHelper.setScopeList(scopeList)
        val authParams = huaweiIdAuthParamsHelper.setAccessToken().createParams()

        mClient = HuaweiIdAuthManager.getService(context, authParams)
        fragment.startActivityForResult(mClient.signInIntent, 1002)
    }

    fun logout(){
        Log.i(Constants.LOGIN_VIEWMODEL_TAG, "In LogOut Fun.")
        val auth = AGConnectAuth.getInstance()
        auth.signOut()
    }
}

6. 创建LoginViewModelFactory类

创建LoginViewModelFactory类,并将上下文设置为参数。此类将返回ViewModel类。

class LoginViewModelFactory(private val context: Context): ViewModelProvider.NewInstanceFactory(){
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return LoginViewModel(context) as T
    }
}

7. 创建LoginFragment

在XML文件上添加ViewModel依赖,并将它作为绑定对象。你需要再次打开XML文件,添加变量“viewmodel”,将type添加为ViewModel类目录。

<data>
    <variable
        name="viewmodel"
        type="com.xxx.xxx.viewmodel.LoginViewModel"/>
</data>

返回LoginFragment并添加工厂类、viewmodel类,并进行绑定。

private lateinit var binding: FragmentLoginBinding
private lateinit var viewModel: LoginViewModel
private lateinit var viewModelFactory: LoginViewModelFactory

在onCreateView方法上定义这些对象。

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        binding = DataBindingUtil.inflate(inflater, R.layout.activity_splash_login, container,false) as ActivitySplashLoginBinding
        viewModelFactory =LoginViewModelFactory(requireContext() )
        viewModel = ViewModelProviders.of(this, viewModelFactory).get(LoginViewModel::class.java)

        return binding.root
    }

创建登录按钮点击事件监听,并在ViewModel类中调用login方法。

var gameLoginButton = binding.id16.findViewById<View>(R.id.id_16)
gameLoginButton.setOnClickListener {
    showProgressDialog()
    viewModel.login(this)
}

最后,创建onActivityResult方法,查看登录结果。如果登录成功,你可以看到一些用户信息,比如用户名、ID、国家/地区、年龄等。认证服务提供了丰富的用户信息,你可以在App中使用认证服务。

override fun onActivityResult(
        requestCode: Int,
        resultCode: Int,
        @Nullable data: Intent?
    ) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1002) {
            val signInHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data)
            if (signInHuaweiIdTask.isSuccessful) {
                val huaweiAccount = signInHuaweiIdTask.result
                val accessToken = huaweiAccount.accessToken
                Log.w(Constants.LOGIN_FRAGMENT_TAG, "accessToken: $accessToken")

                val credential = HwIdAuthProvider.credentialWithToken(accessToken)
                val provider_now = credential.provider
                Log.w(Constants.LOGIN_FRAGMENT_TAG, "provider_now: $provider_now")

                AGConnectAuth.getInstance().signIn(credential)
                    .addOnSuccessListener { signInResult ->
                        val user = AGConnectAuth.getInstance().currentUser
                        Log.w(Constants.LOGIN_FRAGMENT_TAG, "Login Success. User Display Name : " + user.displayName)
                        userName = user.displayName
                       //Start another fragment here.
                        (activity as MainActivity?)!!.setSelectedTab(Constants.TAB_LOGIN,Constants.TAB_HOME,false)

                        dismisProgressDialog()

                    }.addOnFailureListener { e: Exception ->
                        Toast.makeText(context, R.string.authenticationError, Toast.LENGTH_SHORT).show()
                        Log.w(Constants.LOGIN_FRAGMENT_TAG, "sign in for agc failed: " + e.message)
                        dismisProgressDialog()
                    }
            } else {
                Toast.makeText(context, R.string.sıgnInError, Toast.LENGTH_SHORT).show()
                Log.e(Constants.LOGIN_FRAGMENT_TAG,"sign in failed : " + (signInHuaweiIdTask.exception as ApiException).statusCode)

                dismisProgressDialog()
            }
        }
    }

结论

现在你可以在游戏App上实现登录功能啦!你也可以跟我一样选择使用认证服务,它可提供多种用户信息,你可在AGC控制台中查看所有用户。

>>访问华为游戏服务官网,了解更多相关内容
>>获取华为游戏服务开发指导文档
>>华为HMS Core官方论坛
>>华为游戏服务开源仓库地址:GitHubGitee

点击右上角头像右方的关注,第一时间了解华为移动服务最新技术~

06-15 16:39