一、前言
接入Android SDK正式告一段落,在这段时间里面,依次接入了华为、应用宝、小米、360等等大大小小十来个SDK,也算对Unity接入渠道SDK有了较为全面的理解,对各个渠道的坑也算深有体会。。。。在接入过程中时间比较紧张,没办法抽空来进行总结深思。今天正好有空,便对之前的接入SDK的代码进行了一次重构,写了一个比较通用的Unity接入Android SDK的中间件,前人栽树,后人乘凉。
进入正题
如果有对一些只是有疑问的,可以看看我之前的三篇文章:
传送门:
Unity3d Android SDK接入解析(一)Unity3d 与 Android之间的互相调用:
http://blog.csdn.net/yang8456211/article/details/51331358
Unity3d Android SDK接入解析(二)Unity3d Android SDK的设计与两种接入方式
http://blog.csdn.net/yang8456211/article/details/51356193
Unity3d Android SDK接入解析(三)接入Android Library的理解(爱贝云支付为例)
http://blog.csdn.net/yang8456211/article/details/51435465
二、关于中间件的一些思考
2.1 为什么不用第三方平台
为什么要自己做一个Unity接入Android SDK的中间件呢?市面上例如Anysdk、易接这种第三方渠道是可以满足接入一次,生成大部分的SDK的,但是由于大渠道的审查越来越严格,已经禁止了这种第三方的平台SDK。因此,这些大渠道则必须由我们自己来接入了(不过二、三线渠道仍然是可以用第三方进行接入的),如果每个渠道都使用一个单独工程来管理,这无疑是一种非常浪费时间而且难以维护的事情,因此我想做的就是一个Unity的接入Android SDK的插件,所有的SDK的逻辑都封装好在Android层面,不同的游戏都可以按照相同的规则来接入进来,只需要调用通用的接口,准备好对应的资源即可。
2.2 怎么样做方便
我希望把这个中间件做的尽量能够通用,而且能够方便拆分、迭代。对Unity层面逻辑透明,只需要关注接口调用的时机和传入的参数。
- 通用,形式简单
- 只关注SDK业务逻辑
- 调用简单
—— 通用,形式简单 ——
先说说通用吧:
对于Unity游戏来说,通常以Plugins的形式接入SDK比较方便,所以从这个思路出发,中间件的形式,我决定做成了jar包,而不是一个Library的工程,jar包里面只包含纯代码,没有资源和任何配置文件,调用方只用把jar包放在 Plugins/Android/libs 里面就可以使用了。对于不同游戏来说,没有差别。
最终的形式,就是一个uasdkinter的jar包,所有的SDK的逻辑会集成在这个jar里面。
形式简单的也有一层含义是,方便集成和拆分:
因此在package的设计上,每个渠道独立一个package放渠道代码,理论上我们导出jar包的时候,直接把所有渠道的代码都打进jar包就可以了,因为每次代码会根据传入的channel执行唯一的渠道,其他代码也就放在那了。
但是有些渠道会进行代码检测,例如360,会检测到包内含有小米支付相关的代码,审核不过,对应我们只需要在打jar的时候,勾选去掉对应的package就可以了。(因为是重构的代码框架,并没有包含很多sdk)
—— 只关注SDK业务逻辑 ——
中间件本身,只包含设计思想和一个简洁的框架。在接入渠道SDK的时候,我们只需要把渠道的SDK代码以一定的规则加入到中间件中即可。
所以这个中间件必须要健壮,框架写好之后,再添加新的SDK代码必须比较方便,无需对框架做大的改动。
因此我使用接口来实现,每个渠道SDK有两个class,一个管理账号信息,一个管理支付信息,账号与支付分离。
账号接口:
public interface UAGameInterf {
// 初始化
public void init(JSONObject sJson);
// 登录
public void login(JSONObject sJson);
// 登出
public void logout();
// 退出游戏
public void exit();
// 初始化参数检查
public boolean initParams(JSONObject sJson);
// 设置生命周期的函数
public void lifeCycle(int status);
// 存储用户信息
public void upUserInfo(JSONObject sJson);
}
支付接口:
public interface UAPayInterf {
// 支付
public void pay();
// 初始化参数
public boolean initParams(JSONObject sJson);
}
在添加SDK的时候,只需要新建账号class和支付的class,分别实现对应的接口,而不用管外层是怎么调用的,消息是怎么返回Unity的,而只用具体的实现每个接口即可,做到只关注SDK的业务逻辑(具体接口的设计说明后面详叙)。
—— 调用简单 ——
调用上,C#初始化“包名+类名”的AndroidJavaClass对象,使用这个对象来调用对应功能,区别于新建一个Activity继承UnityPlayerActivity 的模式,这个方法避免了一系列的蛋疼的问题(例如中间件工程需要和游戏工程的包名一样)
C#的调用:
中间件工程的包名是: com.uainter.main
接口类名是:UAMain
因此可以在C#创建AndroidJavaClass对象:
AndroidJavaClass ajc_SDKCall ajc_SDKCall = new AndroidJavaClass("com.uainter.main.UAMain");
为了方便调用,把对外的接口都做成了静态方法,所以用CallStatic去调用,因为每个渠道需要的参数类型和参数个数不确定,因为把传入参数定义成了一个Json。
例如调用小米渠道的Init方法:
小米渠道需要3个参数:appid、appkey、islandscape(登录与支付横屏还是竖屏显示)
string json = "{‘channel‘:‘11‘,‘debugmode‘:1,‘appid‘:‘xxx‘,‘appkey‘:‘xxx‘,‘islandscape‘:false}";
ajc_SDKCall.CallStatic("uaInit",json);
Login方法:
string json = "{}";
ajc_SDKCall.CallStatic("uaLogin",json);
对于每个可能会有参数传入的方法,都设置了一个json对象作为参数,例如login方法,在接入应用宝的时候,需要在json数据中传入一个platform来判断是登录微信还是QQ。
中间键暴露出的接口有以下几个:
2.3 一些特殊操作的思考与处理
Activity生命周期的处理
理论我希望做到不需要修改启动的Activity,所以Activity生命周期的处理,放在了C#去控制,Android提供接口public void lifeCycle(int status);
在这个接口里面处理渠道SDK需要做的生命周期操作。
例如华为:
(Android 代码)
public void lifeCycle(int status) {
if (getActivity() == null) {
DybGSdkUtil.E("还未Init初始化,不执行生命周期操作 ");
return;
}
switch (status) {
case DybGSdkConstants.onStart:
break;
case DybGSdkConstants.onResume:
BuoyOpenSDK.getIntance().showSmallWindow(getActivity());
break;
case DybGSdkConstants.onPause:
BuoyOpenSDK.getIntance().hideSmallWindow(getActivity());
BuoyOpenSDK.getIntance().hideBigWindow(getActivity());
break;
case DybGSdkConstants.onStop:
break;
case DybGSdkConstants.onDestroy:
OpenHwID.releaseResouce();
BuoyOpenSDK.getIntance().destroy(getActivity());
break;
default:
break;
}
}
(C#调用)
void OnApplicationPause(bool isPause)
{
if (isPause) {
string json = "{‘status‘:‘3‘}";
ajc_SDKCall.CallStatic("uaLifeCycle",json);
}
}
void OnApplicationFocus(bool isFocus)
{
if (isFocus)
{
if (ajc_SDKCall != null){
string json = "{‘status‘:‘1‘}";
ajc_SDKCall.CallStatic("uaLifeCycle",json);
json = "{‘status‘:‘2‘}";
ajc_SDKCall.CallStatic("uaLifeCycle",json);
}
}
}
void OnApplicationQuit()
{
string json = "{‘status‘:‘5‘}";
ajc_SDKCall.CallStatic("uaLifeCycle",json);
}
(对应的status和生命周期)
// Android Activity生命周期
public static final int onStart = 1;
public static final int onResume = 2;
public static final int onPause = 3;
public static final int onStop = 4;
public static final int onDestroy = 5;
public static final int onRestart = 6;
实在遇到需要Activity的地方怎么处理?
只有在接入应用宝的时候,遇到了需要接入Activity的两个方法onNewIntent和onActivityResult时,需要接受qq和微信的回调,这种情况我也没有想到什么好办法,只有创建一个Activity,然后实现这个两个方法,并修改这个Activity为AndroidManifest里面的启动Activity。
遇到需要自定application的情况呢?
跟Activity类似,这个时候我们新建一个Application即可。
大部分的SDK方法需要在UI线程中调用
这个之前有说过,在这里只是列出来不详述了:
例如登录:
public static void uaLogin(String jsonString) {
try {
final JSONObject sJson = new JSONObject(jsonString);
final UAGameInterf uaManager = getSdkObj(sChannel);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
uaManager.login(sJson);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
怎么发送消息回Unity
// 发送消息回Unity3d
public static void dybCallback(JSONObject rjson) {
UnityPlayer.UnitySendMessage(UAMain.callBackobj, UAMain.callBackFun,
rjson.toString());
}
其中callBackobj 和 callBackFun,分别对应接收返回值的对象的名称和回调方法。(此处我是写死的常量,也可以通过在init中传入对应的key来动态的修改这两个值)
可以看到,返回的也是一个json,里面包括了一个“callbackType”的key用来判断是哪个接口回调的结果,例如Init回调:
JSONObject jsonObj = new JSONObject();
String code = "1";
jsonObj.put("callbackType", "Init");
jsonObj.put("code", code);
UAMain.dybCallback(jsonObj);
三、中间件对外接口说明
- uaInit
public static void uaInit(String jsonString)
主要用于各个渠道SDK的初始化,传入的json字符串中,必须包含的是,debugMode和channel这两个key,channel是用于区分目前调用的是哪个渠道,debugMode是用于区分调试模式还是正式模式(一般SDK都会有两种模式),这里的debugMode我也用来作为显示日志的开关。剩下的key就要根据不同SDK所需要的不同的参数来传入。
- uaLogin
public static void uaLogin(String jsonString)
一般SDK不用传入jsonString,直接传一个空的json字符串“{}”即可,当有些SDK需要在Login功能中加上切换账号功能是,我会传一个type进来,用来判断此时的操作是登录还是切换账号。
- uaLogout
public static void uaLogout()
用于账号的退出,这个接口不需要参数。
- uaExit
public static void uaExit()
用于退出游戏,一般SDK会有一个弹出框来显示一些论坛或者相关的广告信息,这个接口也不需要参数。
- uaUpUserInfo
public static void uaUpUserInfo
用于信息的打点,就是报备一些信息,例如创建角色、角色升级、退出等等。
- uaLifeCycle
public static void uaLifeCycle
用于生命周期函数的调用。
- uaPay
public static void uaPay
用于支付。
四、后续思考
- 最初写这个框架的时候,大概花费了2天的时间,后续接入中遇到了一些问题,也对这个中间件进行了一些修改,总的来说,能够满足基本上市面上大部分sdk的接入(至少我现在没有遇到接入不了的)。重构之后更加的简洁了,删掉了不少无用的东西。
- 但是对于需要监听onNewIntent等函数的SDK,虽然可以处理(新建一个Activity去处理),却不太满意。在思考是否做成一个Activity形式的中间件更好(而不是一个Java的class),当然,还有生命周期上的处理,感觉很多东西都有优化的空间。
- 花了整整一天写的东西,也希望“爬虫们”在转发的同时,也留个原文链接,因为不仅仅是我想把我拥有的知识去分享给他人,我也希望从他人的到宝贵的意见,指出我的错误和不足,这才是我写这篇文章的用意,是作为一个程序员最珍贵的东西,在此谢谢。
源码地址:
https://github.com/yang8456211/UASDKInter
杨光(atany)原创,转载请注明博主与博文链接,未经博主允许,禁止任何商业用途。
博文地址:http://blog.csdn.net/yang8456211/article/details/52231305
博客地址:http://blog.csdn.net/yang8456211
本文遵循“署名-非商业用途-保持一致”创作公用协议