iOS端手游和c++交互 lua和c++交互

iOS端手游和c++交互 lua和c++交互

进了一家新的手游公司,坐标杭州,因为之前是做发行做了一段时间,才知道互联网真正赚钱的是手游。所以从武汉来杭州就一心想找一家手游公司,从而深入了解一下iOS工程师能为手游做多少工作。其实要做的工作并没有多少,主要是给手游(无论是unity写的还是cocos写的)套壳子。
工作内容如下:
1、对接渠道方的sdk,现在对接的sdk包括国服的飞鱼sdk(发行萝卜保卫战),日服的b站游戏sdk(坑很多,尤其是外服),韩服的网易sdk(文档写的非常全面,流程复杂),台服的心动sdk(中规中矩)
2、写oc和c++的交互桥接文件,也是我要在本bolg里着重说的一点,写c++和lua的交互桥接文件。
3、优化内存,找到内存泄漏的地方,大概率都是c++代码。

oc和c++的交互桥接文件

我拿韩服和网易sdk的桥接文件举例:
在这里插入图片描述新建C++File
在这里插入图片描述.hpp:本质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该.hpp文件即可,无需再将cpp加入到project中进行编译。而实现代码将直接编译到调用者的obj文件中,不再生成单独的obj,采用hpp将大幅度减少调用project中的cpp文件数与编译次数,也不用再发布lib与dll文件,因此非常适合用来编写公用的开源库。

hpp的优点不少,但是编写中有以下几点要注意:
1、是Header Plus Plus的简写。(.h和.hpp就如同.c和.cpp似的)
2、与.h类似,.hpp是C++程序头文件格式。
3、是VCL专用的头文件,已预编译。
4、是一般模板类的头文件。
5、一般来说,.h里面只有声明,没有实现,而.hpp里声明实现都有,后者可以减少.cpp的数量。
6、.h里面可以有using namespace std,而.hpp里则无。
7、不可包含全局对象和全局函数。

由于.hpp本质上是作为.h被调用者include的,所以当hpp文件中存在全局对象或者全局函数,而该hpp被多个调用者include时,将在链接时导致符号重定义错误。要避免这种情况,需要去除全局对象,将全局函数封装为类的静态方法。

.mm :源代码文件。带有这种扩展名的源代码文件,除了可以包含Objective-C和C代码以外还可以包含C++代码。仅在你的Objective-C代码中确实需要使用C++类或者特性的时候才用这种扩展名

首先贴上.hpp头文件:

#ifndef NTSdkBridge_hpp
#define NTSdkBridge_hpp

#include <stdio.h>
#include <string>
#include <vector>
#include <unordered_map>
typedef std::vector<std::string> payProductList;

class NTSdkBridge {
public:
    enum class EventType{
        INIT,
        LOGIN,
        LOGOUT,
        PAY,
        SHARE,
    };
    static NTSdkBridge* getInstance();
//    void init(std::string gameRegion, std::string gameVersion, std::string gameLanguage, std::string engineVersion, std::string resourceVersion);
    void login();
    void logincallback(int code);
    void logout();
    void switchAccount();
    void traceAccount(std::string serverid, int level);
    void bugReport(std::string serverid, std::string nickname, std::string clientversion);
    void userCenter(std::string serverid, std::string nickname, std::string clientversion);
    void storeReview();
    std::string getChannelID();
    //支付
    void queryWithProducts(payProductList* list);
    
    float getProductAmount(std::string id);
    std::string getProductCurrency(std::string id);
    std::string getProductDisplayPrice(std::string id);
    
    void payWithProductID(std::string productid, std::string serverid, std::string ext, int level);
    void paycallback(int code);
    void paycallback(int code, std::string productid);
    
    void eventTrack(std::string event);
    
    void registerEventHandler(EventType event, int handler);
    //分享
    void share(std::string image, std::string link, std::string msg);
    void sharecallback(int code);
    
private:
    NTSdkBridge();
    ~NTSdkBridge();
    void removeDeprecatedHandler(int &handler);
    
private:
        static NTSdkBridge* instance;
        int _inithandler = 0;
        int _loginhandler = 0;
        int _logouthandler = 0;
        int _payhandler = 0;
        int _sharehandler = 0;
        
        std::unordered_map<std::string, std::string> _cached_products;
};
#endif /* NTSdkBridge_hpp */

头文件包括几部分:
1、public方法:
枚举的EventType:回调event
函数声明
2、private方法:
处理回调的handler
私有函数声明

.mm文件:

