首页 > 作文

手机悬浮球

更新时间:2023-03-16 00:18:15 阅读: 评论:0

大理美食攻略-大魔王提莫

手机悬浮球
2023年3月16日发(作者:给公司的祝福语)

IOS游戏渠道SDK抽象⼯程封装

iOS游戏渠道SDK抽象⼯程封装(上)

⼀款⼿机游戏,要是想挣钱,接⼊渠道SDK是很重要滴。但是渠道SDK有那么多家,每⼀家的接⼝也不⼀样,那么是否需要每⼀家渠道

SDK都来接⼊⼀次呢?游戏的研发同学,每次想到这边,都表⽰⼀个头,两个⼤。

那么为了给研发的同学减轻负担,让他们专⼼搞研发,给所有渠道SDK封装⼀个抽象⼯程,是很有必要的⼀件事情。这样,游戏接⼊⼀次抽

象⼯程就OK了,到时候要接⼊渠道SDK,只需要把⽂件替换⼀下,省时⼜省⼒,岂不是美美哒。

什么是渠道SDK的抽象⼯程?

抽象⼯程,可以说是渠道SDK的驱壳。这个驱壳,可以装下各种各样的渠道SDK。

虽然渠道SDK种类繁多,但是细⼼⼀看,他们的接⼝也是⼤同⼩异的。⼤体上有这么⼏个:

-初始化

-⽤户登陆

-⽤户退出

-⽤户⽀付

-⽤户中⼼

-⼯具栏打开关闭

摸清了他们的套路,咱们也可以⼤⼤⽅⽅地出⼿了。

抽象⼯程的总⼊⼝

游戏与抽象⼯程的所有交互,都是由这个类来完成。我们把它命名为SDKAccount。

先来个SDKAccount.h的代码

为了使我们的抽象⼯程更⽅便地使⽤,我们这边采⽤单例的模式,使⽤sharedInstance来获取抽象⼯程的单例。

然后⼤家是不是以为,接下来就是在SDKAccount.m⾥头来实现渠道SDK的代码啦。nonono,这样会使我们抽象⼯程的业务代码,和渠

道SDK的业务混杂在⼀起,使代码变得杂乱不堪,这是我所不能容忍的。我们把渠道SDK的代码,统统放在另外⼀个地⽅,这个后⾯再讲。

先来讲讲SDKAccount.m

获取单例,我们⽤最常见的gcd⽅式来创建。

//获取单例

+(instancetype)sharedInstance;

//sdk⽤户初始化

-(void)doInit:(NSString*)gameVersion;

//sdk登陆

-(void)doLogin;

//sdk退出

-(void)doLogout;

//sdk切换⽤户

-(void)doSwitchAccount;

//sdk⽀付

-(void)doPay:(SDKPayInfo*)sdkPayInfo;

//调⽤暂停页⾯

-(void)doPau;

//设置⼯具栏YES打开/NO关闭

-(void)doSetting:(BOOL)visible;

//打开⽤户中⼼

-(void)doUrCenter;

初始化

登陆

退出

⽀付

+(instancetype)sharedInstance{

staticSDKAccount*instance=nil;

staticdispatch_once_tonceToken=0;

dispatch_once(&onceToken,^{

instance=[[SDKAccountalloc]init];

});

returninstance;

}

-(void)doInit:(NSString*)gameVersion{

[[SDKContainersharedInstance]doThirdInit:lfgameVersion:gameVersion];

}

-(void)doLogin{

[[SDKContainersharedInstance]doLogin];

}

-(void)doLogout{

[[SDKContainersharedInstance]doLogout];

}

