Android NDK JNI开发<7>
这一节C回调java程序方法,这步骤如下:
<1> : 启动eclipse,新建一个android工程,取名:hellojnidemo5,MainActivity的包名:package com.example.hellojnidemo5;这里面我回调的函数不是在这个包下,另外重新新建了一个包:package java2c;
在package java2c下新建一个回调用的类:functionInteface,代码如下:
package java2c; public class functionInteface { public native void javaToca(); public native void javaTocb(); public native void javaTocc(); public void show(){ System.out.println("show java information ."); } public int multi(int x, int y) { return x * y; } public void msg(String m) { System.out.println("your information : " + m); } }
有个细节要注意,要手动eclipse菜单project->clean一下,当然如果选择project->build automatically(如果勾上,会导致eclipse有点卡),那么就不需要手动.这样就可以让eclipse自动为我们生成.class文件了->functionInteface.class
<2> : 要将java类生成.h头文件,借助的是javah命令,当然前面可以用javac编译生成.class,就不要eclipse,但是javac只是在文件数目少的情况下,手工输入还行.
这个目录让人有点纠结,不知道为什么,其实很简单:
比如我的工程目录在 : D:\ADB\android-ndk-r9d\workspace-jni\hellojnidemo5,而生成的.class在工程目录下子目录/bin/classes/java2c目录下,
但是用javah命令不要求进入到java2c这个目录下才能编译,根据javah后面带的格式,只需要进入顶级包文件夹所在的目录即可,即这里只需要进入classes目录下就可以了,
所以,启动cmd.exe

然后输入的命令格式 : javah -jni packagename.classname(不带扩展名)
这里是: D:\ADB\android-ndk-r9d\workspace-jni\hellojnidemo5\bin\classes>javah -jni java2c.functionInteface
结果就在classes目录下生成了java2c_functionInteface.h的头文件(生成后的头文件可以修改文件名放到jni文件夹下),具体内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class java2c_functionInteface */ #ifndef _Included_java2c_functionInteface #define _Included_java2c_functionInteface #ifdef __cplusplus extern "C" { #endif /* * Class: java2c_functionInteface * Method: javaToca * Signature: ()V */ JNIEXPORT void JNICALL Java_java2c_functionInteface_javaToca (JNIEnv *, jobject); /* * Class: java2c_functionInteface * Method: javaTocb * Signature: ()V */ JNIEXPORT void JNICALL Java_java2c_functionInteface_javaTocb (JNIEnv *, jobject); /* * Class: java2c_functionInteface * Method: javaTocc * Signature: ()V */ JNIEXPORT void JNICALL Java_java2c_functionInteface_javaTocc (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
另外一个javap -s packagename.classname可以获得方法的签名,这个签名信息非常重要,是后面c中事要用到的信息:

(如果经常报出javah找不到文件,这个问题上次在公司见过,其实没什么大不了的,是由于jdk设置环境变量导致的:
具体设置参考: http://blog.csdn.net/yusiguyuan/article/details/14123669(主要要设置JAVA_HOME变量,具体原因不清楚,我一直都是直接用jdk绝对路径)
另外附加一条连接:http://361324767.blog.163.com/blog/static/11490252520103783716114/做参考.)
<3> 折腾了半天,把c源码写出来(javatoc.h):
#include "java2c_functionInteface.h" #include<android/log.h> #include<string.h> //修改日志tag中的值 #define LOG_TAG "logfromc" //日志显示的等级 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_com_example_hellojnidemo5_MainActivity_javaToca(JNIEnv * env,jobject obj){ LOGI("in call java msg"); //get class name firstly // 获取到functionInteface对象 char* classname="java2c/functionInteface"; jclass dpclazz=(*env)->FindClass(env,classname); if(dpclazz==0){ LOGI("not find class!"); }else{ LOGI("find class"); } //第三个参数 和第四个参数 是方法的签名,第三个参数是方法名 , 第四个参数是根据返回值和参数生成的 jmethodID methodID=(*env)->GetMethodID(env,dpclazz,"show","()V"); if(methodID==0){ LOGI("not find method!"); }else{ LOGI("find class"); } //获取到functionInteface要调用的方法 (*env)->CallVoidMethod(env,obj,methodID); } JNIEXPORT void JNICALL Java_com_example_hellojnidemo5_MainActivity_javaTocb(JNIEnv * env,jobject obj){ LOGI("in call java msg"); //get class name firstly char* classname="java2c/functionInteface"; jclass dpclazz=(*env)->FindClass(env,classname); if(dpclazz==0){ LOGI("not find class!"); }else{ LOGI("find class"); } jmethodID methodID=(*env)->GetMethodID(env,dpclazz,"msg","(Ljava/lang/String;)V"); if(methodID==0){ LOGI("not find method!"); }else{ LOGI("find class"); } (*env)->CallVoidMethod(env,obj,methodID,(*env)->NewStringUTF(env,"zhibao.liu")); } JNIEXPORT void JNICALL Java_com_example_hellojnidemo5_MainActivity_javaTocc(JNIEnv * env,jobject obj){ LOGI("in call java msg"); //get class name firstly char* classname="java2c/functionInteface"; jclass dpclazz=(*env)->FindClass(env,classname); if(dpclazz==0){ LOGI("not find class!"); }else{ LOGI("find class"); } jmethodID methodID=(*env)->GetMethodID(env,dpclazz,"multi","(II)I"); if(methodID==0){ LOGI("not find method!"); }else{ LOGI("find class"); } (*env)->CallVoidMethod(env,obj,methodID,11,12); }
<4> : 用cgywin编译后生成so文件.
<5> android调用代码:
package com.example.hellojnidemo5; import java2c.functionInteface; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private Button mShowBtn; private Button mMultiBtn; private Button mMsgBtn; private functionInteface fn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fn=new functionInteface(); mShowBtn=(Button)findViewById(R.id.button1); mShowBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "show message ! ", Toast.LENGTH_SHORT).show(); fn.show(); fn.javaTocb(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } static{ System.loadLibrary("jnilibs"); } }
这一片文章最后要推荐一个参考链接:http://blog.csdn.net/furongkang/article/details/6857610
似乎全部的网络和教材都TMD用一个例子再讲,汗死一片....

浙公网安备 33010602011771号