#include "NTSdkBridge.hpp"
#include <stdio.h>
#import "RootViewController.h"
#include "cocos2d.h"
#include "CCLuaEngine.h"

#include <sys/param.h>
#include <sys/mount.h>
#include <ui/UIVideoPlayer.h>
#include <NtUniSdkNetEaseGlobal/NtUniSdk.h>

@interface NTAgent : NSObject
-(void) loginNotification:(NSNotification *)notification;
-(void) finishInitNotification:(NSNotification *)notification;
-(void) registerNotification:(NSNotification *)notification;
-(void) logoutNotification:(NSNotification *)notification;
-(void) closeManagerViewNotification:(NSNotification *)notification;
-(void) closeFFViewNotification:(NSNotification *)notification;
-(void) getProductInfoNotification:(NSNotification *)notification;
-(void) userManagerViewHasNewMessage:(NSNotification *)notification;
-(void) init:(void*)ntbridge;
@end
@implementation NTAgent
{
    NTSdkBridge * _bridge;
}

-(void) init:(void *)ntbridge{
    _bridge = (NTSdkBridge *)ntbridge;
    //初始化通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(finishInitNotification:) name:NT_NOTIFICATION_FINISH_INIT object:nil];

    //监听注册通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registerNotification:) name:NT_NOTIFICATION_REGISTER object:nil];

    //注销通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutNotification:) name:NT_NOTIFICATION_LOGOUT object:nil];

    //监听登录通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginNotification:) name:NT_NOTIFICATION_LOGIN object:nil];

    //管理视图关闭通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeManagerViewNotification:) name:NT_NOTIFICATION_CLOSE_MANAGERVIEW object:nil];

    //支付结束通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeFFViewNotification:) name:NT_NOTIFICATION_CLOSE_FFVIEW object:nil];

    //成功获取商品信息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getProductInfoNotification:) name:NT_NOTIFICATION_FINISH_GET_PRODUCT_INFO object:nil];

    //用户界面有新的消息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userManagerViewHasNewMessage:) name:NT_NOTIFICATION_NEW_MESSAGE object:nil];
    
}

-(void)finishInitNotification:(NSNotification *)notification{
    NSLog(@"finishInitNotification.");
    NSDictionary *dict = notification.userInfo;
    if (dict) {
        //有字典信息,获取dict中的各个字段信息,根据情况进行处理
        //ex:
        NSString *value01 = dict[@"key-01"];
    }

    else {
        //没有字典信息,不用处理传入的notification
    }

    //处理初始化完成的事情
    CCLOG("init success");
    _bridge->initCallBack(0);
    
}

-(void)registerNotification:(NSNotification *)notification{
    NSLog(@"[NtUniSdk] Notification registerNotification.");
}
//注销通知处理,在用户管理界面登出后能收到这个回调
-(void)logoutNotification:(NSNotification *)notification{
    _bridge->logoutCallBack(0);
}
-(void)closeManagerViewNotification:(NSNotification *)notification{
    NSLog(@"[NtUniSdk] Notification closeManagerView.");
}
-(void)closeFFViewNotification:(NSNotification *)notification{
    NSLog(@"[NtUniSdk] Notification closeFFViewNotification.");
}
-(void)getProductInfoNotification:(NSNotification *)notification{
   
}
-(void)userManagerViewHasNewMessage:(NSNotification *)notification{
    
}
-(void)loginNotification:(NSNotification *)notification{
    NSLog(@"loginNotification.");
    //NSLog(@"LOGIN_TYPE : %d",[[NtSdkMgr getInst] getPropInt:LOGIN_TYPE default:-1]);

    NSDictionary *dict = notification.userInfo;
    NSLog(@"");
    if ([dict[NT_NOTIFICATION_INFO_LOGIN_STATE] isEqual: NT_NOTIFICATION_INFO_LOGIN_OK]) {
        NSLog(@"%@",[NSString stringWithFormat:@"[NtUniSdk] Notification login.\nLS: %i\nUID:%@\nSESSION:%@\n",
        [[NtSdkMgr getInst] hasLogin],
        [[NtSdkMgr getInst] getPropStr:NT_UID],
                     [[NtSdkMgr getInst] getPropStr:NT_SESSION]]);
        _bridge->logincallback(0);
    }

    else if ([dict[NT_NOTIFICATION_INFO_LOGIN_STATE] isEqual: NT_NOTIFICATION_INFO_LOGIN_FAILED]) {
        NSLog(@"检查下netease.data文件中的appid是否填写正确");
        [self msg:@"登录失败"];
        _bridge->logincallback(1);
        //参照下方登录失败错误码,可以弹一些提示信息
    }

    else if ([dict[NT_NOTIFICATION_INFO_LOGIN_STATE] isEqual: NT_NOTIFICATION_INFO_LOGIN_CANCEL]) {
        [self msg:@"登录取消"];
        _bridge->logincallback(2);
    }
    else if ([dict[NT_NOTIFICATION_INFO_LOGIN_STATE] isEqual: NT_NOTIFICATION_INFO_BIND_OK]) {
        [self msg:@"绑定成功"];
    }

    NSString *sauth = [[NtSdkMgr getInst] getPropStr:NT_SAUTH_STR];
    NSLog(@"计费sauth=%@", sauth);
    sauth = [[NtSdkMgr getInst] getPropStr:NT_SAUTH_JSON];
    NSLog(@"计费sauth_json=%@", sauth);

    [[NtSdkMgr getInst] setProp:NT_USERINFO_UID as:@"uid123"];
}
//弹提示
- (void)msg:(NSString*) str
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertView * alertA= [[UIAlertView alloc] initWithTitle:@"UniSDK 提示" message:str delegate:self cancelButtonTitle:@"哦哦" otherButtonTitles: nil];
        [alertA show];
    });
}
@end
NTSdkBridge* NTSdkBridge::instance = NULL;