-(void)doPay:(SDKPayInfo*)sdkPayInfo{

SDKUr*sdkUr=[SDKUrsharedInstance];

if(==nil||==0){

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_NO_LOG

return;

}

if(sdkPayInfo==nil){

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_PARAM_E

return;

}

if([intValue]<=0||[length]==0||[Idlength]==0||[tIdlength]==0){

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_PARAM_E

return;

}

SDKPayReq*payReq=[[SDKPayReqalloc]init];

=;

rmUrId=[[SDKUrsharedInstance]uid];

erId=d;

ductId=tId;

ductName=tName;

rId=;

rName=me;

eId=;

eName=me;

eLevel=vel;

到这边,有些朋友会问,为什么doPay的代码会多出这么多?那是因为这些代码,是我们⾃⼰的业务逻辑。

在调⽤渠道SDK的⽀付之前,我们需要先把⽀付信息传到我们的服务器上⾯,⽣成⼀个订单号,这个订单号,会记录在数据库中,作为以后

游戏⽤户的⽀付凭据。⽣成完以后,再回传回来。这时候我们才能⽤这个订单号,来调⽤渠道SDK的⽀付接⼝。

暂停页⾯

eLevel=vel;

verId=Id;

verName=Name;

lId=[lfgetChannelId];

Id=[lfgetDeviceId];

ifyUri=Uri;

=;

el=el;

[payReqpost:^(NSHTTPURLRespon*respon,NSDictionary*data){

SDKLog(@"订单信息---%@",data);

NSNumber*code=data[@"code"];

if([codeintValue]==0){

NSDictionary*info=data[@"data"];

NSString*orderId=info[@"order_id"];

NSString*amountStr=[NSStringstringWithFormat:@"%d",[[payReqamount]intValue]/100];//单位为元

NSString*productId=ductId;

NSString*productName=ductName;

NSString*roleId=eId;

NSString*rverId=verId;

NSString*rverName=verName;

NSString*payDesc=[NSStringstringWithFormat:@"Product_%@",ductId];

NSDictionary*orderMsg=@{

@"orderId":CleanNil(orderId),

@"amountStr":CleanNil(amountStr),

@"productId":CleanNil(productId),

@"productName":CleanNil(productName),

@"roleId":CleanNil(roleId),

@"rverId":CleanNil(rverId),

@"rverName":CleanNil(rverName),

@"payDesc":CleanNil(payDesc)

};

[[SDKContainersharedInstance]doPayWithOrder:orderMsg];

}el{

[lfnotifitionCreateOrderError];

}

}failure:^(NSHTTPURLRespon*respon,NSDictionary*data,NSError*error){

[lfnotifitionCreateOrderError];

}];

}

-(void)doPau{

[[SDKContainersharedInstance]doPau];

}

有些渠道SDK(⽐如91助⼿),要求在按下home键回到主界⾯,再切换回游戏时,会弹出⼀个暂停页⾯,⽤来展⽰⼴告。这时就要在

AppDelegate中的applicationWillEnterForeground⽅法中,调⽤doPau这个⽅法。

⼯具栏(悬浮球)开

打开⽤户中⼼

切换账号

切换账号实际上也就是先退出,再调⽤登陆窗⼝。

盛放渠道SDK代码的容器

前⾯讲到,为了不使我们的代码变得杂乱不堪,我们把业务逻辑和渠道SDK的代码分开来。创建⼀个新的类,⽤来盛放渠道SDK代码。这个

类⼤家也猜到了,就叫做SDKContainer。

先上SDKContainer.h的代码。

-(void)doSetting:(BOOL)visible{

[[SDKContainersharedInstance]doSetting:visible];

}

-(void)doUrCenter{

[[SDKContainersharedInstance]doUrCenter];

}

-(void)doSwitchAccount{

[[SDKContainersharedInstance]doSwitchAccount];

}

⾸先⼀上来是⼀个协议,有协议就有⼈遵守。没错,这个协议是为SDKAccount准备的。

先在SDKAccount.h的头部写上

@interfaceSDKAccount:NSObject

1

然后在SDKAccount.m中实现这些⽅法

@protocolSDKContainerDelegate

-(void)initFinish:(NSDictionary*)initMsg;

-(void)loginFinished:(NSDictionary*)loginMsg;

-(void)logoutFinished:(NSDictionary*)logoutMsg;

-(void)payFinished:(NSDictionary*)payMsg;

//登录成功

-(void)notifitionLoginSuccess:(SDKUr*)sdkUr;

//登录失败

-(void)notifitionLoginError;

//登录取消

-(void)notifitionLoginCancel;

//注销成功

-(void)notifitionLogoutSuccess;

//创建订单失败

-(void)notifitionCreateOrderError;

//充值⽤户未登录

-(void)notifitionPayNoLogin;

//充值成功

-(void)notifitionPaySuccess;

//充值失败

-(void)notifitionPayError;

//充值取消

-(void)notifitionPayCancel;

//充值发货中

-(void)notifitionPayShipping;

//充值⽹络异常

-(void)notifitionPayNetError;

@end

-(void)initFinish:(NSDictionary*)initMsg{

[lfdoLogin];

}

