为了访问 Google Play 游戏服务功能,您的游戏需要提供已登录玩家的帐号。如果玩家未经身份验证,您的游戏在调用 Google Play 游戏服务 API 时可能会遇到错误。本文档介绍如何在游戏中实现无缝登录体验。
实现玩家登录
GoogleSignInClient
类是检索当前已登录玩家的帐号以及在玩家之前未在设备上的应用中登录的情况下登录玩家的主要入口点。
要创建登录客户端,请按照以下步骤操作
通过
GoogleSignInOptions
对象创建登录客户端,如下面的代码片段所示。在GoogleSignInOptions.Builder
中配置您的登录时,必须指定GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN
。GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN;
如果您想使用
SnapshotsClient
,请将.requestScopes(Games.SCOPE_GAMES_SNAPSHOTS)
添加到您的GoogleSignInOptions.Builder
中,如下面的代码片段所示GoogleSignInOptions signInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN) .requestScopes(Games.SCOPE_GAMES_SNAPSHOTS) .build();
调用
GoogleSignIn.getClient()
方法并传入您在上一步中配置的选项。如果调用成功,Google 登录 API 将返回GoogleSignInClient
的实例。
检查玩家是否已登录
您可以使用 GoogleSignIn.getLastSignedInAccount()
检查当前设备上是否已登录帐号,并使用 GoogleSignIn.hasPermissions()
检查此帐号是否已授予所需的权限。如果两个条件都为真(即,getLastSignedInAccount()
返回非空值,并且 hasPermissions()
返回 true
),即使设备离线,您也可以安全地使用 getLastSignedInAccount()
返回的帐号。
执行静默登录
您可以调用 silentSignIn()
来检索当前已登录玩家的帐号,如果他们在其他设备上已成功登录到您的应用,则尝试在不显示用户界面的情况下登录玩家。
silentSignIn()
方法返回 Task<GoogleSignInAccount>
。任务完成后,您将前面声明的 GoogleSignInAccount
字段设置为任务返回的结果作为登录帐号,或设置为 null
,表示没有已登录用户。
如果静默登录尝试失败,您可以选择发送登录意图以显示登录用户界面,如 执行交互式登录 中所述。
由于活动不在前台时已登录玩家的状态可能会发生变化,因此我们建议从活动的 onResume()
方法调用 silentSignIn()
。
要静默执行登录,请按照以下步骤操作
- 在
GoogleSignInClient
上调用silentSignIn()
方法以启动静默登录流程。此调用返回一个Task<GoogleSignInAccount>
对象,如果静默登录成功,则该对象包含GoogleSignInAccount
。 - 通过重写
OnCompleteListener
来处理玩家登录的成功或失败。- 如果登录任务成功,请通过调用
getResult()
获取GoogleSignInAccount
对象。 - 如果登录不成功,您可以发送登录意图来启动交互式登录流程。有关您可以使用的其他回调侦听器的列表,请参阅Tasks API 开发者指南和
Task
API 参考。
- 如果登录任务成功,请通过调用
以下代码片段显示了您的应用如何执行静默登录
private void signInSilently() { GoogleSignInOptions signInOptions = GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN; GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); if (GoogleSignIn.hasPermissions(account, signInOptions.getScopeArray())) { // Already signed in. // The signed in account is stored in the 'account' variable. GoogleSignInAccount signedInAccount = account; } else { // Haven't been signed-in before. Try the silent sign-in first. GoogleSignInClient signInClient = GoogleSignIn.getClient(this, signInOptions); signInClient .silentSignIn() .addOnCompleteListener( this, new OnCompleteListener<GoogleSignInAccount>() { @Override public void onComplete(@NonNull Task<GoogleSignInAccount> task) { if (task.isSuccessful()) { // The signed in account is stored in the task's result. GoogleSignInAccount signedInAccount = task.getResult(); } else { // Player will need to sign-in explicitly using via UI. // See [sign-in best practices](http://developers.google.com/games/services/checklist) for guidance on how and when to implement Interactive Sign-in, // and [Performing Interactive Sign-in](http://developers.google.com/games/services/android/signin#performing_interactive_sign-in) for details on how to implement // Interactive Sign-in. } } }); } } @Override protected void onResume() { super.onResume(); signInSilently(); }
如果静默登录尝试失败,您可以调用getException()
来获取包含详细状态代码的ApiException
。状态代码为CommonStatusCodes.SIGN_IN_REQUIRED
表示玩家需要采取明确的操作才能登录。在这种情况下,您的应用应启动交互式登录流程,如下一节所述。
执行交互式登录
要进行玩家交互式登录,您的应用需要启动登录意图。如果成功,Google 登录 API 会显示一个用户界面,提示玩家输入其凭据以登录。这种方法简化了您的应用开发,因为登录活动代表您的应用处理诸如需要更新 Google Play 服务或显示同意提示之类的场景。结果通过onActivityResult
回调返回。
要交互式执行登录,请按照以下步骤操作
在
GoogleSignInClient
上调用getSignInIntent()
以获取登录意图,然后调用startActivity()
并传入该意图。以下代码片段显示了您的应用如何启动交互式登录流程private void startSignInIntent() { GoogleSignInClient signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); Intent intent = signInClient.getSignInIntent(); startActivityForResult(intent, RC_SIGN_IN); }
在
onActivityResult()
回调中,处理返回意图的结果。- 如果登录结果成功,请从
GoogleSignInResult
中获取GoogleSignInAccount
对象。 - 如果登录结果不成功,您应该处理登录错误(例如,在警报中显示错误消息)。以下代码片段显示了您的应用如何处理玩家登录的结果
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RC_SIGN_IN) { GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); if (result.isSuccess()) { // The signed in account is stored in the result. GoogleSignInAccount signedInAccount = result.getSignInAccount(); } else { String message = result.getStatus().getStatusMessage(); if (message == null || message.isEmpty()) { message = getString(R.string.signin_other_error); } new AlertDialog.Builder(this).setMessage(message) .setNeutralButton(android.R.string.ok, null).show(); } } }
- 如果登录结果成功,请从
检索玩家信息
Google 登录 API 返回的GoogleSignInAccount
不包含任何玩家信息。如果您的游戏使用玩家信息(例如玩家的显示名称和玩家 ID),您可以按照以下步骤检索此信息。
- 通过调用
getPlayersClient()
方法并传入GoogleSignInAccount
作为参数,获取PlayersClient
对象。 - 使用
PlayersClient
方法异步加载包含玩家信息的Player
对象。例如,您可以调用getCurrentPlayer()
来加载当前登录的玩家。如果任务返回状态代码为SIGN_IN_REQUIRED
的ApiException
,则表示需要重新验证玩家身份。为此,请调用GoogleSignInClient.getSignInIntent()
以交互式登录玩家。 - 如果任务成功返回
Player
对象,则可以调用Player
对象的方法来检索特定的玩家详细信息(例如,getDisplayName()
或getPlayerId()
)。
提供登录按钮
要在游戏中提供标准的 Google 登录按钮,您可以使用以下方法之一
- 在主活动布局中包含
com.google.android.gms.common.SignInButton
;或 - 根据Google 登录品牌指南设计自定义登录按钮。
当用户点击登录按钮时,您的游戏应通过发送登录意图来启动登录流程,如执行交互式登录中所述。
此代码片段显示了如何在活动的onCreate()
方法中添加登录按钮。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_in); findViewById(R.id.sign_in_button).setOnClickListener(this); findViewById(R.id.sign_out_button).setOnClickListener(this); }
以下代码片段显示了当用户点击登录按钮时如何发送登录意图。
@Override public void onClick(View view) { if (view.getId() == R.id.sign_in_button) { // start the asynchronous sign in flow startSignInIntent(); } else if (view.getId() == R.id.sign_out_button) { // sign out. signOut(); // show sign-in button, hide the sign-out button findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE); findViewById(R.id.sign_out_button).setVisibility(View.GONE); } }
显示游戏弹出窗口
您可以使用GamesClient
类在游戏中显示弹出视图。例如,您的游戏可以显示“欢迎回来”或“成就解锁”弹出窗口。要允许 Google Play 游戏服务在您的游戏视图中启动弹出窗口,请调用setViewForPopups()
方法。您可以通过调用setGravityForPopups()
进一步自定义弹出窗口在屏幕上的显示位置。
注销玩家
注销是通过在GoogleSignInClient
上调用signOut()
方法来完成的。
private void signOut() { GoogleSignInClient signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); signInClient.signOut().addOnCompleteListener(this, new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // at this point, the user is signed out. } }); }