USING_NS_CC;

NTSdkBridge::NTSdkBridge()
:_loginhandler(0),
_payhandler(0),
_sharehandler(0) {
    
}

NTSdkBridge::~NTSdkBridge() {
    
}

NTSdkBridge* NTSdkBridge::getInstance() {
    if (instance == NULL) {
        instance = new NTSdkBridge();
    }
    
    return instance;
}

void NTSdkBridge::login() {
    [[NtSdkMgr getInst] ntLogin];
}

void NTSdkBridge::logout() {
    [[NtSdkMgr getInst] ntLogout];
}

void NTSdkBridge::switchAccount() {
    
}

void NTSdkBridge::traceAccount(std::string serverid, int level) {
    
}

void NTSdkBridge::bugReport(std::string serverid, std::string nickname, std::string clientversion) {
    
}

void NTSdkBridge::userCenter(std::string serverid, std::string nickname, std::string clientversion) {
    
}

void NTSdkBridge::storeReview() {
   
}

std::string NTSdkBridge::getChannelID() {
    return "ios_kr_hqxy";
}

//获取手机剩余空间 单位MB
std::string NTSdkBridge::getFreeDiskSpaceInBytes(){
    struct statfs buf;
    unsigned long long freeSpace = -1;
    if (statfs("/var", &buf) >= 0) {
        freeSpace = (unsigned long long)(buf.f_bsize * buf.f_bavail);
    }
     NSString *str = [NSString stringWithFormat:@"%0.2lld ",freeSpace/1024/1024];
    return [str UTF8String];
}

void NTSdkBridge::queryWithProducts(payProductList* list) {
    NSMutableArray *products = [[NSMutableArray alloc] init];
    for (int i = 0; i < list->size(); i++) {
        [products addObject:[NSString stringWithUTF8String:list->at(i).c_str()]];
    }
    
    
}

float NTSdkBridge::getProductAmount(std::string id) {
    return -1;
}

std::string NTSdkBridge::getProductCurrency(std::string id) {
    return "";
}

std::string NTSdkBridge::getProductDisplayPrice(std::string id) {
    auto iter = _cached_products.find(id);
    if (iter != _cached_products.end()) {
        //CCLOG("GetProductPrice: %s", iter->second.c_str());
        return iter->second;
    }
    
    return "";
}


void NTSdkBridge::payWithProductID(std::string productid, std::string serverid, std::string ext, int level) {
    
}

void NTSdkBridge::eventTrack(std::string event) {
    
}

void NTSdkBridge::removeDeprecatedHandler(int &handler) {
    if (handler == 0)
        return;
    
    LuaEngine::getInstance()->removeScriptHandler(handler);
    handler = 0;
}

