项目上线期,加上公司原有未配置热更新的Cocos2d / Unity游戏项目的日常更新,工作中遇到了不少多SDK接入集成的事。
打算做一个打包工具,记录进度和遇到的坑。
pre
Unity提供了调用安卓静态和非静态的方法,
/// <summary>
/// Unity访问安卓非静态方法
/// </summary>
public void CallAndroid()
{
AndroidJavaClass UnityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = UnityClass.GetStatic<AndroidJavaObject>("currentActivity");
activity.Call("Init");
}
/// <summary>
/// Unity访问安卓静态方法
/// </summary>
public void CallAndroidStatic()
{
AndroidJavaClass jc = new AndroidJavaClass("com.sdk.chenchenInterface");
jc.CallStatic("Login");
}
/// <summary>
/// Unity收到从SDK发来的通知
/// </summary>
/// <param name="s"></param> s为待解析的json文件
public void ReceiveNotifyFromSDK(string s)
{
Debug.LogError("Unity --------ReceiveNotifyFromSDK--------:" + s);
}
安卓部分加入相对应的方法,静态函数写在自己定义的类com.sdk.chenchenInterface里面,非静态方法写在安卓程序入口UnityPlayerActivity里面,打一下日志,分别调用成功。将Unity和安卓之间互相调用的流程跑通。
part1 Unity/Cocos部分
每次都把各渠道SDK与游戏登录等逻辑写在一起很混乱,也不能重用,所以需要在这两者之间封装一层
SDKBase为SDK基础类,以后可以让iOS和安卓继承SDKBase,在SDKManager里面进行判断
BaseSDK
public class SDKBase {
/// <summary>
/// 初始化
/// </summary>
public virtual void Init() { }
/// <summary>
/// 登录
/// </summary>
public virtual void Login() { }
/// <summary>
/// 登出
/// </summary>
public virtual void Logout() { }
/// <summary>
/// 支付
/// </summary>
/// <param name="s"></param>
public virtual void Pay(string s) { }
/// <summary>
/// 游戏中心
/// </summary>
/// <param name="s"></param>
public virtual void GameCenter(string s) { }
}
安卓SDK 采用非静态方法
public class SDKAndroid : SDKBase {
//安卓渠道SDK集成类
/// <summary>
/// 安卓渠道SDK的Init接口入口
/// </summary>
public override void Init()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject jo = jo.GetStatic<AndroidJavaObject>("currentActivity"))
{
jo.Call("init");
}
}
}
/// <summary>
/// 安卓渠道SDK的Login接口入口
/// </summary>
public override void Login()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject jo = jo.GetStatic<AndroidJavaObject>("currentActivity"))
{
jo.Call("login");
}
}
}
/// <summary>
/// 安卓渠道SDK的Logout接口入口
/// </summary>
public override void Logout()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject jo = jo.GetStatic<AndroidJavaObject>("currentActivity"))
{
jo.Call("logout");
}
}
}
/// <summary>
/// 安卓渠道SDK的Pay接口入口
/// </summary>
public override void Pay(string s)
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject jo = jo.GetStatic<AndroidJavaObject>("currentActivity"))
{
jo.Call("pay", s);
}
}
}
/// <summary>
/// 安卓渠道SDK的GameCenter接口入口
/// </summary>
public override void GameCenter(string s)
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject jo = jo.GetStatic<AndroidJavaObject>("currentActivity"))
{
jo.Call("gameCenter", s);
}
}
}
}
SDKManager单例类,匹配相应的SDK,并调用相应SDK的接口
调用时直接
chenchenSDKMgr.Instance.Init();
这样就把SDK与项目逻辑隔离开,框架可以重复使用了
public class chenchenSDKMgr : MonoBehaviour {
private static chenchenSDKMgr mInstance;
public static chenchenSDKMgr Instance
{
get {
if (mInstance == null)
mInstance = new chenchenSDKMgr();
return mInstance;
}
}
private static SDKBase mSDKApi;
void Awake()
{
mInstance = this;
#if UNITY_EDITOR
mSDKApi = new SDKBase();
#elif UNITY_ANDROID //切换iOS/安卓(不同渠道)
mSDKApi = new SDKAndroid();
//#elif UNITY_IOS
#endif
}
public void Init()
{
mSDKApi.Init();
}
public void Login()
{
mSDKApi.Login();
}
public void Logout()
{
mSDKApi.Logout();
}
public void Pay(string s)
{
mSDKApi.Pay(s);
}
public void GameCenter(string s)
{
mSDKApi.GameCenter(s);
}
/// <summary>
/// Unity收到从SDK发来的通知
/// </summary>
/// <param name="s"></param> s为待解析的json文件
public void ReceiveNotifyFromSDK(string s)
{
Debug.LogError("Unity --------ReceiveNotifyFromSDK--------:" + s);
}
}
part2 Eclipse部分
新建一个Unity空工程,将他导出到ADT,作为SDK基类使用,libs里面有unity-classes.jar这个文件,就可以实现Unity部分的回调等,新建一个Android项目空工程,是具体某个渠道的SDK,把android-support-v4.jar文件(安卓相关)拷到上面那个工程中。
基类工程中新建BaseActivity Class,作为UnityPlayerActivity的扩展
public class BaseActivity extends UnityPlayerActivity{
public static String mUnityListenerObject = "chenchenSDK";
public static String mUnityListenerMethod = "ReceiveNotifyFromSDK";
@Override
public void onCreate(Bundle b) {
super.onCreate(b);
}
}
将两个项目都设置成库,并且渠道SDK引用基类SDK
MainActivity类继承BaseActivity,把Unity调用的安卓方法实现。
public class MainActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void login() {
Log.i("Unity", "login -------------- SDK");
}
public void init() {
Log.i("Unity", "init ---------------SDK");
}
public void logout() {
Log.i("Unity", "logout -------------SDK");
}
public void pay(String s) {
Log.i("Unity", "pay ----------------SDK");
}
public void gameCenter(String s) {
Log.i("Unity", "gameCenter -------------SDK");
}
}
使用的时候,将基类SDK和渠道SDK build出来的jar包导入Unity工程中。将渠道SDK的AndroidManifest文件也导入。
这样启动项为渠道SDK项目的MainActivity,然后从渠道SDK去调用基类
======================2017.6.28
Cocos2d-lua部分
如果项目使用Cocos引擎,需要在C++框架层使用jni与java底层交互,使用CallStaticMethod方法,获取SDK传回来的Callback,游戏逻辑内解析后传到服务器归档。
UserActivity单例模式,如果在Cocos中使用Require头文件,需要注意如果不写一个单例模式get方法的话,多次返回会产生不同的User类,在别的文件中访问就会被初始化。
jni返回一次登陆数据之后,可以进行归档,将微信和qq三方授权的TokenID和密码存储在本地并手动创建一个原生的账号,可以避免多次请求微信授权的问题。
密码在游客登录的时候已经自动生成,需要执行一次修改密码的操作。如果绑定了手机,就不用进行密码修改。在不同的渠道,该操作均相同,所以需要保留渠道信息。
结合新手引导界面
有两种方式,第一种是在界面上放一层遮罩,通过改变按钮的层级来改变他们的交互性(是否能够进行响应),第二种是动态改变按钮的位置和响应方法,使用入口函数做成Manager来实现。
第一种方式较为复杂但是易读,但是可以写config配置文件来较为方便的修改前后顺序。第二种实现较为简单。
我自己使用的是第二种方法。
网友评论