最近在研究jni。jni: java native interface。
遇到的问题是如何在windows下打包生成native函数。直接使用helloworld入正题。
1)首先创建HelloWorld.java文件:
class HelloWorld
{
public native void hello();//创建一个native函数,需要用C实现
static{
System.loadLibrary("hello"); //这里加载的库是hello.so或者hello.dll等,我们使用.so
}
public static void main(String[] args)
{
new HelloWorld().hello();
}
}
2)将上述文件保存为HelloWorld.java
如下图:
3)打开cygwin(我的平台是win7 64位,cygwin-terminal 64)
进入到存放的目录(下面都是我的文件路径):
$cd /cygdrive/e/android/test
4)通过javac生成.class(java路径配置在这里不描述了)
$javac HelloWorld.java
这样就可以在文件夹下看到HelloWorld.class文件了
5)通过.class生成native要用的.h文件
$javah -jni HelloWorld
注意这里只需要输入HelloWorld即可,自动会调用HelloWorld.class
6)通过5)生成的HelloWorld.h内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
7)由上述源码可以知道,我们要在C中实现函数HelloWorld_hello()。
具体HelloWorld.c实现如下:
#include <stdio.h>
typedef signed long long __int64;
#include <jni.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_hello
(JNIEnv *env, jobject obj){
printf("Hello World!\n");
}
其中需要补充一下的是,在编译C时出现了很多问题:
首先是jni.h不能被找到,stdio.h也找不到。
jni.h是包含在%JAVA_HOME%\include目录下,而jni.h又包含了jni_md.h,这个文件在%JAVA_HOME%\include\win32里。
如果在cygwin下直接-I"%JAVA_HOME%\include"或者-I"%JAVA_HOME%/include"等是不行的,因为JAVA_HOME只是win7下的环境变量,并不是cygwin下设置的环境变量。
建议直接 -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include" -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include/win32" 其中jdk的路径是C:\Program Files\Java\jdk1.6.0_45。
编译命令如下:
$gcc -c -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include" -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include/win32" HelloWorld.c -o hello.o
这个时候提示错误:
错误显示内容是__int64没有定义。这个问题我也不知道该包含哪些库。最简单的办法是直接在HelloWorld.c里加typedef long long __int64;
放的位置有讲究。由错误图片可以看出,是jni_md.h里没有定义__64,故需要在jni.h前定义好typedef.
8)再次执行
$gcc -c -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include" -I"/cygdrive/c/Program Files/Java/jdk1.6.0_45/include/win32" HelloWorld.c -o hello.o
可以看到生成了目标文件hello.o
9)接下来就是要将hello.o文件生成.so的动态链接库
命令如下:
$gcc hello.o -shared -fPIC -o libhello.so
建议加入-fPIC生成标准的C++函数库。
执行完成后就可以看到libhello.so了。
至于为什么要用libhello.so,是因为android在System.loadLibrary(“hello”)时自动会查找libhello.so的。
需要深入的话推荐看《深入理解Android》