使用jni接口完成android本地程序的运行

最近在开发android相关的程序。可惜啊,android的开发接口都是基于java的,作为一个c开发者,于是我想开发一个c程序,然后想法root掉那个手机,然后使用adb工具将程序拷贝到手机里就可以运行了...想法很好,但是有两个问题,第一,靠点击根本无法运行本地程序;第二,如果程序发布,难道能指望用户将手机寄过来然后帮他们root吗?于是这个方法直接pass掉了。
接下来,想把程序打包到一个基于java的apk中,安装的时候直接将程序复制到和apk相同的目录下,然后由java程序使用exec调用这个本地程序。实验证明,由于权限问题,不可行!后来又想将程序通过apk直接复制到SD卡上,但是通过查看android的源代码发现,SD卡被mount的时候是指定了noexec标志的,也就是说SD卡上的程序无法执行(这是有道理的,因为如果sd卡的程序可以执行的话,随便一个溢出漏洞就可能危害系统...再说,sd卡耗电,又不稳定)...于是,没有办法了!难道在android上开发程序必须用java吗?其实不是这样的!虽然接口是java,但是java明确规定了又jni接口可以调用本地程序的,如此看来,既然java对于android是被信任的,那么使用java的jni调用的本地程序也是被信任的(虽然java虚拟机并不管理它,但是它确实没有任何管理者监管啊),于是就想办法将要执行的本地程序封装成一个so(动态库),然后用java的loadlibrary执行之。
以ABC c语言编写的程序为例,下面的步骤搞定了它,这里仅仅用java SE作为例子,没有使用android的sdk/ndk,然而其工作原理是一样:
1.首先写一个java程序,很简单的:Test.java
class Test
{
public native void jni_main();
static {
System.loadLibrary("abc");
}
public static void main(String[] args) {
new Test().jni_main();
}
}
2.生成头文件:
javah Test
生成Test.h
3.将Test.h复制到ABC的源码目录下
4.想办法将abc编译成libabcd.so(其实ABC本来在linux平台被编译成一个elf可执行文件的,这里要把它编译成so,用于java程序的jni接口加载)
4.1.修改abc.c,如下:
//int main(int argc, char* argv[]) { //原来的main函数
JNIEXPORT void JNICALL Java_TestABC_Wrapper_1main (JNIEnv *env, jobject obj) { //修改后的jni接口调用的main函数
...
}
4.2.编写Makefile文件:
#开始
CC := droid-gcc
LD := droid-ld
DEFS = ...#复制原来的Makefile的该字段
LIBS = ...#复制原来的Makefile的该字段
CFLAGS := ...(复制原来Makefile的该CFLAGS) -I...#复制和android相关的头文件的路径
LDFLAGS := -shared -fpic
SOURCE := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SOURCE))
TARGET_LIB := libabc.so
all:$(OBJS)
$(LD) $(LDFLAGS) -o $(TARGET_LIB) $(OBJS) $(LIBS)
%.o:%.c
$(CC) -c $(CFLAGS) $< -o $*.o
*.o -rf
#结束
5.编译,执行make,最终生成一个so,然后运行java Test,结果是abc被运行啦!
PS:我认为,google的android仅仅用java作为其主流开发语言,这是不妥的,这样就使得很多厂商望而却步,很多做c的人望而却步,本来android的用户就没有symbian的多,现在由于这个原因,更使得它只能在众多hacker圈子里打转,一般的手机用户是不懂什么linux的,也不关心什么root权限,因此很多hacker方略对于一般的用户是没有意义的,他们关心的最终的体验,因此很多的任务不得不压在开发者身上,开发者越多就意味着潜在用户越多,symbian走的就是这条路线,palm当初也许就是因为没有走这个路线而失败的。因此,不管怎么多,平台提供者不应该限制开发者,开放的越多,应用就会越多,众口难调的用户才会易于伺候。

你可能感兴趣的:(android)