Ubuntu下使用NDK实现JNI调用
参考文档 : http://blog.csdn.net/redoffice/article/details/6654714
http://my.oschina.net/sosofy/blog/78353
http://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/15/2352890.html
后来发现一博客,本人推荐:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3095074.html
以下步骤均有自己测试完成。
http://my.oschina.net/sosofy/blog/78353
http://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/15/2352890.html
后来发现一博客,本人推荐:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3095074.html
以下步骤均有自己测试完成。
实现JNI方式有两种,一种为动态方式,一种为静态方式,本文先讨论常用的静态方式
MainActivity代码:
View Code
static区声明的代码会先于onCreate方法执行,表明程序开始运行的时候会加载com_tom_myjni_JNI
JNI.java代码
# cd /home/wu/workspace/HelloJNI/
一,新建项目
1,新建Android项目HelloJNI,如图:
2,这里新建一个包com.tom.myjni和接口文件JNI.java,可以把所有要实现调用的方法在这里首先声明,方便,结构清晰。
MainActivity代码:
package com.tom.hellojni; import com.tom.myjni.JNI; import android.os.Bundle; import android.app.Activity; import android.widget.TextView; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView text = (TextView) findViewById(R.id.text); JNI jni = new JNI(); String str = jni.printString(); text.setText(str); } static { System.loadLibrary("com_tom_myjni_JNI"); } }
JNI.java代码
package com.tom.myjni; public class JNI { public native String printString(); }
native 关键字表示这两个方法是本地方法,也就是说这两个方法是通过本地代码(C/C++)实现的,在java代码中仅仅是声明
二,生产.h头文件
1,进入主目录
# cd /home/wu/workspace/HelloJNI/2,新建一个目录
新建一个目录jni,输入命令:# mkdir jni (必须叫这个,否则后面会不能编译哦)
3,javah 命令
输入命令:# javah -classpath bin/classes/ -d jni com.tom.myjni.JNI此时在jni目录会产生文件com_tom_my_jni.h
*******
这里如果是在XXXActivity中 声明的native 方法的话,如果运行 # javah -classpath bin/classes/ -d jni com.tom.xxx.xxxActivity则会报找不到android.app.Activity的错误信息。原因是你的activity种引用android的包导致javah认不出来,可以加上android.jar的路径,
有两种方法,一是在命令中加入,二是在环境变量中配置
例如:javah -classpath bin/classes -bootclasspath /opt/adt_bundle_linux/sdk/platforms/android-19/android.jar -d jni com.tom..xxxActivity
例如:export CLASSPATH=.:/opt/adt_bundle_linux/sdk/platforms/android-19/android.jar:$CLASSPATH
*******
com_tom_my_jni.h的内容:
View Code
函数名按照:java_pacakege_class_mathod 形式来命名。
com_tom_my_jni.h的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_tom_myjni_JNI */ #ifndef _Included_com_tom_myjni_JNI #define _Included_com_tom_myjni_JNI #ifdef __cplusplus extern "C" { #endif /* * Class: com_tom_myjni_JNI * Method: printString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_tom_myjni_JNI_printString (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
注意下其中的注释:
Signature: ()Ljava/lang/String;
()Ljava/lang/String;
()表示函数的参数为空(这里为空是指除了JNIEnv *, jobject 这两个参数之外没有其他参数,JNIEnv*, jobject是所有jni函数必有的两个参数,分别表示jni环境和对应的java类(或对象)本身),
Ljava/lang/String; 表示函数的返回值是java的String对象。
三,根据.h文件编写相应的C/C++代码。
同样在jni目录下新建com_tom_my_jni.c文件
com_tom_my_jni.c代码:
/* ============================================================================ Name : hello.c Author : wu Version : Copyright : Your copyright notice Description : Hello World in C, Ansi-style ============================================================================ */ #include <string.h> #include <jni.h> jstring JNICALL Java_com_tom_myjni_JNI_printString (JNIEnv *env, jobject thiz){ return (*env)->NewStringUTF(env,"Hello Jni!"); }
四,编译so动态库
1,在jni目录下建立Android.mk文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := com_tom_myjni_JNI LOCAL_SRC_FILES := com_tom_myjni_JNI.c include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH :用于返回当前路径(即包含Android.mk file文件的目录)
include $(CLEAR_VARS):指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量
LOCAL_MODULE :编译的目标对象,注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'hello-jni'的共享库模块,将会生成'libhello-jni.so'文件
LOCAL_SRC_FILES :变量必须包含将要编译打包进模块中的C或C++源代码文件。LOCAL_MODULE :编译的目标对象,注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'hello-jni'的共享库模块,将会生成'libhello-jni.so'文件
include $(BUILD_SHARED_LIBRARY):表示编译生成共享库,是编译系统提供的变量
2.生产so库文件
进入到jni目录,输入命令:# ndk-build 即可生产,so库文件,即libs/armeabi/libcom_tom_myjni_JNI.so