移动开发 \ Android \ android java 调用 c

android java 调用 c

总点击240
简介:windowseclipseAndroidjdk1.7 javah时报错“错误:找不到***类文件“ 按照网上的教程都没用,最后解决方法:

windows eclipse Android jdk1.7


javah时报错“错误: 找不到 ***类文件“

按照网上的教程都没用,最后解决方法:

在AndroidManifest.xml同级目录下,新建Exportjni.bat

Exportjni.bat内容为:

javah -classpath binclasses -d jni com.yeshen.ndk.HelloNDK


双击bat就可以生成com_yeshen_ndk_HelloNDK.h,世界清净了


本文链接:http://blog.csdn.net/yeshennet/article/details/38564045


2016补:

以下转载:来自其他几个博客,原文链接都在模块的头部:


http://blog.csdn.net/xnwyd/article/details/7086384  

---------------------------------------------------------转载-----分割线---------------------------------------------------------------

安装jdk1.6

(1)从jdk官方网站http://www.oracle.com/technetwork/java/javase/downloads/jdk-6u29-download-513648.html下载jdk-6u29-linux-i586.bin文件。

(2)执行jdk安装文件

[html] view

plain copy

$chmod a+x jdk-6u29-linux-i586.bin  

$jdk-6u29-linux-i586.bin  


(3)配置jdk环境变量


[html] view

plain copy

$sudo vim /etc/profile  

#JAVAEVIRENMENT  

exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29  

exportJRE_HOME=$JAVA_HOME/jre  

exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH  

exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH  


保存后退出编辑,并重启系统。


(4)验证安装


[html] view

plain copy

$java -version  

javaversion "1.6.0_29"  

Java(TM)SE Runtime Environment (build 1.6.0_29-b11)  

JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)  

$javah  

用法:javah[选项]<类>  

其中[选项]包括:  

-help输出此帮助消息并退出  

-classpath<路径>用于装入类的路径  

-bootclasspath<路径>用于装入引导类的路径  

-d<目录>输出目录  

-o<文件>输出文件(只能使用-d或-o中的一个)  

-jni生成JNI样式的头文件(默认)  

-version输出版本信息  

-verbose启用详细输出  

-force始终写入输出文件  

使用全限定名称指定<类>(例  

如,java.lang.Object)。  

安装android应用程序开发环境

ubuntu下安装android应用程序开发环境与windows类似,依次安装好以下软件即可:

(1)Eclipse

(2)ADT

(3)AndroidSDK

与windows下安装唯一不同的一点是,下载这些软件的时候要下载Linux版本的安装包。

安装好以上android应用程序的开发环境后,还可以选择是否需要配置emulator和adb工具的环境变量,以方便在进行JNI开发的时候使用。配置步骤如下:

把emulator所在目录android-sdk-linux/tools以及adb所在目录android-sdk-linux/platform-tools添加到环境变量中,android-sdk-linux指androidsdk安装包android-sdk_rxx-linux的解压目录。

[plain] view

plain copy

$sudo vim /etc/profile  

exportPATH=~/software/android/android-sdk-linux/tools:$PATH  

 exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH  


编辑完毕后退出,并重启生效。


安装NDK

NDK是由android提供的编译android本地代码的一个工具。

(1)从androidndk官网http://developer.android.com/sdk/ndk/index.html下载ndk,目前最新版本为android-ndk-r6b-linux-x86.tar.bz2.

(2)解压ndk到工作目录:

[plain] view

plain copy

$tar -xvf android-ndk-r6b-linux-x86.tar.bz2  

$sudo mv android-ndk-r6b /usr/local/ndk  


(3)设置ndk环境变量


[plain] view

plain copy

$sudo vim /etc/profile  

exportPATH=/usr/local/ndk:$PATH  


编辑完毕后保存退出,并重启生效


(4)验证安装

[plain] view

plain copy

$ cd/usr/local/ndk/samples/hello-jni/  

$ ndk-build  

Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver  

Gdbsetup : libs/armeabi/gdb.setup  

Install : libhello-jni.so => libs/armeabi/libhello-jni.so  


