美文网首页手游SDK
手游SDK — 第四篇(SDK架构设计代码实现篇(下)- 项目需

手游SDK — 第四篇(SDK架构设计代码实现篇(下)- 项目需

作者: Bzaigege | 来源:发表于2019-01-29 14:35 被阅读7次

    第二部分:项目需求开发

    基础库搭建好了之后就是根据项目需求进行实际功能开发了,因为不同的项目有不同的项目需求,我简单的以项目初始化、账号登录/切换账号/账号登出、支付三大功能点来进行框架的代码实现。

    1、需求开发 - Manager控制模块

    Manager模块是SDK的核心模块,主要负责业务的功能实现及逻辑控制。根据项目需求,暂定为初始化Manager、账号Manager、支付Manager。

    初始化Manager:处理SDK的初始化逻辑,全局参数缓存、环境切换、权限问题等。
    public class InitManager {
    
        private final String TAG = getClass().getSimpleName();
    
        private volatile static InitManager INSTANCE;
    
        private InitManager() {
        }
    
        public static InitManager getInstance() {
            if (INSTANCE == null) {
                synchronized (InitManager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new InitManager();
                    }
                }
            }
            return INSTANCE;
        }
    
        /**
         * 加载SDK项目配置入口插件(这是项目最开始加载的)
         * @param context 上下文
         * @param isdebug 日志调试开关
         */
        public void initApplication(Application cxt, Context context, boolean isdebug){
    
            ApplicationCache.init(cxt);
            LogUtils.setDebugLogModel(isdebug);
            ProjectManager.init(context).loadAllProjects();
            //聚合SDK加载渠道插件
            ChannelManager.init(context).loadChannel();
        }
    
    
        private static Handler sApiHandler;
        private static boolean initState = false;
    
        /**
         * SDK初始化逻辑
         * @param activity
         * @param callBackListener
         */
        public void init(final Activity activity, final String gameid, final String gamekey, final CallBackListener callBackListener) {
    
            if (sApiHandler == null) {
                HandlerThread ht = new HandlerThread("project_sdk_thread",
                        Process.THREAD_PRIORITY_BACKGROUND);
                ht.start();
                sApiHandler = new Handler(ht.getLooper());
            }
    
            Runnable r = new Runnable() {
                @Override
                public void run() {
    
                    //1、初始化全局缓存变量
                    BaseCache.init(activity.getApplication());
                    BaseCache.getInstance().put(KeyConfig.GAME_ID,gameid);
                    BaseCache.getInstance().put(KeyConfig.GAME_KEY,gamekey);
    
                    //2、初始化SDK参数
                    SDKInfoCache.getDefault(activity.getApplication());
    
                    //3、初始化持久化数据
                    SharePreferencesCache spCache = new SharePreferencesCache(activity);
                    spCache.init();
    
                    //4、加载功能插件
                    PluginManager.init(activity).loadAllPlugins();
    
                    //5、初始化域名配置
                    UrlConfig.initUrl();
    
                    //6、开始初始化逻辑
                    startInitLogic(activity,callBackListener);
    
                }
            };
            sApiHandler.post(r);
        }
    
    
        /**
         * 真正的初始化逻辑
         */
        private void startInitLogic(final Activity activity, final CallBackListener callBackListener){
    
            //-----------------------------已初始化完成--------------------------------
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setInitState(true);
                    callBackListener.onSuccess(null);
                }
            });
        }
    
        /**
         * 初始化功能插件()
         */
        private void initFunctionPlugin(Activity activity){
    
            //腾讯bugly日志收集
    
        }
    
    
        public void setInitState(boolean state) {
            initState = state;
            //将当前状态存储到全局变量供其他模块插件使用
            BaseCache.getInstance().put(KeyConfig.IS_INIT,initState);
        }
    
        public boolean getInitState() {
            return initState;
        }
    }
    
    账号Manager:管理账号的各个功能接口:登录、切换账号、注销账号、绑定账号。登录可细分为设备登陆、游客登录、账号登陆、三方登陆(google/facebook/微信)等登录逻辑和切换、绑定逻辑。
    public class AccountManager {
    
        public static final String TAG = "AccountManager";
    
        private volatile static AccountManager INSTANCE;
    
        private AccountManager() {
        }
    
        public static AccountManager getInstance() {
            if (INSTANCE == null) {
                synchronized (AccountManager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new AccountManager();
                    }
                }
            }
            return INSTANCE;
        }
    
        private Activity mActivity;
        private AccountBean mLoginInfo; //当前登陆的登陆信息
        private boolean isSwitchAccount = false; //通过标记位来判断是否是切换账号按钮的登录回调
    
    
        /******************************************      获取Project账号监听     ****************************************/
    
        private CallBackListener projectLoginCallBackListener;
        public void setLoginCallBackLister(CallBackListener callBackLister){
            projectLoginCallBackListener = callBackLister;
        }
    
        private void CallBackToProject(int event, int code, AccountBean accountBean, String msg){
    
            //设置回调信息
            AccountCallBackBean accountCallBackBean = new AccountCallBackBean();
            accountCallBackBean.setEvent(event); //事件类型ID
            accountCallBackBean.setErrorCode(code); //事件码
            accountCallBackBean.setAccountBean(accountBean); //事件的账号信息
            accountCallBackBean.setMsg(msg); //设置事件的信息
    
            if (projectLoginCallBackListener != null){
                projectLoginCallBackListener.onSuccess(accountCallBackBean);//回调给Project的信息
            }
        }
    
    
        /**
         * 登录结果监听
         */
        private CallBackListener LoginCallBackLister = new CallBackListener<AccountBean>(){
    
            @Override
            public void onSuccess(AccountBean loginInfo) {
                LogUtils.d(TAG, "loginInfo:" + loginInfo.toString());
    
                mLoginInfo = loginInfo;
                //登陆成功,设置登录信息
                setLoginSuccess(loginInfo);
    
                if (isSwitchAccount){
                    CallBackToProject(TypeConfig.SWITCHACCOUNT, ErrCode.SUCCESS,loginInfo, "user switchAccount success");
                    isSwitchAccount = false; //置为false
    
                }else {
                    CallBackToProject(TypeConfig.LOGIN,ErrCode.SUCCESS,loginInfo, "user login success");
                }
            }
    
            @Override
            public void onFailure(int code, String msg) {
                mLoginInfo = null; //当前登陆失败就置为null
    
                if (isSwitchAccount){
    
                    if (code == ErrCode.CANCEL){ //如果切换账号时,不走登录,给登出回调
                        CallBackToProject(TypeConfig.LOGOUT, ErrCode.SUCCESS, null, "user logout success");
    
                    }else {
                        CallBackToProject(TypeConfig.SWITCHACCOUNT, code, null, msg);
                    }
    
                }else {
                    CallBackToProject(TypeConfig.LOGIN, code, null, msg);
                }
            }
        };
    
        /******************************************      登录     ****************************************/
    
    
        /**
         * 显示登录界面
         */
        public void showLoginView(final Activity activity, HashMap<String,Object> loginMap){
            mActivity = activity;
    
    
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            builder.setMessage("是否登录?");
            builder.setTitle("登录界面");
            builder.setPositiveButton("登录",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
    
                            AccountBean loginInfo = new AccountBean();
                            loginInfo.setLoginState(true); //将登录成功状态返回
                            loginInfo.setUserToken("dasfkaf-SAFA-kfad");
                            loginInfo.setUserID("userID-123");
                            loginInfo.setUserName("测试用户"); //聚合将用名设置为UserID
                            LoginCallBackLister.onSuccess(loginInfo);
    
                        }
                    });
            builder.setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            LoginCallBackLister.onFailure(ErrCode.FAILURE,"login fail");
                        }
                    });
            builder.create().show();
    
        }
    
    
        /**
         * 授权登录,具体项目具体实现逻辑
         */
        public void authLogin(Activity activity, HashMap<String,Object> loginMap){
            mActivity = activity;
    
            AccountBean loginInfo = new AccountBean();
            loginInfo.setLoginState(true); //将登录成功状态返回
            loginInfo.setUserToken("dasfkaf-SAFA-kfad");
            loginInfo.setUserID("userID-123");
            loginInfo.setUserName("测试用户"); //聚合将用名设置为UserID
    
            LoginCallBackLister.onSuccess(loginInfo);
        }
    
    
        /**
         * 获取当前登陆状态,默认false
         * @return
         */
        public boolean getLoginState() {
            if (mLoginInfo != null){
                return mLoginInfo.getLoginState();
            }
            return false;
        }
    
        /******************************************      切换账号    ****************************************/
    
        /**
         * 切换账号
         * @param activity
         */
        public void switchAccount(Activity activity){
    
            mActivity = activity;
    
            //先走登出逻辑
            mLoginInfo = null; //登录信息清空
            isSwitchAccount = true;
            clearLoginInfo(activity);
        }
    
    
        /******************************************      登出   ****************************************/
    
        /**
         * 账号登出
         */
        public void logout(Activity activity){
    
            mActivity = activity;
    
            mLoginInfo = null; //登录信息清空
            isSwitchAccount = false;
            clearLoginInfo(activity);
    
            CallBackToProject(TypeConfig.LOGOUT, ErrCode.SUCCESS, null, "user logout success");
        }
    
    
        /**
         * 设置登录成功行为
         */
        private void setLoginSuccess(AccountBean loginInfo){
    
            if (loginInfo != null){
                BaseCache.getInstance().put(KeyConfig.PLAYER_ID,loginInfo.getUserID());
                BaseCache.getInstance().put(KeyConfig.PLAYER_NAME,loginInfo.getUserName());
                BaseCache.getInstance().put(KeyConfig.PLAYER_TOKEN,loginInfo.getUserToken());
    
                //将当前状态存储到全局变量供其他模块插件使用
                BaseCache.getInstance().put(KeyConfig.IS_LOGIN, getLoginState());
            }
        }
    
    
        /**
         * 清空登陆信息
         */
        private void clearLoginInfo(Activity activity){
    
            mLoginInfo = null;
    
            //清空内存的用户信息
            BaseCache.getInstance().put(KeyConfig.PLAYER_ID,"");
            BaseCache.getInstance().put(KeyConfig.PLAYER_NAME,"");
            BaseCache.getInstance().put(KeyConfig.PLAYER_TOKEN,"");
    
            //将当前状态存储到全局变量供其他模块插件使用
            BaseCache.getInstance().put(KeyConfig.IS_LOGIN, getLoginState());
    
        }
    
    }
    
    支付Manager:购买管理类,管理SDK的各个购买功能接口:创建订单、三方支付、运营商支付、渠道支付、补单逻辑、包月、订阅等。注意可能还会有各个复杂的支付逻辑: 可能会先短代支付、然后渠道支付、三方支付,还有后台切换支付开关等。
    public class PurchaseManager {
    
        public static final String TAG = "PurchaseManager";
    
        private volatile static PurchaseManager INSTANCE;
    
        private PurchaseManager() {
        }
    
        public static PurchaseManager getInstance() {
            if (INSTANCE == null) {
                synchronized (PurchaseManager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new PurchaseManager();
                    }
                }
            }
            return INSTANCE;
        }
    
        /**
         * 创建订单,具体项目具体实现
         */
        public void createOrderId(Activity activity, HashMap<String, Object> payParams , final CallBackListener callBackListener){
    
            LogUtils.debug_d(TAG,"payParams = " + payParams.toString());
            String orderID = "DD1441";
            callBackListener.onSuccess(orderID);
    
        }
    
        /**
         * 显示支付界面
         */
        public void showPayView(Activity activity, HashMap<String, Object> payParams, final CallBackListener callBackListener){
            LogUtils.debug_d(TAG,"payParams = " + payParams.toString());
    
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            String message = "充值金额:" + "2"
                    + "\n商品名称:" + "大饼"
                    + "\n商品数量:" + "1"
                    + "\n资费说明:" + "2元";
            builder.setMessage(message);
            builder.setTitle("请确认充值信息");
            builder.setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(final DialogInterface dialog, int index) {
                            //支付结果回调到这里来
                            PurchaseResult purchaseResult = new PurchaseResult(PurchaseResult.PurchaseState,null);
                            callBackListener.onSuccess(purchaseResult);
                        }
                    });
            builder.setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            callBackListener.onFailure(ErrCode.FAILURE,"pay fail");
                        }
                    });
            builder.create().show();
        }
    }
    
    

    2、需求开发 - Plugin三方功能插件层

    Plugin三方功能插件层分两部分组成:反射API和具体Plugin插件。反射API是动态插拔功能插件的关键,可以打包时动态打对应的供插件。Plugin插件是具体实现和封装对应的功能层。额外拓展新的功能插件时,继承Plugin类即可。下面以微信插件为例:

    微信功能Plugin:封装和实现微信的登录、支付、分享等常见功能
    public class WechatPlugin extends Plugin {
    
        private String TAG = "WechatPlugin";
    
        @Override
        protected synchronized void initPlugin() {
            super.initPlugin();
            LogUtils.d(TAG,"init " + getClass().getSimpleName());
        }
    
        /**
         * 调用微信支付接口
         */
        public void wechatPay(Context context, Map<String,Object> payMap, CallBackListener callBackListener){
            WechatPay.getInstance().pay(context,payMap,callBackListener);
        }
    
    
        /**
         * 调用微信登录接口
         */
        public void wechatLogin(Context context, Map<String,Object> LoginMap, CallBackListener callBackListener){
            
        }
    
    
        /**
         * 调用微信分享接口
         */
        public void wechatShare(Context context, Map<String,Object> ShareMap, CallBackListener callBackListener){
    
        }
    
        /**
         * 根据当前的生命周期
         * @param context
         */
        @Override
        public void onResume(Context context) {
            WechatPay.getInstance().onResume(context);
        }
    }
    
    微信功能PluginAPI:对接微信Plugin接口。
    public class WechatPluginApi extends PluginReflectApi {
    
        private String TAG = "WechatPluginApi";
    
        private Plugin wechatPlugin;
    
        private volatile static WechatPluginApi INSTANCE;
    
        private WechatPluginApi() {
            wechatPlugin = PluginManager.getInstance().getPlugin("plugin_wechat");
        }
    
        public static WechatPluginApi getInstance() {
            if (INSTANCE == null) {
                synchronized (WechatPluginApi.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new WechatPluginApi();
                    }
                }
            }
            return INSTANCE;
        }
    
        /**
         * 调用微信app支付
         */
        public void pay(Context context, Map<String,Object> map, CallBackListener callBackListener){
    
            if (wechatPlugin != null){
                invoke(wechatPlugin,"wechatPay",new Class<?>[]{Context.class, Map.class, CallBackListener.class},
                        new Object[]{context, map, callBackListener});
            }
        }
    
    }
    

    3、需求开发 - Project项目业务层

    Project层主要分自定义SDK项目和聚合SDK项目两大类,自定义SDK是自己实现SDK的功能逻辑;聚合SDK主要是封装渠道SDK用于游戏的联运。业务需求是不一样的。相对而已聚合SDK会简单点。如有新的项目需求,可继承Project对应实现就OK了。主要自定义SDK为例讲解下

    public class CustomProject extends Project{
    
        private final String TAG = getClass().getSimpleName();
    
    
        /**
         * 项目实例化入口
         */
        @Override
        protected synchronized void initProject() {
            LogUtils.d(TAG, getClass().getSimpleName() + " has init");
            super.initProject();
        }
    
    
        /******************************************      初始化      ****************************************/
    
        @Override
        public void init(Activity activity, String gameid, String gamekey, final CallBackListener callBackListener) {
            LogUtils.d(TAG,"init");
    
            if (activity == null || callBackListener == null) {
                callBackListener.onFailure(ErrCode.PARAMS_ERROR,"activity or callBackListener is null");
                return;
            }
    
            //设置账号监听
            AccountManager.getInstance().setLoginCallBackLister(projectAccountCallBackListener);
    
            InitManager.getInstance().init(activity, gameid, gamekey, new CallBackListener() {
                @Override
                public void onSuccess(Object object) {
                    callBackListener.onSuccess(null);
                }
    
                @Override
                public void onFailure(int code, String msg) {
                    callBackListener.onFailure(code,msg);
                }
            });
        }
    
    
        /******************************************      账号      ****************************************/
    
        /*** SDKApi层设置回调监听 */
        private CallBackListener ApiAccountCallback;
    
        @Override
        public void setAccountCallBackLister(CallBackListener callBackLister) {
            ApiAccountCallback = callBackLister;
        }
    
        /**
         * 监听AccountManager登录、切换账号、绑定、注销的回调信息
         */
        private CallBackListener projectAccountCallBackListener = new CallBackListener<AccountCallBackBean>() {
    
            @Override
            public void onSuccess(AccountCallBackBean callBackBean) {
                ApiAccountCallback.onSuccess(callBackBean);
            }
    
            @Override
            public void onFailure(int code, String msg) {
                //不会走到这里来
            }
        };
    
        private void AccountOnFailCallBack(int event, int code, String msg){
    
            AccountCallBackBean callBackBean = new AccountCallBackBean();
            callBackBean.setEvent(event);
            callBackBean.setErrorCode(code);
            callBackBean.setMsg(msg);
            ApiAccountCallback.onSuccess(callBackBean);
        }
    
    
        @Override
        public void login(Activity activity, HashMap<String, Object> loginParams) {
            LogUtils.d(TAG,"login");
    
            if (!InitManager.getInstance().getInitState()){
                Toast.makeText(activity,"请先初始化",Toast.LENGTH_SHORT).show();
                return;
            }
    
            if (activity == null ) {
                AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,"activity is null");
                return;
            }
    
            AccountManager.getInstance().showLoginView(activity,loginParams);
        }
    
    
        @Override
        public void switchAccount(Activity activity) {
            LogUtils.d(TAG,"switchAccount");
    
            if (!InitManager.getInstance().getInitState()){
                Toast.makeText(activity,"请先初始化",Toast.LENGTH_SHORT).show();
                return;
            }
    
            if (!AccountManager.getInstance().getLoginState()){
                AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT,ErrCode.NO_LOGIN,"account has not login");
                return;
            }
    
            if (activity == null ) {
                AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,"activity is null");
                return;
            }
    
            AccountManager.getInstance().switchAccount(activity);
        }
    
        @Override
        public void logout(Activity activity) {
            LogUtils.d(TAG,"logout");
    
            if (!InitManager.getInstance().getInitState()){
                Toast.makeText(activity,"请先初始化",Toast.LENGTH_SHORT).show();
                return;
            }
    
            if (!AccountManager.getInstance().getLoginState()){
                AccountOnFailCallBack(TypeConfig.LOGOUT,ErrCode.NO_LOGIN,"account has not login");
                return;
            }
    
            if (activity == null ) {
                AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,"activity is null");
                return;
            }
    
            AccountManager.getInstance().logout(activity);
        }
    
    
        /******************************************      购买      ****************************************/
    
    
        @Override
        public void pay(Activity activity, HashMap<String, Object> payParams, CallBackListener callBackListener) {
            LogUtils.d(TAG,"pay");
    
            if (!InitManager.getInstance().getInitState()){
                Toast.makeText(activity,"请先初始化",Toast.LENGTH_SHORT).show();
                return;
            }
    
            if (!AccountManager.getInstance().getLoginState()){
                callBackListener.onFailure(ErrCode.NO_LOGIN,"account has not login");
                return;
            }
    
            if (activity == null || payParams == null || callBackListener == null) {
                callBackListener.onFailure(ErrCode.PARAMS_ERROR,"activity or PayParams or callBackListener is null");
                return;
            }
    
            PurchaseManager.getInstance().showPayView(activity,payParams,callBackListener);
        }
    
    
        /******************************************      退出      ****************************************/
    
    
        /**
         * 退出SDK
         */
        @Override
        public void exit(Activity activity, CallBackListener callBackListener) {
            LogUtils.d(TAG,"exit");
    
            if (activity == null || callBackListener == null) {
                callBackListener.onFailure(ErrCode.PARAMS_ERROR,"activity or callBackListener is null");
                return;
            }
    
            callBackListener.onFailure(ErrCode.NO_EXIT_DIALOG,"channel not exitDialog");
        }
    
    
        /*************************************  生命周期接口(必接) ****************************************/
    
        @Override
        public void onCreate(Activity activity, Bundle savedInstanceState) {
            LogUtils.d(TAG,"onCreate");
    
            if (InitManager.getInstance().getInitState()){
                super.onCreate(activity, savedInstanceState);
            }
        }
    
        @Override
        public void onStart(Activity activity) {
            LogUtils.d(TAG,"onStart");
    
            if (InitManager.getInstance().getInitState()){
                super.onStart(activity);
            }
        }
    
        @Override
        public void onResume(Activity activity) {
            LogUtils.d(TAG,"onResume");
    
            if (InitManager.getInstance().getInitState()){
                super.onResume(activity);
            }
        }
    
        @Override
        public void onPause(Activity activity) {
            LogUtils.d(TAG,"onPause");
    
            if (InitManager.getInstance().getInitState()){
                super.onPause(activity);
            }
        }
    
        @Override
        public void onStop(Activity activity) {
            LogUtils.d(TAG,"onStop");
    
            if (InitManager.getInstance().getInitState()){
                super.onStop(activity);
            }
        }
    
        @Override
        public void onDestroy(Activity activity) {
            LogUtils.d(TAG,"onDestroy");
    
            if (InitManager.getInstance().getInitState()){
                super.onDestroy(activity);
            }
        }
    
        @Override
        public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
            LogUtils.d(TAG,"onActivityResult");
    
            if (InitManager.getInstance().getInitState()){
                super.onActivityResult(activity, requestCode, resultCode, data);
            }
        }
    
        @Override
        public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions,int[] grantResults) {
            LogUtils.d(TAG,"onRequestPermissionsResult");
    
            if (InitManager.getInstance().getInitState()){
                super.onRequestPermissionsResult(activity, requestCode, permissions, grantResults);
            }
        }
    }
    

    4、需求开发 - 项目Channel业务层

    主要是面向聚合SDK项目,主要封装渠道的SDK内容。如需封装新的渠道SDK,继承Channel类即可。

    public class TestChannelSDK extends Channel {
    
        private final String TAG = getClass().getSimpleName();
    
        @Override
        protected void initChannel() {
            LogUtils.d(TAG, getClass().getSimpleName() + " has init");
        }
    
        @Override
        public String getChannelID() {
            return "1";
        }
    
        @Override
        public boolean isSupport(int FuncType) {
    
            switch (FuncType){
                case TypeConfig.FUNC_SWITCHACCOUNT:
                    return true;
    
                case TypeConfig.FUNC_LOGOUT:
                    return true;
    
                case TypeConfig.FUNC_SHOW_FLOATWINDOW:
                    return true;
    
                case TypeConfig.FUNC_DISMISS_FLOATWINDOW:
                    return true;
    
                default:
                    return false;
            }
        }
    
        @Override
        public void init(Context context, HashMap<String, Object> initMap, CallBackListener initCallBackListener) {
            LogUtils.d(TAG,getClass().getSimpleName() + " init");
            initOnSuccess(initCallBackListener);
        }
    
        @Override
        public void login(Context context, HashMap<String, Object> loginMap, CallBackListener loginCallBackListener) {
            LogUtils.d(TAG,getClass().getSimpleName() + " login");
            showLoginView(context,loginCallBackListener);
        }
    
        @Override
        public void switchAccount(final Context context, final CallBackListener changeAccountCallBackLister) {
    
            LogUtils.d(TAG,getClass().getSimpleName() + " switchAccount");
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage("是否切换账号?");
            builder.setTitle("切换账号");
            builder.setPositiveButton("切换账号",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            showLoginView(context,changeAccountCallBackLister);
                        }
                    });
            builder.setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            switchAccountOnCancel("channel switchAccount cancel",changeAccountCallBackLister);
                        }
                    });
            builder.create().show();
        }
    
        @Override
        public void logout(Context context, final CallBackListener logoutCallBackLister) {
    
            LogUtils.d(TAG,getClass().getSimpleName() + " logout");
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage("是否注销账号?");
            builder.setTitle("注销账号");
            builder.setPositiveButton("成功",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            logoutOnSuccess(logoutCallBackLister);
                        }
                    });
            builder.setNegativeButton("失败",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            logoutOnFail("channel logout fail",logoutCallBackLister);
                        }
                    });
            builder.create().show();
    
        }
    
        @Override
        public void pay(Context context, HashMap<String, Object> payMap, final CallBackListener payCallBackListener) {
    
            LogUtils.d(TAG,getClass().getSimpleName() + " pay");
    
            String orderID = (String) payMap.get("orderId");
            String productName = (String) payMap.get("productName");
            String productDesc = (String) payMap.get("productDesc");
            String money = String.valueOf(payMap.get("money"));
            String productID = String.valueOf(payMap.get("productID"));
            LogUtils.d(TAG,productID);
    
            final HashMap<String,Object> paymap = new HashMap<>();
            paymap.put("orderID",orderID);
            paymap.put("productName",productName);
            paymap.put("money",money);
    
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            String message = "充值金额:" + money
                    + "\n商品名称:" + productName
                    + "\n商品数量:" + "1"
                    + "\n资费说明:" + productDesc;
            builder.setMessage(message);
            builder.setTitle("请确认充值信息");
            builder.setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(final DialogInterface dialog, int index) {
                            payOnSuccess(payCallBackListener);
                        }
                    });
            builder.setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            OnCancel(payCallBackListener);
                        }
                    });
            builder.create().show();
    
        }
    
    
        private void showLoginView(final Context context, final CallBackListener loginCallBackListener){
    
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage("是否登录?");
            builder.setTitle("登录界面");
            builder.setPositiveButton("登录",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            JSONObject json = new JSONObject();
                            try {
                                json.put("sid", "testID");
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
    
                            loginOnSuccess(json.toString(),loginCallBackListener);
                        }
                    });
            builder.setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int index) {
                            loginOnFail("channel login fail",loginCallBackListener);
                        }
                    });
            builder.create().show();
    
        }
    
    
        @Override
        public void exit(Context context, CallBackListener exitCallBackLister) {
            LogUtils.d(TAG,getClass().getSimpleName() + " exit");
            channelNotExitDialog(exitCallBackLister);
        }
    }
    

    项目代码总结

    ----------------------------------------------------------------------------------------------
    
    GameSDK_API层:
    
       SDK对外接口层:是暴露给CP的接口,底层返回的数据格式在这一层转化,该层不参与混淆。
                     所以不要在该层做业务逻辑处理,避免被反射调用修改。
    
       后续有新的接口,可以在该层做拓展对外给CP。
    
    ----------------------------------------------------------------------------------------------
    
    GameSDK_BeginProject层:
    
       SDK项目层:是与Api层对接的项目入口层,可以通过修改配置文件 Project_config.txt
       进入和替换成不同的Project SDK项目。
    
       注意:
    
           顶层Project已经确定好后,不要修改太多,如果有拓展的功能接口,
           可以通过extendFunction()对应type拓展,避免改动太多底层代码。
    
    
        SDK大体分为两类:
        1、Project_JuHe为聚合SDK项目,主要业务用于封装三方渠道。
    
        2、Project_Custom为自定义SDK项目,主要是做自己的渠道,每个公司可能会有不同的名称,
           主要业务是,实现用户入口、支付逻辑、数据统计等功能。
    
           可能根据不同的游戏运营需求会有不同的登录逻辑、绑定逻辑、支付方式、数据上报等
           会细分为公版项目、海外项目(针对地区)、根据游戏的定制化项目等。可根据不同的项目,拓展Project
    
    
        该层是做业务逻辑处理的,希望能有清晰的架构思路。
        
    ----------------------------------------------------------------------------------------------
    
    SYSDK_Channel: SDK项目渠道层
    
       该层负责对接渠道接入的业务,不同的渠道都会有对应的Module实现具体的代码调用和逻辑处理,以及资源配置
       通过配置文件 Channel_config.txt 管理。
    
       而且每个渠道Module都会有对应的开发者说明文件,方便后续的开发同事维护更新。详见开发者说明。
    
       开发者格式说明:
    
          格式: 渠道名 -- 版本号 -- 开发人员 (如果渠道没有版本就按V1.0.0来)    日期
    
                    相关注意事项说明:
                    1、.... xxx ....
                    2、.... xxx ....
    
    
    ----------------------------------------------------------------------------------------------
    
    SYSDK_Manager:
    
       SDK逻辑管理层:
    
          该层为整个SDK功能逻辑的实现:初始化、账号、支付、获取道具信息、补单逻辑、退出
          为避免逻辑层因业务太乱导致代码过多,及后续的功能模块抽离.
          采用模块化化思想进行模块管理.
    
          初始化:SDK初始化(全局参数缓存、环境切换、权限问题等) >- 项目初始化(默认初始化 和 项目初始化)
    
          登陆:设备登陆、游客登录、账号登陆、三方登陆(google/facebook/微信)
    
          支付:三方支付:google、支付宝、微信、及特有的项目支付、补单
    
          退出:
    
          当有额外的功能添加的时候,在该层实现即可。
    
    ----------------------------------------------------------------------------------------------
    
    GameSDK_Manager_Impl:
    
       SDK逻辑功能拓展反射层,通过反射解耦插件:
    
            该层更多的是针对后续Plugin插件做不同的功能反射,具体调用Plugin层插件。
            只负责对接GameSDK_Manager_Impl 和 Plugin插件层。
    
    ----------------------------------------------------------------------------------------------
    
    GameSDK_Plugin:
    
        SDK功能插件层,与渠道层有点类似,通过配置文件 Plugin_config.txt 管理。
        通过逻辑控制层 Manager_Logic_Impl 反射调用实现,把插件拔除不影响。
        可以是三方的功能插件,也可以是自己实现的插件。
    
        目前为说明功能,用支付宝和微信说明
        Alipay功能插件层:实现Alipay功能,封装Alipay相关接口
        Wechat功能插件层:实现Wechat功能,封装Wechat相关接口
    
       当有额外的功能添加的时候,在该层实现即可。
       
    ----------------------------------------------------------------------------------------------
    
    GameSDK_Utils:
    
       GameSDK_Utils层:该层为整个SDK功能基础库:目前分为业务基础库 和 功能基础库,方便后续将业务分离。
    
          基础组件:
    
             1、数据缓存、域名配置、项目/插件/渠道管理
                注意:将项目、渠道、插件分别加载的目的:
    
                是为了快速替换项目Project的入口类
    
                一个项目Project 可以对应多个渠道、多个插件。后续可以在多渠道、多插件上
                进行快速的插拔和后台开关的切换渠道。
    
                不过正常的需求都是一个项目,对应零个或一个渠道、一个或多个功能插件
    
    
             2、网络请求、日志输出、Gson解析
    
                注意:网络请求,目前封装的volly (volly是比较轻量级的,主要是为减少SDK包体)
                     日志输出,目前封装的logger(logger比较轻量级,主要用于开发日志信息输出)
    
                     第三方库快速替换方案思路:(方便后续维护替换成更好的库)
                     接口解耦封装,实现上层业务网络请求接口不改动,只做封装层的api调用即可
    
    
       基础库不要轻易修改! 不要轻易修改! 不要轻易修改! 不要轻易修改! 不要轻易修改!
    
    ---------------------------------------------------------------------------------------
    
    结语:

    关于手游SDK的客户端的实现就大体介绍到这里。Demo的地址: 手游SDK框架Demo
    声明下,该Demo只是框架的讲解,不具备任何商业价值。如涉及到纠纷,可不能赖我呀。

    关于打包篇,可移步:
    手游SDK — 第五篇(游戏打包篇(上)- 打包系统设计)
    手游SDK — 第六篇(游戏打包篇(中)- 自动化打包)
    手游SDK — 第七篇(游戏打包篇(下)- 自动化打包踩坑记录)

    相关文章

      网友评论

        本文标题:手游SDK — 第四篇(SDK架构设计代码实现篇(下)- 项目需

        本文链接:https://www.haomeiwen.com/subject/eijxsqtx.html