-(void)loginFinished:(NSDictionary*)loginMsg{

//登录成功,开发者可继续游戏逻辑

SDKLoginReq*loginReq=[[SDKLoginReqalloc]init];

=loginMsg[@"code"];

=loginMsg[@"code"];

=loginMsg[@"uid"];

me=loginMsg[@"urname"];

me=loginMsg[@"nickname"];

[loginReqpost:^(NSHTTPURLRespon*respon,NSDictionary*data){

//打印⽇志

SDKLog(@"登录信息---%@",data);

NSNumber*code=data[@"code"];

if([codeintValue]==0){

NSDictionary*dataDic=data[@"data"];

SDKUr*sdkUr=[SDKUrsharedInstance];

=dataDic[@"uuid"];

=dataDic[@"check_token"];

rm=FYSDK_PLATFORM_NAME;

NSDictionary*ur=dataDic[@"ur"];

NSString*uid=ur[@"id"];

NSString*urname=ur[@"name"];

NSString*nickname=ur[@"nickname"];

if(!=0){

=;

}el{

=uid;

}

if(!=0){

me=me;

}el{

me=urname;

}

if(!=0){

me=me;

}el{

me=nickname;

}

r=sdkUr;

[lfnotifitionLoginSuccess:sdkUr];

}el{

[lfnotifitionLoginError];

}

}failure:^(NSHTTPURLRespon*respon,NSDictionary*data,NSError*error){

[lfnotifitionLoginError];

}];

}

-(void)logoutFinished:(NSDictionary*)logoutMsg{

[lfnotifitionLogoutSuccess];

}

-(void)payFinished:(NSDictionary*)payMsg{

}

//-------------------------各种通知-------------------------------

//登录成功

-(void)notifitionLoginSuccess:(SDKUr*)sdkUr{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_LOGINobject:lfurInfo:[SDKResponBadict:SDK_RESP_SUCCES

}

//登录失败

-(void)notifitionLoginError{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_LOGINobject:lfurInfo:[SDKResponBadict:SDK_RESP_LOGIN_E

}

//登录取消

-(void)notifitionLoginCancel{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_LOGINobject:lfurInfo:[SDKResponBadict:SDK_RESP_CANCEL_

}

//创建订单失败

-(void)notifitionCreateOrderError{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_CREATE_O

}

//注销成功

-(void)notifitionLogoutSuccess{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_LOGOUTobject:lfurInfo:[SDKResponBadict:SDK_RESP_SUCCE

}

//注销失败

-(void)notifitionLogoutError{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_LOGOUTobject:lfurInfo:[SDKResponBadict:SDK_RESP_PARAM

}

//充值⽤户未登录

-(void)notifitionPayNoLogin{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_NO_LOGIN]

}

//充值成功

-(void)notifitionPaySuccess{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_SUCCESS]]

}

//充值失败

-(void)notifitionPayError{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_PAY_ERRO

}

//充值取消

-(void)notifitionPayCancel{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_CANCEL_O

}

//充值发货中

-(void)notifitionPayShipping{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_PAY_ING]];

}

//充值⽹络异常

