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

以下步骤均有自己测试完成。
实现JNI方式有两种,一种为动态方式,一种为静态方式,本文先讨论常用的静态方式

一,新建项目

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");
    }
}
 
View Code

 

static区声明的代码会先于onCreate方法执行,表明程序开始运行的时候会加载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的内容:
 
/* 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
View Code

 

函数名按照:java_pacakege_class_mathod 形式来命名。 

注意下其中的注释:

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!");
}
View Code

 

 

四,编译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++源代码文件。
include $(BUILD_SHARED_LIBRARY):表示编译生成共享库,是编译系统提供的变量

2.生产so库文件

进入到jni目录,输入命令:# ndk-build 即可生产,so库文件,即libs/armeabi/libcom_tom_myjni_JNI.so

五,eclipse运行,编译,打包成apk  


 
posted on 2013-11-29 13:17  lucky_tom  阅读(381)  评论(0编辑  收藏  举报