Unity3d Android SDK接入解析(四)通用的Android SDK接入中间件

版权声明:本文为博主Atany原创文章,未经博主允许不得转载。博客地址:http://blog.csdn.net/yang8456211 https://blog.csdn.net/yang8456211/article/details/52231305

一、前言

接入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

如果还有不明白,可以到群里交流

unity3d-sdk交流Q群:113659593

杨光(atany)原创,转载请注明博主与博文链接,未经博主允许,禁止任何商业用途。
博文地址:http://blog.csdn.net/yang8456211/article/details/52231305
博客地址:http://blog.csdn.net/yang8456211
本文遵循“署名-非商业用途-保持一致”创作公用协议

猜你喜欢

转载自blog.csdn.net/yang8456211/article/details/52231305
今日推荐