void NTSdkBridge::registerEventHandler(EventType event, int handler) {
    switch(event) {
        case EventType::INIT: {
            removeDeprecatedHandler(_inithandler);
            _inithandler = handler;
                
            break;
        }
        case EventType::LOGIN: {
            removeDeprecatedHandler(_loginhandler);
            _loginhandler = handler;
            
            break;
        }
        case EventType::PAY: {
            removeDeprecatedHandler(_payhandler);
            _payhandler = handler;
            
            break;
        }
        case EventType::SHARE: {
            removeDeprecatedHandler(_sharehandler);
            _sharehandler = handler;
            
            break;
        }
        case EventType::LOGOUT: {
            removeDeprecatedHandler(_logouthandler);
            _logouthandler = handler;
            
            break;
        }
        default:
            break;
    }
}
void NTSdkBridge::initCallBack(int code) {
    if (_inithandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->executeFunctionByHandler(_inithandler, 1);
    stack->clean();
}

void NTSdkBridge::logincallback(int code) {
    if (_loginhandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->executeFunctionByHandler(_loginhandler, 1);
    stack->clean();
}

void NTSdkBridge::logincallback(int code, int uid, std::string sid, bool isGuest, bool isBindPhoneNum) {
    if (_loginhandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->pushInt(uid);
    stack->pushString(sid.c_str());
    stack->pushBoolean(isGuest);
    stack->pushBoolean(isBindPhoneNum);
    stack->executeFunctionByHandler(_loginhandler, 5);
    stack->clean();
}

void NTSdkBridge::paycallback(int code) {
    if (_payhandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->executeFunctionByHandler(_payhandler, 1);
    stack->clean();
}

void NTSdkBridge::paycallback(int code, std::string productid) {
    if (_payhandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->pushString(productid.c_str());
    stack->executeFunctionByHandler(_payhandler, 2);
    stack->clean();
}

void NTSdkBridge::logoutCallBack(int code) {
    if (_logouthandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->executeFunctionByHandler(_logouthandler, 1);
    stack->clean();
}
void NTSdkBridge::share(std::string image, std::string link, std::string msg) {
    NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:link.c_str()]];
    
}

void NTSdkBridge::sharecallback(int code) {
    if (_sharehandler == 0)
        return;
    
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
    stack->pushInt(code);
    stack->executeFunctionByHandler(_sharehandler, 1);
    stack->clean();
}



.mm文件包含几个内容:
1、bridge类扩展
包括init函数供oc调用,基本都是在appdelegate里调用,sdk的通知监听和通知的实现。
2、bridge单例的初始化,public函数实现
3、注册回调handler
4、回调实现,实现和lua的交互(下面会提到lua和c++的交互桥接文件)

lua和C++的交互

因为我游是lua写的脚本,大多数游戏都是lua脚本,也有js脚本。所以我们要在壳子里写lua和c++交互的桥接文件。
在这里插入图片描述
ntsdk_lua_binding.hpp:

#ifndef ntsdk_lua_binding_hpp
#define ntsdk_lua_binding_hpp

#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif

TOLUA_API int register_ntsdk_luabinding(lua_State* L);
#endif /* ntsdk_lua_binding_hpp */

tolua++.h文件,网上有很多成熟的tolua的工具库,大概都是”tolua_isnumber“,这种。
最后要注册这个桥接文件,在lua里调用。
tolua++需要将 c/c++ 中的类型,变量,函数,对象导出到lua

ntsdk_lua_binding.cpp:

#include "ntsdk_lua_binding.hpp"
#include "NTSdkBridge.hpp"
#include "tolua_fix.h"
#include "LuaBasicConversions.h"
#include "CCLuaEngine.h"
#include <string>

int lua_ntsdk_login(lua_State* toluaS) {
    NTSdkBridge::getInstance()->login();

    return 0;
}

int lua_ntsdk_switchaccount(lua_State* toluaS) {
    NTSdkBridge::getInstance()->switchAccount();

    return 0;
}

int lua_ntsdk_traceaccount(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 2 || !lua_isstring(toluaS, 1) || !lua_isnumber(toluaS, 2)) {
        CCLOG("Wrong Args In traceAccount!!!!");
        return 0;
    }

    std::string serverid = tolua_tocppstring(toluaS, 1, "");
    int level = lua_tointeger(toluaS, 2);

    NTSdkBridge::getInstance()->traceAccount(serverid, level);

    return 0;
}

int lua_ntsdk_bugreport(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 3 || !lua_isstring(toluaS, 1) || !lua_isstring(toluaS, 2) || !lua_isstring(toluaS, 3)) {
        CCLOG("Wrong Args In bugReport!!!!!");
        return 0;
    }

    std::string serverid = tolua_tocppstring(toluaS, 1, "");
    std::string nickname = tolua_tocppstring(toluaS, 2, "");
    std::string clientversion = tolua_tocppstring(toluaS, 3, "");

    NTSdkBridge::getInstance()->bugReport(serverid, nickname, clientversion);

    return 0;
}

int lua_ntsdk_usercenter(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 3 || !lua_isstring(toluaS, 1) || !lua_isstring(toluaS, 2) || !lua_isstring(toluaS, 3)) {
        CCLOG("Wrong Args In bugReport!!!!!");
        return 0;
    }

    std::string serverid = tolua_tocppstring(toluaS, 1, "");
    std::string nickname = tolua_tocppstring(toluaS, 2, "");
    std::string clientversion = tolua_tocppstring(toluaS, 3, "");

    NTSdkBridge::getInstance()->userCenter(serverid, nickname, clientversion);

    return 0;
}

int lua_ntsdk_storereview(lua_State* toluaS) {
    NTSdkBridge::getInstance()->storeReview();

    return 0;
}

int lua_ntsdk_getchannelid(lua_State* toluaS) {
    std::string channelid = NTSdkBridge::getInstance()->getChannelID();

    lua_pushstring(toluaS, channelid.c_str());
    return 1;
}

int lua_ntsdk_querywithproducts(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 1 || (!lua_istable(toluaS, 1))) {
        CCLOG("Wrong Params For queryWithProducts!!!!!");
        return 0;
    }

    payProductList list;
    size_t len = lua_objlen(toluaS, 1);
    if (len <= 0) {
        return 0;
    }

    for (int i = 0; i < len; i++) {
        lua_pushnumber(toluaS, i+1);
        lua_gettable(toluaS, 1);

        if (lua_isnil(toluaS, -1)) {
            lua_pop(toluaS, 1);
            continue;
        }

        if (!lua_isstring(toluaS, -1)) {
            lua_pop(toluaS, 1);
            continue;
        }

        std::string value = tolua_tocppstring(toluaS, -1, "");
        list.push_back(value);

        lua_pop(toluaS, 1);
    }

    NTSdkBridge::getInstance()->queryWithProducts(&list);

    return 0;
}

