为啥要接GCloud呢?因为我们项目采用的方式有问题,这是腾讯专家说的,然后只能改了。先说下我们这边的方式,客户端是请求PHP后台生成的一个txt文件(Json格式的),然后获取CDN和区服相关信息,根据参数是否显示审核服还是正式服,接着再去请求一堆区服数据的txt。如果在选服界面的话,还需要每隔5秒或者10秒重新请求,判断是否有新的服务器开了或服务器状态变化了(比如变成维护了)。
具体情况说完,开始接入,然后发现又踩坑里去了。先说下SDK版本,是在官网下载的Unity插件,版本是GCloud1.1.5.185491.2018111900.unityPackage,然后开始编译,各种失败,iOS和Android各种编译不通过。iOS的之前有遇到过同样的问题,猜是不是XCode10的问题,向官方要支持XCode10的framework,然后给了个Cocos和UE4版本的,嗯,什么鬼?framework全部替换成Cocos和UE4的,iOS编译通过,运行也没问题,能获取到区服数据。
接下来是Android的问题,错误经常看到,就猜到是jar包重复,检查了下,发现MSDK和GCloud都包含了android-support-v4.jar,随意删除一个,编译成功。以为这样就结束了,太天真了。运行时一直获取不到区服数据,调试发现IsConnected接口,一直返回没有成功连接上服务器,然后去官方文档上仔细看了下,猜估计是主Activity没有继承GCloud的Activity。然后就艹了,啥玩意呀,都什么年代了,还用这么老的技术,MSDK都是用命令行修改一堆参数生成一个Jar包,接下来啥的都不用管,一到GCloud,要怎么麻烦,我们怎么接。
咋办,大厂时间都定好了,没几天了,只能硬上了,找到编译成MSDK jar包的源码,修改源码,生成一个支持GCloud的MSDK jar包。
在DeployAndroid.cs脚本的GenerateAdapter()接口中,添加如下代码,不要忘了拷贝相关的Jar包到该目录:
找到Assets\Msdk\Adapter\Android\java\src\com\example\wegame目录,对MGameActivity.java进行修改。其实也就是添加下代码,代码不是乱写的呀,也不要去看文档,直接用反编译工具反编译GCloudSDK中的GCloudUnity.jar包,然后开始拷贝代码就行:
MGameActivity.java原来的:
package com.example.wegame;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import com.tencent.bugly.msdk.crashreport.CrashReport;
import com.tencent.msdk.WeGame;
import com.tencent.msdk.adapter.MsdkActivity;
import com.tencent.msdk.api.LoginRet;
import com.tencent.msdk.api.WGPlatform;
import com.tencent.msdk.consts.CallbackFlag;
import com.tencent.msdk.consts.EPlatform;
import com.tencent.msdk.consts.TokenType;
import com.tencent.msdk.tools.Logger;
/**.
* 游戏主Activity需要继承MsdkActivity
*/
public class MGameActivity extends MsdkActivity {
private static Activity activity = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
}
@Override
protected void onDestroy() {
super.onDestroy();
activity = null;
}
// MSDKDemo Functions
/**
* TODO Game 拉起支付示例,游戏需要参考米大师文档自己编写支付相关代码
* 需要先安装支付示例工程AndroidPaySample(位于MSDKzip包中的Tencent AndroidPayRelease.zip中)
* 才能拉起支付Demo
*/
public static void launchPayDemo() {
Logger.d("called");
Intent i = new Intent("com.tencent.pay.sdksample.AndroidPaySample");
LoginRet lr = new LoginRet();
WGPlatform.WGGetLoginRecord(lr);
// 注意:这里需要判断登录态是否有效
if (lr.flag != CallbackFlag.eFlag_Succ) {
if (lr.platform == EPlatform.ePlatform_Weixin.val()) {
// accesstoken过期,尝试刷新票据
if (lr.flag == CallbackFlag.eFlag_WX_AccessTokenExpired) {
WGPlatform.WGRefreshWXToken();
return;
} else {
// 微信登录态失效,引导用户重新登录授权
return;
}
} else {
// 手Q登录态失效,引导用户重新登录授权
return;
}
}
i.putExtra("userId", lr.open_id);
i.putExtra("offerId", WeGame.getInstance().offerId);
if (lr.platform == WeGame.WXPLATID) {
i.putExtra("userKey", lr.getTokenByType(TokenType.eToken_WX_Access));
i.putExtra("sessionType", "wc_actoken");
i.putExtra("sessionId", "hy_gameid");
} else if (lr.platform == WeGame.QQPLATID) {
i.putExtra("userKey", lr.getTokenByType(TokenType.eToken_QQ_Pay));
i.putExtra("sessionType", "kp_actoken");
i.putExtra("sessionId", "openid");
}
i.putExtra("pf", WGPlatform.WGGetPf(""));
i.putExtra("zoneId", "1");
i.putExtra("pfKey", WGPlatform.WGGetPfKey());
i.putExtra("acctType", "common");
i.putExtra("saveValue", "60");
i.putExtra("msdk", true);
activity.startActivity(i);
}
/**
* 游戏崩溃后会将堆栈信息上报到腾讯组件————灯塔中。这时制造native层崩溃测试异常上报
*/
public static void nativeCrashTest() {
// Native异常测试
Logger.d("called");
CrashReport.testNativeCrash();
}
/**
* 游戏崩溃后会将堆栈信息上报到腾讯组件————灯塔中。这时制造空指针异常测试异常上报
*/
public static void nullPointerExceptionTest() {
// 空指针异常测试
Logger.d("called");
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
String str = null;
str.equals("");
}
});
}
}
MGameActivity.java修改后:
package com.example.wegame;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import com.tencent.bugly.msdk.crashreport.CrashReport;
import com.tencent.msdk.WeGame;
import com.tencent.msdk.adapter.MsdkActivity;
import com.tencent.msdk.api.LoginRet;
import com.tencent.msdk.api.WGPlatform;
import com.tencent.msdk.consts.CallbackFlag;
import com.tencent.msdk.consts.EPlatform;
import com.tencent.msdk.consts.TokenType;
import com.tencent.msdk.tools.Logger;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
import com.tencent.gcloud.GCloud;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
/**.
* 游戏主Activity需要继承MsdkActivity
*/
public class MGameActivity extends MsdkActivity {
private static Activity activity = null;
private static final String tag = "GCloud";
private static final int REQUEST_CODE_ASK_PERMISSION = 101;
private boolean bEnableRequestPermission = true;
public void setEnableRequestPermission(boolean paramBoolean)
{
this.bEnableRequestPermission = paramBoolean;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
Object localObject = GCloud.Instance;
if (!((GCloud)localObject).initialize(this))
{
Log.i("GCloud", "Warning!Reduplicate game activity was detected.Activity will finish immediately.");
finish();
return;
}
}
protected void onNewIntent(Intent paramIntent)
{
try
{
super.onNewIntent(paramIntent);
GCloud.Instance.onNewIntent(paramIntent);
}
catch (Exception localException)
{
Log.w("Exception", "onNewIntent Exception:" + localException.toString());
}
}
protected void onPause()
{
try
{
super.onPause();
GCloud.Instance.onPause();
}
catch (Exception localException)
{
Log.w("Exception", "onPause Exception:" + localException.toString());
}
}
protected void onResume()
{
try
{
super.onResume();
GCloud.Instance.onResume();
}
catch (Exception localException)
{
Log.w("Exception", "onResume Exception:" + localException.toString());
}
}
protected void onRestart()
{
try
{
super.onRestart();
GCloud.Instance.onRestart();
}
catch (Exception localException)
{
Log.w("Exception", "onDestroy Exception:" + localException.toString());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
activity = null;
try
{
super.onDestroy();
GCloud.Instance.onDestroy();
}
catch (Exception localException)
{
Log.w("Exception", "onDestroy Exception:" + localException.toString());
}
}
public void onConfigurationChanged(Configuration paramConfiguration)
{
super.onConfigurationChanged(paramConfiguration);
Log.i("GCloud", "onConfigurationChanged");
}
public void onSaveInstanceState(Bundle paramBundle)
{
super.onSaveInstanceState(paramBundle);
Log.i("GCloud", "onSaveInstanceState");
}
protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent)
{
super.onActivityResult(paramInt1, paramInt2, paramIntent);
GCloud.Instance.onActivityResult(paramInt1, paramInt2, paramIntent);
}
// MSDKDemo Functions
/**
* TODO Game 拉起支付示例,游戏需要参考米大师文档自己编写支付相关代码
* 需要先安装支付示例工程AndroidPaySample(位于MSDKzip包中的Tencent AndroidPayRelease.zip中)
* 才能拉起支付Demo
*/
public static void launchPayDemo() {
Logger.d("called");
Intent i = new Intent("com.tencent.pay.sdksample.AndroidPaySample");
LoginRet lr = new LoginRet();
WGPlatform.WGGetLoginRecord(lr);
// 注意:这里需要判断登录态是否有效
if (lr.flag != CallbackFlag.eFlag_Succ) {
if (lr.platform == EPlatform.ePlatform_Weixin.val()) {
// accesstoken过期,尝试刷新票据
if (lr.flag == CallbackFlag.eFlag_WX_AccessTokenExpired) {
WGPlatform.WGRefreshWXToken();
return;
} else {
// 微信登录态失效,引导用户重新登录授权
return;
}
} else {
// 手Q登录态失效,引导用户重新登录授权
return;
}
}
i.putExtra("userId", lr.open_id);
i.putExtra("offerId", WeGame.getInstance().offerId);
if (lr.platform == WeGame.WXPLATID) {
i.putExtra("userKey", lr.getTokenByType(TokenType.eToken_WX_Access));
i.putExtra("sessionType", "wc_actoken");
i.putExtra("sessionId", "hy_gameid");
} else if (lr.platform == WeGame.QQPLATID) {
i.putExtra("userKey", lr.getTokenByType(TokenType.eToken_QQ_Pay));
i.putExtra("sessionType", "kp_actoken");
i.putExtra("sessionId", "openid");
}
i.putExtra("pf", WGPlatform.WGGetPf(""));
i.putExtra("zoneId", "1");
i.putExtra("pfKey", WGPlatform.WGGetPfKey());
i.putExtra("acctType", "common");
i.putExtra("saveValue", "60");
i.putExtra("msdk", true);
activity.startActivity(i);
}
/**
* 游戏崩溃后会将堆栈信息上报到腾讯组件————灯塔中。这时制造native层崩溃测试异常上报
*/
public static void nativeCrashTest() {
// Native异常测试
Logger.d("called");
CrashReport.testNativeCrash();
}
/**
* 游戏崩溃后会将堆栈信息上报到腾讯组件————灯塔中。这时制造空指针异常测试异常上报
*/
public static void nullPointerExceptionTest() {
// 空指针异常测试
Logger.d("called");
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
String str = null;
str.equals("");
}
});
}
@TargetApi(23)
public void onRequestPermissionsResult(int paramInt, String[] paramArrayOfString, int[] paramArrayOfInt)
{
Log.i("GCloud", "onRequestPermissionsResult: " + paramInt);
super.onRequestPermissionsResult(paramInt, paramArrayOfString, paramArrayOfInt);
switch (paramInt)
{
case 101:
if ((paramArrayOfString.length <= 0) || (paramArrayOfInt.length <= 0)) {
Log.e("GCloud", "onRequestPermissionsResult: permissions or grantResults is empty");
} else {
for (int i = 0; i < paramArrayOfString.length; i++) {
if (paramArrayOfInt[0] == 0) {
Log.i("GCloud", "onRequestPermissionsResult: " + paramArrayOfString[i] + " Granted!");
} else {
Log.i("GCloud", "onRequestPermissionsResult: " + paramArrayOfString[i] + " Denied!");
}
}
}
break;
}
}
static
{
System.loadLibrary("abase");
System.loadLibrary("TDataMaster");
System.loadLibrary("gcloud");
}
}
然后重新使用MSDK自带的Deploy按钮重新生成一个MSDK jar包,只需要这个,其他的都不需要,这样易于管理。编译通过,运行也没有问题,可以获取到区服数据。说句老实话,GCloud也不咋样,获取区服数据有点慢,需要1到10秒左右,怪不得完美世界(手游)在登陆后要播放CG,估计就是在等获取区服数据,为啥,反编译看到有GCloud的相关库。
顺带说下,之前项目没有采用GVoice语音,用的是另外公司的SDK,主要是免费,嗯,免费。但最近在线上测试中,Crash率几乎一半都在语音SDK上,所以商量后,决定采用GVoice语音来减少Crash率(大厂对Crash率要求有点高)。之前稍微接过GVoice玩了下,因此接起来还是很快的。官方还提供了XCode10版本的,因此iOS上编译也没有太大问题。就有一个小问题,语音转文字,不要用GCloudVoiceMode.RSTT模式,要用GCloudVoiceMode.Translation模式。这个稍微坑了下,官方demo用这个模式可以转换文字,我们项目就不行,用GCloudVoiceMode.Translation就可以,有点小坑。