JNI实现

我们需要定义一个符合JNI接口规范的c/c++接口,这个接口不用太复杂,例如输出一个字符串。接下来,则需要把c/c++接口的代码文件编译成共享库(动态库).so文件,并放到模拟器的相关目录下。最后,启动Java应用程序,就可以看到最终效果了。

编写Java应用程序代码

(1)启动Eclipse,新建android工程

Project:JNITest

Package:org.tonny.jni

Activity:JNITest

(3)编辑JNITest.java文件

[java] view

plain copy

packageorg.tonny.jni;  

  

importandroid.app.Activity;  

importandroid.os.Bundle;  

importandroid.view.View;  

importandroid.widget.EditText;  

importandroid.widget.Button;  

  

  

publicclassJNITestextendsActivity {  

static{  

System.loadLibrary("JNITest");  

}  

privatenativeString GetReply();  

privateEditTextedtName;  

privateButtonbtnShow;  

Stringreply;  

/**Called when the activity is first created. */  

@Override  

publicvoidonCreate(Bundle savedInstanceState) {  

super.onCreate(savedInstanceState);  

setContentView(R.layout.main);  

reply= GetReply();  

edtName= (EditText)this.findViewById(R.id.ed_name);  

btnShow= (Button)this.findViewById(R.id.btn_show);  

btnShow.setOnClickListener(newButton.OnClickListener() {  

publicvoidonClick(View arg0) {  

edtName.setText(reply);  

}  

});  

}  

}  

我们看这一段代码:

[java] view

plain copy

static{  

System.loadLibrary("JNITest");  

}  

static表示在系统第一次加载类的时候,先执行这一段代码,在这里表示加载动态库libJNITest.so文件。

再看这一段:

[java] view

plain copy

privatenativeString GetReply();  

native表示这个方法由本地代码定义,需要通过jni接口调用本地c/c++代码。

[java] view

plain copy

publicvoidonClick(View arg0) {  

edtName.setText(reply);  

}  


这段代码表示点击按钮后,把native方法的返回的字符串显示到EditText控件。


(4)编译工程,生成.class文件。


用javah工具生成符合JNI规范的c语言头文件


在终端中,进入android工程所在的bin目录

[plain] view

plain copy

$cd ~/project/Android/JNITest/bin  

我们用ls命令查看,可以看到bin目录下有个classes目录,其目录结构为classes/org/tonny/jni,即classes的子目录结构是android工程的包名org.tonny.jni。请注意,下面我们准备执行javah命令的时候,必须进入到org/tonny/jni的上级目录,即classes目录,否则javah会提示找不到相关的java类。

下面继续:

[plain] view

plain copy

$cd classes  

$javah org.tonny.jni.JNITest  

$ls  

org org_tonny_jni_JNITest.h  


执行javahorg.tonny.jni.JNITest命令,在classes目录下会生成org_tonny_jni_JNITest.h头文件。如果不进入到classes目录下的话,也可以这样:

[plain] view

plain copy

$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest  

-classpath 参数表示装载类的目录。


编写c/c++代码

生成org_tonny_jni_JNITest.h头文件后,我们就可以编写相应的函数代码了。下面在android工程目录下新建jni目录,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h头文件拷贝到jni目录下,并在jni目录下新建org_tonny_jni_JNITest.c文件,编辑代码如下:

[cpp] view

plain copy

#include<jni.h>  

#include<string.h>  

#include"org_tonny_jni_JNITest.h"  

  

  

JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply  

(JNIEnv *env, jobject obj){  

return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");  

}  


我们可以看到,该函数的实现相当简单


http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html

---------------------------------------------------------转载-----分割线---------------------------------------------------------------

第四步:

编译生成so库

编译com_lucyfyr_HelloWorld.c成so库可以和app一起编译,也可以都单独编译。

在当前目录下建立jni文件夹:HelloWorld/jni/

下建立Android.mk ,并将com_lucyfyr_HelloWorld.c和 com_lucyfyr_HelloWorld.h 拷贝到进去

编写编译生成so库的Android.mk文件:

 

