一、google登录

google登录接入文档 ​​https://developers.google.com/identity/sign-in/android/start-integrating​

  • 准备工作
    1.首先准备一个google账号。
    2.测试机需要挂VPN,需要安装Google Play 服务、Google服务框架、Google Play 商店,
    很重要,很重要,很重要!!!直接影响我们后面调试是否成功。

    3.在​​Google Cloud Platform​​后台创建一个项目。
  • 导航菜单选择API和服务
  • 左边API和服务菜单栏选择凭据,然后创建Oauth客户端ID

    注意: SHA-1证书指纹可以通过cmd运行以下命令生成;keystone文件可以在Android Studio中生成,或者你已经有keystone文件了;keystone就是我们所说的证书,令牌这一类的文件;
keytool -keystore [你的keystone文件路径] -list -v
  • 这时我们已经有OAuth 客户端ID了

    以上红色框内为自动创建的客户端ID,在集成登录功能时需要填入这个客户端ID。
  • 开始集成google登录
    此时我们应该已经通过cocos creator build成功了Android包了。(这里我使用的是cocos creator2.4.4)。
  • 在我们的应用级build.gradle文件中,将Google Play 服务声明为依赖项
apply plugin: 'com.android.application'
...
dependencies {
...
implementation 'com.google.android.gms:play-services-auth:19.0.0'
}
  • 上代码
    GoogleSign.java如下
package org.googleApi;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

import org.cocos2dx.javascript.AppActivity;
import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;

public class GoogleSign {

private static final String TAG = "GoogleSign";
private static final int RC_SIGN_IN = 9001;
// google后台自动创建的 Web client(Auto-created for Google Sign-in)
private static final String server_client_id = "XXXXXXXXXXX";

// Client used to sign in with Google APIs
public GoogleSignInClient mGoogleSignInClient;

private static AppActivity this_tmp;

public void init(AppActivity context) {
Log.d(TAG, "init");
this.this_tmp = context;
}

public void onCreate() {
Log.d(TAG, "onCreate.");
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(server_client_id)
.requestEmail()
.build();
// Build a GoogleSignInClient with the options specified by gso.
mGoogleSignInClient = GoogleSignIn.getClient(this_tmp, gso);
}

public void onStart() {
Log.d(TAG, "onStart.");
// Check for existing Google Sign In account, if the user is already signed in
// the GoogleSignInAccount will be non-null.
// GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this_tmp);
// updateUI(account);
}

// 静默登录
public void silentSignIn() {
Log.d(TAG, "signInSilently()");
mGoogleSignInClient.silentSignIn().addOnCompleteListener(this_tmp,
new OnCompleteListener<GoogleSignInAccount>() {
@Override
public void onComplete(Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
Log.d(TAG, "signInSilently(): success");

} else {
Log.d(TAG, "signInSilently(): failure", task.getException());

}
}
});
}
// 意图登录
public void logIn() {
Log.d(TAG, "logIn.");
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
this_tmp.startActivityForResult(signInIntent, RC_SIGN_IN);
}

public void logOut() {
Log.d(TAG, "signOut()");
mGoogleSignInClient.signOut().addOnCompleteListener(this_tmp,
new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "signOut(): success");

} else {
Log.d(TAG, "signOut(): failure");

}
}
});
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
Log.d(TAG, "onActivityResult: resultCode = " + resultCode);
Log.d(TAG, "onActivityResult: data = " + data);

// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
String idToken = account.getIdToken();
System.out.println("idToken = " + idToken);
// 返回js层 验证token

loginRes(account.getDisplayName(), account.getEmail(), idToken);

// Signed in successfully, show authenticated UI.
// updateUI(account);
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
// updateUI(null);

loginRes(null, null, null);
}
}
}

private void loginRes(final String pName, final String pEmail, final String idToken) {
this_tmp.runOnGLThread(new Runnable() {
@Override
public void run() {
String value = "window.NativeJSBridgeIns.googleLoginRes(\"" + pName + "\",\"" + pEmail + "\",\"" + idToken + "\");";
System.out.println("evalstring: " + value);
Cocos2dxJavascriptJavaBridge.evalString(value);
}
});
}