-(void)notifitionPayNetError{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAYobject:lfurInfo:[SDKResponBadict:SDK_RESP_NET_ERRO

}

//暂停页⾯关闭通知

-(void)notifitionPuaPageClo{

[[NSNotificationCenterdefaultCenter]postNotificationName:SDK_CALLBACK_PAUSE_PAGE_CLOSEobject:lfurInfo:nil];

}

在SDKAccount的doInit中,将lf传给SDKContainer。这样SDKContainer就可以回调SDKAccount啦。

上⾯的loginFinished⽅法,也是调⽤了我们的业务逻辑。在渠道SDK登陆完以后,需要将token发到我们的服务器中,然后再由我们的服

务器,转发给渠道SDK服务器去验证登陆。

我们来继续SDKContainer的内容。

有没有很眼熟,和SDKAccount很像,是吧。

然后是

SDKContainer.h

@interfaceSDKContainer:NSObject

+(instancetype)sharedInstance;

-(void)doThirdInit:(id)delegategameVersion:(NSString*)gameVersion;

-(void)doLogin;

-(void)doLogout;

-(void)doPayWithOrder:(NSDictionary*)orders;

-(void)doPau;

-(void)doSetting:(BOOL)visible;

-(void)doUrCenter;

-(void)doSwitchAccount;

@end

#import"SDKContainer.h"

@interfaceSDKContainer()

@property(nonatomic)iddelegate;

@end

@implementationSDKContainer

+(instancetype)sharedInstance{

staticSDKContainer*instance=nil;

staticdispatch_once_tonceToken=0;

dispatch_once(&onceToken,^{

instance=[[SDKContaineralloc]init];

});

returninstance;

}

-(void)doThirdInit:(id)delegategameVersion:(NSString*)gameVersion{

te=delegate;

//----------------打印平台版本号---------------

NSString*platformVersion=@"";//更新SDK必填

NSLog(@"---PlatformVersion---%@",platformVersion);

//---------------sdk初始化代码-----------------

//0横屏1竖屏

if([SDK_CONFIG_ORIENTATIONisEqual:@"0"]){

//-----------sdk横屏设置-----------

}el{

//-----------sdk竖屏设置-----------

}

}

-(void)doLogin{

//-----------sdk登陆接⼝-----------

}

-(void)doLogout{

//-----------sdk退出接⼝-----------

}

-(void)doPayWithOrder:(NSDictionary*)orders{

NSString*orderId=orders[@"orderId"];//订单

NSString*amountStr=orders[@"amountStr"];//⾦额,单位为元

NSString*productName=orders[@"productName"];//商品名

NSString*roleId=orders[@"roleId"];//⾓⾊名

NSString*rverId=orders[@"rverId"];//区服id

NSString*payDesc=orders[@"payDesc"];//额外⽀付信息

//-----------sdk⽀付接⼝-----------

}

-(void)doPau{

//------------sdk暂停页⾯-------------

}

-(void)doSetting:(BOOL)visible{

if(visible){

//-----------sdk打开⼯具栏-----------

}el{

//-----------sdk关闭⼯具栏-----------

}

}

-(void)doUrCenter{

//-----------sdk打开个⼈中⼼-----------

}

-(void)doSwitchAccount{

[lfdoLogout];

[lfdoLogin];

}

//---------------渠道sdk回调接⼝----------------

这边我们为渠道SDK预留了位置,将来要接⼊渠道SDK的时候,只需要将渠道SDK的代码,放到中对应的位置就⾏

了。是不是很⽅便呢?

细⼼的朋友发现,多了⼀个m出来。这是因为有些渠道SDK是⽤C++和Obj-C混合写的。所以要求我们要将.m改

为.mm。平时我们使⽤.mm也不妨碍我们的代码。

当渠道SDK需要回调游戏的时候该怎么办?只需要调⽤⼀下delegate中的⽅法,就可以了。

*(1)初始化结束调⽤以下代码

*(2)登陆结束调⽤以下代码

*(3)登陆取消调⽤以下代码

*(4)登陆失败调⽤以下代码

*(5)⽀付成功调⽤以下代

(6)⽀付取消调⽤以下代码

*(7)⽀付失败调⽤以下代码

*(8)⽀付⽤户未登陆调⽤以下代码

*(9)创建订单失败调⽤以下代码

*(10)充值发货中调⽤以下代码

//-----------------------------------------

[teinitFinish:nil];

NSString*code=;//登陆时的token

NSString*uid=;//游戏账号的唯⼀值

NSString*urname=;//游戏账号名

NSDictionary*loginMsg=@{

@"code":code,

@"uid":uid,

@"urname":urname

};

[teloginFinished:loginMsg];

[tenotifitionLoginCancel];

[tenotifitionLoginError];

[tenotifitionPaySuccess];

[tenotifitionPayCancel];

[tenotifitionPayError];

[tenotifitionPayNoLogin];

[tenotifitionCreateOrderError];

*(11)充值⽹络异常调⽤以下代码

*(12)退出成功调⽤以下代码

然后由SDKAccount统⼀去回调游戏。

这样是不是将渠道SDK的代码和我们的业务代码,完全地分离开来了呢?

我们将渠道SDK的代码,和我们⾃⼰的业务代码分离,⼀个放在SDKContainer⾥⾯,⼀个放在SDKAccount⾥⾯。

这样做的好处,不⽌在于可以清晰地划分代码之间的界限,更重要的是,这样更加便于管理和维护。

试想⼀下,我们做抽象⼯程的⽬的是什么?是为了游戏可以不⽤频繁重复地接⼊渠道SDK嘛。那么怎么才能达到这个⽬的呢?

抽象⼯程的⽬录结构

我们将代码划分成两个部分:

第⼀部分是不⽤变动的部分,也就是说所有的渠道SDK,都来共⽤这部分的代码,是⼀些基础类。我们统⼀将他们放在⽂件夹Ba⾥⾯。

这个Ba⾥⾯,包含了我们所有⾃⼰的业务代码:⽐如SDKAccount,⽹络请求类,⼯具类等等。

第⼆部分是需要变动的部分,也就是说所有的渠道SDK都有各⾃⾃⼰的⼀份。我们统⼀将他们放在Replace⽂件夹下。这⾥⾯包含了

SDKContainer和渠道SDK的⼀些配置信息。

先给出⼀张⽬录截图:

这⾥写图⽚描述

ThirdLib⽤来存放渠道SDK的依赖库⽂件。

为什么我们要把⽬录的职责分得这么细呢?这是为了更好地在开发中起到⼀个分⼯明确地作⽤。

如何使⽤抽象⼯程

1.在实际开发过程中,我们先创建⼀个空的抽象⼯程。这时候SDKContainer中是还没有没有渠道SDK代码的。

[tenotifitionPayShipping];

[tenotifitionPayNetError];

[tenotifitionLogoutSuccess];

2.这时研发的同学,来把我们的抽象⼯程拿过去,然后在游戏代码中调⽤我们的SDKAccount⾥⾯的接⼝。抽象⼯程算是接好了。但是现在

还不能⽤,不是吗?你得到了我的驱壳,却没得到我的灵魂。。。不过这时研发的同学,可以把SDK的事情放下了,专⼼地去做研发。

3.负责专门接⼊SDK的同学,从商务⼿中拿到渠道SDK。然后他把抽象⼯程拷贝⼀份过来。拷贝完之后,把渠道SDK的依赖库,放到

ThirdLib⾥⾯。然后在SDKContainer中,填⼊渠道SDK的代码。接着在SDKConfig中,填⼊渠道SDK的配置信息。最后测试⼀下,看有

没有问题。没有问题再把它交给研发的同学。

4.研发的同学,拿到接好的渠道SDK的抽象⼯程,只需要动动⼿指头,把⾥⾯的Replace和ThirdLib⽂件夹拷贝到原来游戏⼯程中,将原来

的两个⽂件夹替换⼀下,OK,接⼊完成。

5.以后再有新的渠道SDK,只需要重复步骤3和步骤4,就可以了。这个过程中,研发的同学,只需要接⼊⼀次抽象⼯程,接下来的事情,

就是动动⼿指头,替换⼀下⽂件。接SDK的同学,也不⽤关⼼业务逻辑,只需要将SDK的代码,填⼊相应的位置就⾏。两个⼈都感觉⼯作量

瞬间减⼩了很多,嘿嘿。。

项⽬管理

有些朋友发现,说了这么多,只不过是替换⽂件夹⼀下⽽已,为什么要分为Ba和Replace?我把所有⽂件统统放在⼀个⽂件夹⾥⾯不⾏

啊,到时候我把这个⽂件夹替换⼀下就好了啊。

先来看看渠道的管理⽬录

从这张图可以发现,我们把Ba单独提出来了。我们知道,Xcode是可以使⽤引⽤的⽅式,引⽤⼀个⽂件夹⾥⾯的内容的,⽽不必⼀定要

拷贝⽂件到⼯程⾥⾯去。也就是说,渠道和Ba之间,是⼀个多对⼀的关系,每个渠道共⽤⼀个Ba。

为什么要这样做?假设有⼀天,你的⽼⼤叫你修改或者添加⼀些⾃家的业务逻辑。哈哈,幸好,我把Ba单独拿出来了。这样我只要修改

⼀份代码就可以了~

后记

尽管抽象⼯程还有很多事情要做,例如⽹络请求,⽤户信息记录,数据采集等等,但是这些都是属于业务逻辑的范畴了,这边也不⼀⼀介绍

了。希望抽象⼯程,对⼤家有帮助,让接⼊渠道SDK不再痛苦。。

转载出处

本文发布于:2023-03-16 00:18:14,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/a8fd63b0e86674766c1f4f145a7c8f66.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:手机悬浮球.doc

本文 PDF 下载地址:手机悬浮球.pdf

标签:手机悬浮球
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图