int lua_ntsdk_paywithproductid(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 4 || !lua_isstring(toluaS, 1) || !lua_isstring(toluaS, 2) || !lua_isstring(toluaS, 3) || !lua_isnumber(toluaS, 4)) {
        CCLOG("Wrong Args For payWithProductID!!!!");
        return 0;
    }

    std::string productid = tolua_tocppstring(toluaS, 1, "");
    std::string serverid = tolua_tocppstring(toluaS, 2, "");
    std::string ext = tolua_tocppstring(toluaS, 3, "");
    int level = lua_tointeger(toluaS, 4);

    NTSdkBridge::getInstance()->payWithProductID(productid, serverid, ext, level);

    return 0;
}

int lua_ntsdk_registereventhandler(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 2 || !lua_isnumber(toluaS, 1) || !lua_isfunction(toluaS, 2)) {
        CCLOG("Wrong Args For RegisterEventHandler!!!!");
        return 0;
    }

    NTSdkBridge::EventType event = (NTSdkBridge::EventType)lua_tointeger(toluaS, 1);
    LUA_FUNCTION handler = toluafix_ref_function(toluaS, 2, 0);

    NTSdkBridge::getInstance()->registerEventHandler(event, handler);

    return 0;
}

int lua_ntsdk_getproductamount(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 1 || !lua_isstring(toluaS, 1)) {
        CCLOG("Wrong Args For getProductAmount!!!!");
        return 0;
    }

    std::string id = tolua_tocppstring(toluaS, 1, "");
    float amount = NTSdkBridge::getInstance()->getProductAmount(id);

    if (amount > 0) {
        lua_pushnumber(toluaS, amount);
        return 1;
    }

    return 0;
}

int lua_ntsdk_getproductcurrency(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 1 || !lua_isstring(toluaS, 1)) {
        CCLOG("Wrong Args For getProductAmount!!!!");
        return 0;
    }

    std::string id = tolua_tocppstring(toluaS, 1, "");
    std::string currency = NTSdkBridge::getInstance()->getProductCurrency(id);

    lua_pushstring(toluaS, currency.c_str());
    return 1;
}

int lua_ntsdk_getproductdisplayprice(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 1 || !lua_isstring(toluaS, 1)) {
        CCLOG("Wrong Args For getProductAmount!!!!");
        return 0;
    }

    std::string id = tolua_tocppstring(toluaS, 1, "");
    std::string display = NTSdkBridge::getInstance()->getProductDisplayPrice(id);

    lua_pushstring(toluaS, display.c_str());
    return 1;
}

