Android JNI (1)

来源:互联网 发布:c语言判断质数的程序 编辑:程序博客网 时间:2024/05/20 14:23

1.  Create a java project


package com.fxf;

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);