文章首发于开源中国,这里是作者本人转载
公司的项目最近要使用Lua进行全平台的解析,iOS的集成在网上已经有了教程,但是lua三方库的集成一直出现错误。在混迹github,stack overflow许久后,终于在cocoa 2dx的相关问题中找到了一个合适的方法,在此总结成篇,以供各位参考。
先抛出几篇基础教程:
将Lua嵌入iOS程序与基本语言的交互:http://taox.l.blog.163.com/blog/static/4836557320121020749247/
作者:Tolecen
ps:网上说Wax开源代码库是可以调用objc的,但是那个库是用来调用开发接口的,不是底层lua文件,不推荐使用(实在不知道该怎么直接用wax直接解析lua文件)
lua加载c动态库:http://www.cnblogs.com/respawn/archive/2012/11/23/2781786.html
作者:小岩
ps:这个是纯c代码,标注一个重点方法:luaL_openlib,围绕这个看就好。
cocos2dx-lua用到的扩展:https://github.com/yangzhu6263736/cocos2dx-lua-ext
ps:感谢这位仁兄的赐教,发现了文件错误,为我指导了相关思路。
安卓lua第三方库的集成方案:http://blog.csdn.net/zzulp/article/details/24184521
作者:zzulp
ps:同样是移动端,提供了一个可行的解决方法。也给iOS提供了一定的思路。
以上的文章如果没有基础,请仔细查看,看了又看才好。还有就是本教程不是为了一定解决问题,而是提供思路。
--------------------------------------------------------------------------------------------2015年02月10日上午
具体集成方法
首先按第一篇文章加入lua库,也就是执行里面的“一、在XCODE中配置LUA”。这里注意,最好集成lua5.1版本不要使用5.2版本。因为第三方库对5.2的支持有些问题,如果你需要5.2版本lua的新特性,请自行寻找可用版的三方库。
下载https://github.com/yangzhu6263736/cocos2dx-lua-ext里面的文件加入到工程里,里面luasocketscripts,lualoadexts文件是配置第三方库的配置文件,如果你要添加其他库,可以在这里进行修改。代码不复杂,请自己浏览理解。这里是.c里面的核心代码:
-
1
2
3
4
5
6
7
socket
int
luaopen_socket(lua_State *L) {
int
arg = lua_gettop(L);
luaL_loadbuffer(L,(
const
char
*)B1,
sizeof
(B1),
"socket.lua"
);
lua_insert(L,1);
lua_call(L,arg,1);
return
1;
}
现在就有了lua源码和第三方库,想要配置第三方库直接引入#include "lualoadexts.h",并在代码中使用lua_loadexts(lua_State*L)方法,就能简单的编译第三方库到程序中了。这里默认添加了cjson和socket两个库。具体的使用下面会提及。
剩下的这里直接贴出代码,和相关解释。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//
// ViewController.m
// lua
//
// Created by Peter Kong on 15-1-6.
// Copyright (c) 2015年 CrazyPeter. All rights reserved.
//
#import "ViewController.h"
#include "lualoadexts.h"
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/*
以下是宏定义代码,复制进去就好,不需要理解(其实一般用不到)
*/
#define NOERROR 0
#define LUA_PMCNT_CHECK(n)\
{ \
int
nParamCnt = lua_gettop(L) ; \
if
( nParamCnt != n ) \
{\
lua_pushnumber( L , -1 ) ; \
return
1 ; \
} \
}
#define LUA_RET_VALUE(n)\
{ \
lua_pushnumber( L , n ); \
return
1 ; \
}
#define LUA_OUT_ERROR(id) lua_pushnumber(L, id);if (id != 0) return 1;
/*
以上是宏定义代码,复制进去就好,不需要理解(其实一般用不到)
*/
/*
LUA相关代码部分
*/
unsigned
long
luaWorkTest(
void
* pParam)
{
//定义一个int变量来观测lua是否正常,后面有s1的地方都是判断方法是否正常调用成功
int
s1;
//为lua开启一块内存区(正式开始)
lua_State *L;
//启动lua的堆栈区状态(这个是根据名字随便猜的,估计类似于init方法)
L = luaL_newstate();
if
(L == NULL)
{
//lua程序执行有错误,此处会打印lua的错误行数,下同
NSLog(@
"error: %s \n"
, lua_tostring(L, -1));
return
-1;
}
//开启lua的基本使用库和注册相关函数(基本的加减发之类的简单函数方法库)
luaL_openlibs(L);
//加载第三方的函数库进入当前lua环境,这个在上面已经说明
//这里如果出了错误,要返回到lualoadexts文件里面查询第三方库的引用名称是否正确
luax_loadexts(L);
/*
1.注意,这里加载lua文件,我的需求是从网上下载lua代码,然后写入一个文件,存为.lua文件到本地,然后在这里调 用,网络下载和本地归档方法此处省略,如果不懂请自行百度。
2.NSString *logPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithForm at:@"luaname.lua"]] 这个方法会报错,因为这是读取文件路径的方法,请自己拼凑lua文件地址
3.luaname.lua这个文件我有,但是你没有,请换成自己要使用的lua文件
*/
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@
"luaname.lua"
]];
//tmp1就是lua文件所在地址的utf8格式的字符串
//在lua源码里面要使用标注的c语言格式,所以用了char变量
const
char
* tmp1= [logPath UTF8String];
NSLog(@
"tmp1 %s \n"
,tmp1);
//通过地址打开lua文件,放进lua环境中
s1 = luaL_loadfile(L, tmp1);
if
(s1 != 0)
{
NSLog(@
"error: %s \n"
, lua_tostring(L, -1));
lua_pop(L, 1);
return
-10;
}
//清空状态,这个代码要在开始结束时两次地方使用
lua_pcall(L, 0, 0, 0);
//lua_getglobal就是调用lua里面方法的方法了
lua_getglobal(L,
"func_printName"
);
//lua_pushstring是用来传参的,相应的还有pushbool。pushint,视参数类型而定
lua_pushstring(L, tmp2);
printf
(
"tmp2 = %s \n"
,tmp2);
/*
lua_pcall执行结果,里面的参数是
L:当前lua环境
1:传入的参数是1个
2:返回的参数是2个
0:执行正确的话result应该是0
*/
int
result = lua_pcall(L,1,2,0);
printf
(
"result = %d\n"
,result);
if
(result != 0) {
//lua程序执行有错误,此处会打印lua的错误行数,下同
NSLog(@
"error-1: %s \n"
, lua_tostring(L, -1));
return
-10;
}
if
(result == 0) {
//lua_toboolean,lua_tostring是从堆栈区获得的返回结果,1,2分别表示返回的第一个参数,第二个参数
BOOL
b = lua_toboolean(L, 1);
const
char
*tmp3 = lua_tostring(L, 2);
NSString *str = [NSString stringWithUTF8String:tmp3];
NSLog(@
"tmp3 - %s"
,tmp3);
NSLog(@
"b- %d"
,b);
//清除2个数据
lua_pop(L, 2);
}
//清空状态,这个代码要在开始结束时两次地方使用
lua_pcall(L, 0, 0, 0);
//关闭lua环境,防止内存溢出
lua_close(L);
return
0;
}
@interface ViewController ()
[@end](http://my.oschina.net/u/567204)
@implementation ViewController
- (
void
)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
/*
开启一条线程使用lua,因为lua在程序里是开启一块空间,也就是一个堆栈区,这样不会影响整体程序的主线程。
*/
//这里使用了block语法来开启线程
dispatch_queue_t queue = dispatch_queue_create(
"com.example.dothis"
, NULL);
dispatch_async(queue, ^{
//NULL是参数,其实也就是标准的c语言调用方法,在luaWorkTest方法里我们定义了一个随意的指针,其实就是作为演示使用而已,没有具体含义
luaWorkTest(NULL);
});
}
/*
这个是在lua中注册的objective-c方法,当lua调用objective-c方法时会调用,但注意必需使用类方法,并且在.h文 件里面声明该方法(具体的原理请仔细研究推荐的第一篇文章)
*/
+(
void
)changeA:(
int
)as B:(
int
)bs
{
NSLog(@
"hahaTHEA:%d"
,as);
}
- (
void
)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
[@end](http://my.oschina.net/u/567204)
- 还有具体的lua和objective-c的交互请仔细看第一个文档中的lua_register(L,"logSomething", logYouWhat);相关内容
注意:
1.静态库问题:lua成为静态库后,给其他人或者真机测试如果出现问题,请去百度iOS静态库的封装。
2.由于环境版本不同会有出入,请多查看报错信息
3.这里贴出的代码是不能直接运行的,只是一个指导方向。
(打完,收工)
-------------------------------------------------------------------------------------------2015年02月10日下午