1. Create a java project
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class HelloWorldActivity extends Activity {
private static final String TAG="HelloWorld";
static {
System.loadLibrary("helloworld");
}
private native String printJNI();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "Activity call JNI:" + printJNI() );
}
}
2. generate JNI head file from the java class file
go to <project path>/bin/classes
$ javah -jni com.fxf.HelloWorldActivity
will create a com_fxf_HelloWorldActivity.h, this is a JNI head file, rename is as helloworld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_fxf_HelloWorldActivity */
#ifndef _Included_com_fxf_HelloWorldActivity
#define _Included_com_fxf_HelloWorldActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_fxf_HelloWorldActivity
* Method: printJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_fxf_HelloWorldActivity_printJNI
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
Edit helloworld.c
#include <jni.h>
#define LOG_TAG "HelloWorld"
#include<utils/Log.h>
//#define LOG_TAG "debug"
//#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
//#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
//#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_fxf_HelloWorldActivity_printJNI(JNIEnv *env, jobject obj)
{
LOGI("Hello World From libhelloworld.so!");
return (*env)->NewStringUTF(env, "Hello World!");
}
/* This function will be call when the library first be load.
* You can do some init in the libray. return which version jni it support.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
void *venv;
LOGI("JNI_OnLoad!");
if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed");
return -1;
}
return JNI_VERSION_1_4;
}
Edit Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=helloworld.c
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
#add these 2 lines to include for utils/Log.h
LOCAL_C_INCLUDES += /home/hadoop/androidsrc/frameworks/base/include/
LOCAL_C_INCLUDES += /home/hadoop/androidsrc/system/core/include/
LOCAL_MODULE := helloworld
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog #this is the log lib used, seem that is not libutils
include $(BUILD_SHARED_LIBRARY)
The c log will present in Logcat of eclipse
compile c native file
create a dir named jni in android project root, put helloworld.h helloworld.c Android.mk in that dir.
$ <path of NDK>/ndk-build
will create a .so file in <android project path>/libs/armeabi/libhelloworld.s
JNI callback
java code
package com.fxf;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class HelloWorldActivity extends Activity {
private static final String TAG="HelloWorld";
private Handler myhandler = null;
static Handler sthandler = null;
public TextView tv=null;
public TextView dev=null;
public Button btn=null;
static {
System.loadLibrary("helloworld");
}
private static native String printJNI();
private static native String init(String dev);
/** Called when the activity is first created. */
//@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv=(TextView)this.findViewById(R.id.tv);
dev=(TextView)this.findViewById(R.id.device);
myhandler=new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
int i = msg.what;
String s = msg.obj.toString();
Log.i(TAG, s );
tv.append(s+"\n");
super.handleMessage(msg);
}
};
btn.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String device = dev.getText().toString();
String s;
s = init(device);
Log.d(TAG, "init joystick result:" + s );
tv.append(s+"\n");
}
});
sthandler = myhandler;
String s = printJNI();
Log.d(TAG, "Activity call JNI:" + printJNI() );
tv.append(s+"\n");
// s = init("/dev/input/js0");
// Log.d(TAG, "init joystick result:" + s );
// tv.append(s+"\n");
//init("/dev/input/js0");
//new Thread(new myThread()).start();
}
class myThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
String s = init("/home/fxf/char_dev");
Log.d(TAG, "init joystick result:" + s );
tv.append(s+"\n");
}
}
public void myCallbackFunc(String nMsg) //this is a callback function from jni
{
Log.v(TAG,"back message:"+nMsg);
Message msg = new Message();
msg.what=0;
msg.obj=nMsg;
sthandler.sendMessage(msg); //here, sthandler must be a static variable, other if, myhandler using here, will be null.
}
}
Jni code
gJinMethod=(*env)->GetMethodID(env,gJniClass,"myCallbackFunc","(Ljava/lang/String;)V");
if(gJinMethod==0 || gJinMethod==NULL)
return (*env)->NewStringUTF(env, "-2");
strcpy(tChar,"PROG:10");
(*env)->CallVoidMethod(env,gJniObj,gJinMethod,(*env)->NewStringUTF(env, tChar));
DisplayCallBack(env);