android LUA 调用C 编译的.SO动态库

测试环境 c4droid 懒人精灵 雷电模拟器 PC DNK-build

DNK-build 编译文件目录
编译环境
lua支持库

SRC目录保存 要编译的.C文件 luabib目录保存 LUA支持库以及 需要的.SO文件

下面展示 MyLib.c代码

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
// An highlighted block
#include <math.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

#include <unistd.h>//pwrite64        头文件
#include <stdlib.h>//atof 头文件
#include <ctype.h>// tolower toupper 头文件

#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PATH  1024
#include <sys/ptrace.h>

static int PagGamePID = 0;

unsigned long hexToDec(const char* addr) {
    unsigned long num;
    sscanf(addr, "%lx", &num);//4294967296
    return num;
}
char* strlowr(char* str)
{
    char* orign = str;
    for (; *str != '\0'; str++)
        *str = tolower(*str);
    return orign;
}
char* strupr(char* str)
{
    char* orign = str;
    for (; *str != '\0'; str++)
        *str = toupper(*str);
    return orign;
}

int FindPidByProcessName(const char* process_name) {
    int ProcessDirID = 0;
    pid_t   pid = -3;
    FILE* fp = NULL;
    char filename[MAX_PATH] = { 0 };
    char  cmdline[MAX_PATH] = { 0 };

    struct dirent* entry = NULL;

    if (process_name == NULL) {
        return -1;
    }

    DIR* dir = opendir("/proc");
    if (dir == NULL) {
        return -2;
    }

    while ((entry = readdir(dir)) != NULL) {
        ProcessDirID = atoi(entry->d_name);//将数字文件名转换为int ,转换失败的话返回0;
        if (ProcessDirID != 0) {
            snprintf(filename, MAX_PATH, "/proc/%d/cmdline", ProcessDirID);// 文件/proc/<pid>/cmdline 为进程的启动命令行。安卓平台的为app包名;
            fp = fopen(filename, "r");
            if (fp)
            {
                fgets(cmdline, sizeof(cmdline), fp);
                fclose(fp);
                if (strncmp(process_name, cmdline, strlen(process_name)) == 0)
                {
                    pid = ProcessDirID;
                    break;
                }
            }
        }
    }
    closedir(dir);
    return pid;
}

static int Add(lua_State* L) {
    double d1 = luaL_checknumber(L, 1);
    double d2 = luaL_checknumber(L, 2);
    lua_pushnumber(L, d1 + d2);
    return 1;//1个结果
}

static int Adr(lua_State* L) {
    double d1 = luaL_checknumber(L, 1);
    double d2 = luaL_checknumber(L, 2);
    lua_pushnumber(L, d1 - d2);
    return 1;
}

//--SO 调用方法
static int luaGetPagGamePID(lua_State* L) {
    //string d1 = lua_checkstring(L, 1);
    const char* str_pt = luaL_checkstring(L, 1);
    //int d2 = 0;
    int d2 = FindPidByProcessName(str_pt);
    PagGamePID = d2;//记录包名PID
    lua_pushnumber(L, d2);
    return 1;
}

static int luaSetPagGamePID(lua_State* L) {
    const int pid = luaL_checknumber(L, 1);
    PagGamePID = pid;//记录包名PID
    lua_pushnumber(L, PagGamePID);
    return 1;
}

static const struct luaL_Reg R[] = {
    {"Add" , Add},
    {"Adr" , Adr},
    {"CppGetPagGamePID",luaGetPagGamePID},
    {"CppSetPagGamePID",luaSetPagGamePID},

    {NULL, NULL}
};

static int luaclose_libMyLib(lua_State* L) //关闭so时释放资源
{
    return 0;
}

int luaopen_libMyLib(lua_State* L)
{
    luaL_newlib(L, R); // 5.2
    return 1;
}

Android.mk

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
// An highlighted block
 LOCAL_PATH := $(call my-dir)
LOCAL_SHORT_COMMANDS := true

##链接其他的SO,因为用不到,注释掉
#include $(CLEAR_VARS)
#LOCAL_MODULE:= assist
#LOCAL_SRC_FILES:=lualib/$(TARGET_ARCH_ABI)/libassist.so
#include $(PREBUILT_SHARED_LIBRARY) #用来指定一个预先已经编译好的静态库

include $(CLEAR_VARS)           #这一步操作主要是清空之前定义的LOCAL_XXX开头的变量,是必须要的操作

#LOCAL_CPP_EXTENSION := .cc #注意统一模块中C++文件后缀必须保持一致。CPP文件编译

LOCAL_C_INCLUDES += $(LOCAL_PATH)/lualib/include #定义源文件所需的头文件所需的目录
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/clib #定义 C++引用的.h 文件目录

#LOCAL_CPP_FEATURES := rtti
LOCAL_CPP_FEATURES := exceptions

LOCAL_MODULE    := MyLib            #定义编译出来的模块名
LOCAL_SRC_FILES := src/MyLib.c      #定义编译模块所需的源文件
LOCAL_LDLIBS    := -lm -lz      #上面的代码告诉编译器在编译模块时还要连接/system/lib/libz.so
LOCAL_SHARED_LIBRARIES := assist    #编译此模块需要依赖的动态库
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

#该变量指向一个构建脚本并收集所有通过LOCAL_XXX变量指定的关于当前模块的信息,并根据你所列出的源文件构建一个动态库(.so)使用该变量前,你应该至少定义了LOCAL_MODULE和LOCAL_SRC_FILES
include $(BUILD_SHARED_LIBRARY)

Application.mk

1
2
3
4
// An highlighted block
APP_ABI := x86 armeabi-v7a
APP_PLATFORM := android-19
APP_SHORT_COMMANDS := true

PC cmd CD 到 so文件名JNI目录 输入 ndk-build 会自动编译

LUA代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// An highlighted block
libMyLib = require("libMyLib")

function main()
    local sum = libMyLib.Add(102,2)
    --local sum2 = libMyLib.Math.Adr(10,2)
    --com.nx.nxproj  com.testproject.testlogingame  12C039E8  Math.
    local sum2 = libMyLib.CppGetPagGamePID("com.testproject.testlogingame")
    local sum4=libMyLib.CppSetPagGamePID(23017)
    --local sum3=libMyLib.Math.CppPreadAddress("0x12C35394","word")
    --print(getPackageName())
    print("sum is:"..sum.."sum2 is:"..sum2.." sum4 is:"..sum4)
end
main()

调试结果

懒人调试结果

踩过的坑

1:ndk-build 的版本有问题, ndk-build 编译会报错一堆的BUG 需要使用 PC版的 ndk-build编译环境
2:LUA调用的 SO文件在 libs目录(jni 目录同级)
3:要注意 你使用的LUA编辑工具,我使用的懒人精灵 加载SO文件不给ROOT权限,CppGetPagGamePID 返回的结果是 -3.0
4:不同的LUA编辑工具不能 通用

总结:技术不够,没办法把C打包成 所有的LUA编辑工具使用

最后感谢 懒人精灵的开发者作者:懒人