android java 调用 c

LOCAL_PATH:= $(call my-dir)

# 一个完整模块编译

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)

LOCAL_MODULE := libHelloWorldJni

LOCAL_SHARED_LIBRARIES := libutils

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE_TAGS :=optional

include $(BUILD_SHARED_LIBRARY)

android java 调用 c

 

系统变量解析:

LOCAL_PATH

- 编译时的目录


$(call 目录,目录….) 目录引入操作符


如该目录下有个文件夹名称 src,则可以这样写 $(call

src),那么就会得到 src 目录的完整路径

include

$(CLEAR_VARS) -清除之前的一些系统变量


LOCAL_MODULE -

编译生成的目标对象


LOCAL_SRC_FILES -

编译的源文件


LOCAL_C_INCLUDES -

需要包含的头文件目录


LOCAL_SHARED_LIBRARIES -

链接时需要的外部库


LOCAL_PRELINK_MODULE -

是否需要prelink处理 


include$(BUILD_SHARED_LIBRARY) -

指明要编译成动态库


http://blog.csdn.net/laczff21/article/details/7542236


---------------------------------------------------------转载-----分割线---------------------------------------------------------------

第一次生成so文件的时候,我们先使用NDK的sample下的hello-jni的例子。

1、启动eclipse,通过Create project  from existing source,选择hello-jni的目录,按默认选项创建工程即可;

2、观察hello-jni的工程目录结构,发现根目录下多了一个名叫jni的文件夹,该文件夹下面有两个文件,Android.mk和hello-jni.c。

     Android.mk是用来生成so文件的配置文件,我们来看看里面是什么:

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni


LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

include $(BUILD_SHARED_LIBRARY)表示会生成一个动态链接库,即so文件,生成的库文件名称为lib*.so


LOCAL_MODULE    := hello-jni表示将要生成一个名称为libhello-jni.so的库文件

LOCAL_SRC_FILES := hello-jni.c表示生成库文件的源文件是hello-jni.c

    打开hello-jni.c文件,会看到里面有一个函数:


jstring Java_com_example_hellojni_HelloJni_stringFromJNI(

JNIEnv* env,jobject thiz )


{


    return (*env)->NewStringUTF(env,"Hello from JNI !");


}

这个函数从根据什么原则生成的呢?是根据src下的HelloJni.java文件中的函数 public

native String  stringFromJNI();生成的。命名规则为:


Java_(固定开头)com_example_hellojni(用"_"连接的包名)_HelloJni(类名)_stringFromJNI(函数名)

   

这个函数的生成可以使用javah的命令:用命令行方式进入工程目录的binclasses目录下,运行javah com.example.hellojni.HelloJni,就会把所有native的函数都按规则生成在一个名为HelloJni.h的头文件里。

3、新建并配置一个新的Builder

    1) 点击Project->Properties->Builders->New,新建立一个Builder。在弹出的对话框上面点击Program,点击OK;

    2) 在弹出的对话框【Edit Configuration】中,配置选项卡【Main】:

               Location中需要填入nkd-build.cmd的路径(NDK安装目录下)。

               WorkingDiretcoty中需要填入HelloJni的工程根目录。

    3) 在【EditConfiguration】中,配置选项卡【Refresh】:

              勾选“Refresh resources upon completion”,

              勾选“The entire workspace”,

              勾选“Recuresively include sub-folders”。

    4)在【EditConfiguration】中,配置选项卡【Build Options】:

             勾选“After a “Clean””,

             勾选“During manual builds”,

             勾选“During auto builds”,

             勾选“Specify working set of relevant resources”。

             点击“Specify Resources…”勾选TestNDK工程的“jni“目录,Finish!

      保存设置,点击OK。

4、生成so文件

     由于我们勾选了“During auto builds”,所以在工程有所改变的时候,so文件便会自动编译,正确生成以后就能在工程目录下发现多了两个文件夹,文件夹libsarmeabi目录下生成了一个叫libhello-jni.so的文件。至此,使用NDK生成so文件的工作就完成了。



意见反馈 常见问题 官方微信 返回顶部