int lua_ntsdk_eventtrack(lua_State* toluaS) {
    if (lua_gettop(toluaS) < 1 || !lua_isstring(toluaS, 1)) {
        CCLOG("Wrong Args For eventTrack");
        return 0;
    }

    std::string event = tolua_tocppstring(toluaS, 1, "");

    NTSdkBridge::getInstance()->eventTrack(event);

    return 0;
}

static const struct luaL_Reg ntsdk_funcs[] = {
    {"login", lua_ntsdk_login},
    {"switchAccount", lua_ntsdk_switchaccount},
    {"traceAccount", lua_ntsdk_traceaccount},
    {"bugReport", lua_ntsdk_bugreport},
    {"userCenter", lua_ntsdk_usercenter},
    {"storereview", lua_ntsdk_storereview},
    {"getChannelID", lua_ntsdk_getchannelid},
    {"queryWithProducts", lua_ntsdk_querywithproducts},
    {"getProductAmount", lua_ntsdk_getproductamount},
    {"getProductCurrency", lua_ntsdk_getproductcurrency},
    {"getProductDisplayPrice", lua_ntsdk_getproductdisplayprice},
    {"payWithProductID", lua_ntsdk_paywithproductid},
    {"eventTrack", lua_ntsdk_eventtrack},
    {"registerEventHandler", lua_ntsdk_registereventhandler},
    {NULL, NULL},
};

int lua_ntsdk_bridge(lua_State* toluaS) {
    lua_newtable(toluaS);
    lua_pushvalue(toluaS, -1);
    lua_setfield(toluaS, LUA_GLOBALSINDEX, "ntsdk");
        const luaL_Reg* lib = ntsdk_funcs;
        for (; lib->func; lib++) {
            lua_pushcfunction(toluaS, lib->func);
            lua_setfield(toluaS, -2, lib->name);
        }
        lua_newtable(toluaS);
        lua_pushvalue(toluaS, -1);
            lua_pushinteger(toluaS, (int)NTSdkBridge::EventType::LOGIN);
            lua_setfield(toluaS, -2, "LOGIN");
            lua_pushinteger(toluaS, (int)NTSdkBridge::EventType::PAY);
            lua_setfield(toluaS, -2, "PAY");
        lua_pop(toluaS, 1);
        lua_setfield(toluaS, -2, "EventType");
    lua_pop(toluaS, 1);
}


int register_ntsdk_luabinding(lua_State* toluaS) {
    return lua_ntsdk_bridge(toluaS);
}

lua代码,要判断c++的函数是否存在

为何要判断c++函数是否存在,是因为lua是热更新的,但是c++代码是随着游戏提审applestore用户才会更新,这就要兼容新老版本,如果在lua里调用了老版本没有的c++代码,那就会导致不好的结果,可能直接闪退或者怎样,所以lua代码中必须要判断c++函数是否存在。

local sdk = {}

function sdk.getServerID()
    return "4"
end

function sdk.login()
    NTSdk.login()
end

function sdk.logout()
    NTSdk.logout()
end

function sdk.switchAccount()
    NTSdk.switchAccount()
end

function sdk.traceAccount(serverid, level)
    NTSdk.traceAccount(serverid, level)
end

function sdk.bugReport(serverid, nickname, clientversion)
    NTSdk.bugReport(serverid, nickname, clientversion)
end

function sdk.userCenter(serverid, nickname, clientversion)
    NTSdk.userCenter(serverid, nickname, clientversion)
end

function sdk.storeReview()
    NTSdk.storereview()
end

function sdk.getChannelID()
    return NTSdk.getChannelID()
end

function sdk.eventTrack(event)
    NTSdk.eventTrack(event)
end

function sdk.queryWithProducts(products)
    NTSdk.queryWithProducts(products)
end

function sdk.getProductDisplayPrice(id)
    return NTSdk.getProductDisplayPrice(id)
end

function sdk.payWithProductID(productid, serverid, ext, level)
    NTSdk.payWithProductID(productid, serverid, ext, level)
end

function sdk.registerLoginListener(handler)
    NTSdk.registerEventHandler(NTSdk.EventType.LOGIN, handler)
end

function sdk.registerPayListener(handler)
    NTSdk.registerEventHandler(NTSdk.EventType.PAY, handler)
end

return sdk

至此,所有工作结束,这样桥接文件就搞好了,lua可以直接调用c++函数,c++可以直接调用oc函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值