private void updateUI(GoogleSignInAccount acct) {
Log.d(TAG, "updateUI.");
System.out.println(acct);
if(acct != null) { // 登录成功
String personName = acct.getDisplayName();
String personGivenName = acct.getGivenName();
String personFamilyName = acct.getFamilyName();
String personEmail = acct.getEmail();
String personId = acct.getId();
Uri personPhoto = acct.getPhotoUrl();
Log.d(TAG, "updateUI: personName = " + personName);
Log.d(TAG, "updateUI: personGivenName = " + personGivenName);
Log.d(TAG, "updateUI: personFamilyName = " + personFamilyName);
Log.d(TAG, "updateUI: personEmail = " + personEmail);
Log.d(TAG, "updateUI: personId = " + personId);
Log.d(TAG, "updateUI: personPhoto = " + personPhoto);

this_tmp.runOnGLThread(new Runnable() {
@Override
public void run() {
Cocos2dxJavascriptJavaBridge.evalString(String.format(
"window.SignIn();"
));
}
});
}
else {
Log.d(TAG, "updateUI: err = " + "登录失败");
}
}

public void onResume() {
Log.d(TAG, "onResume()");
// silentSignIn();
}
}

在AppActivity.java的onCreate方法中进行new及init,在onActivityResult中调用GoogleSign.java的onActivityResult方法,在我们进行了登录操作后,这个方法可以监听到登录的信息。如需要验证idToken则在这里将idToken返回到JS层,JS层再将idToken发给游戏服务器进行校验。至此,登录集成完毕。

二、google支付

google支付接入文档​https://developer.android.com/google/play/billing​​​ 具体步骤可参考这篇博文​​google计费接入,Billing结算库支付_Android凯的博客-博客​​,写的非常详细了。
我这里再强调几个需要注意的点,很重要!很重要!很重要!

  • 准备一个google开发者账号,注册的话需要25美刀;如果是公司项目,可以使用公司的账号将上面准备工作中的google账号邀请为开发者,然后你就不用再花25美刀了。
  • Google Play Console平台根据接入文档配置项目信息,在可以添加应用内商品前需要在内部测试菜单栏上传apk或其他,上传时若出现Google Play 提包错误:“您的APK或Android App Bundle会使用需提供隐私权政策的权限”。需要在应用内容菜单栏的隐私权政策中添加一个网址。
  • 在调试过程中连接谷歌服务器时出现code==3。
billingResult.getResponseCode() = 3;
billingResult.getResponseCode() = BillingClient.BillingResponseCode.BILLING_UNAVAILABLE;
billingResult.getDebugMessage() = "billing service unavailable"

可能原因:手机不支持google支付,可以打开Google Play 商店验证。一般不支持付费协议的话付费的应用列表为空,如果包含付费的应用且点击付费可以拉起付费弹窗,则支持。在验证之前必须完成准备工作中的第二点!

  • 查询商品列表时,返回空。
List<String> skuList = new ArrayList<>();
skuList.add("test_1");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, @Nullable List<SkuDetails> skuDetailsList) {
Log.i(TAG, "getResponseCode=" + billingResult.getResponseCode() + ",skuDetailsList =" + skuDetailsList);
}
....
});

即:Log.i中 getResponseCode=0,查询成功;skuDetailsList=[],列表为空。具体原因是Google Play Console后台提交apk包或者app bundle之后需要检查版本发布,也就是提交审核,不需要等审核成功,这时候已经可以开始测试了。

这里也有几点需要注意:

1.保证 versionCode 和版本号与我们上传的apk的包的一样。

Cocos Creator 原生平台接入google登录、支付_android studio

上传的apk版本号

Cocos Creator 原生平台接入google登录、支付_Google_02


调试时测试机上apk的版本号2.保证后台和你传入的购买商品的 id 一致。

Google Play Console后台创建的商品id要与你测试购买传入的商品id一致。

Cocos Creator 原生平台接入google登录、支付_android_03

后台配置的商品id

Cocos Creator 原生平台接入google登录、支付_android studio_04

发起购买时传入的商品id3.确保我们所使用的账号是在测试人员里,不仅后台需要添加测试人员的账号,还需要发送邀请链接,然后测试人员点击确认邀请才可以。

Cocos Creator 原生平台接入google登录、支付_cocos2d_05

邀请链接从Google Play Console后台进行复制。

以上3步缺一不可。不然你可能遇到“无法购买您要的商品”的问题(亲自踩过坑了~)。

补充:测试支付

测试支付文档 ​​​https://docs.revenuecat.com/docs/google-play-store​​ 这里指的是沙盒测试,测试过程不需要进行真正的支付操作。如下是测试支付截图:

Cocos Creator 原生平台接入google登录、支付_Google_06

1. 在Google Play Console后台配置测试账号

Cocos Creator 原生平台接入google登录、支付_Google_07


2.在内部测试轨道中添加第一步中配置过的测试账号

Cocos Creator 原生平台接入google登录、支付_2d_08


在登录了测试账号情况下复制链接并打开,同意成为测试人员。

注意点:1.在后台进行了商品修改操作或者将应用发布到测试轨道后几个小时后才会生效。2.应用配置的地区要包含测试账号所在的地区。