• Android 中Java 和C/C++的相互调用方法


      在一些Android应用的开发中,需要通过JNI Android NDK工具实现JAVAC/C++之间的相互调用。

           Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI是本地编程接口,它使得在 Java 虚拟机 (VM)内部运行的 Java代码能够与用其它编程语言(CC++和汇编语言)编写的应用程序和库进行交互操作。

           由于Android的应用层的类都是以Java写的,这些Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Machine)来执行。在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让JavaC组件能通过标准的JNI介面而相互沟通。

           在实际应用中这两者之间的调用关系可以归纳为以下四种方式:

                 1.       在应用的JAVA代码中调用NDKC/C++实现的函数。

                 2.       在NDK开发中的C/C++代码调用应用中JAVA类的静态函数。

                 3.       在NDK开发中的C/C++代码调用应用中JAVA类当前传入NDK中的实例的函数。

                4.       在NDK开发中的C/C++代码调用应用中JAVA类新建实例的函数。

     

    下面我们就怎样在Eclipse中实现JNI编码和四种调用方式加以阐述。

     

    一、Eclipse中建立一个包含JNI开发的工程。

    在这里我们不直接导入NDK中的hello-jni来说明JNI的使用方法。而是新建立一个工程,来说明怎样建立一个包含JNI的工程。

    第一步:建立一个Andriod工程JniDemo,在该工程的根目录下建立一个叫jni的目录,在jni目录下建立一个叫Android.mk的文件,(当然你也可以从其他地方,比如ndk样例代码hello-jni中将里面的Android.mk复制过来修改) Android.mk里面的内容如下所示

    LOCAL_PATH :=$(call my-dir)

    include$(CLEAR_VARS)

    LOCAL_MODULE   := demo-jni

    LOCAL_SRC_FILES := demo-jni.c

    include$(BUILD_SHARED_LIBRARY)

    关于这几句话的含义,在这里不再赘述。网上搜下,就可以很明白。

    然后在jni目录下生成demo-jni.c文件。实现的接口的内容。

    现在选中工程中的jni目录,点击鼠标右键,选Refreshjni目录中的文件就显示在工程的jni目录下了。

    第二步:设置jni的编译环境。选中工程中的根目录JniDemo,点击鼠标右键,选Properties。弹出对话框,选中列表中的Builders。如图一所示:

    图一:JniDemo特性设置对话框

    点击对话框右端的new按钮,弹出“Choose configuration type”对话框,如图二,选择Program,点击对话框下面的OK按钮。

    图二:选择配置类型

    现在我们打开了”Edit Configuration”对话框,在Name对应的文本框中输入名字JniBuilder(当然也可是你喜欢的其他名字).Main选项下,Location中输入cygwin系统中bash.exe的绝对路径。我这里是c:cygwininash.exec:cygwin为我的系统中cygwin的安装目录,这里要根据你的电脑中cygwin的安装目录来确定),Working Directory中输入c:cygwinin.Arguments中输入--login -c "cd /cygdrive/d/study/JniDemo && /cygdrive/d/android-ndk-r6b/ndk-build"。这里/cygdrive/d/study/JniDemo为工程根目录, /cygdrive/d/android-ndk-r6bNDK的安装目录。这两个目录参数根据你的工程目录和ndk的安装目录而定。注意的是驱动器要采用cygwin的方式。(比如:Windows系统下的D:对应/cygdrive/d,其余类推)。设置结果如图三所示,然后点击 OK按钮即可。

    图三:编辑JNI配置参数

     

    二、演示四种调用方式

    演示界面如图四所示,四个按钮分别测试四种调用方式。

    图四:演示界面图

    分别点击按钮Test1, Test2, Tes3, Test四的测试结果如图五、六、七、八所示。

    图五:点击Test1的测试结果

    图六:点击Test2的测试结果

    图七:点击Test3的测试结果

     

    图八:点击Test4的测试结果

     

    Test1演示在应用中调用NDKC/C++实现的函数。JAVA代码和C代码分别为:

    JAVA 代码:

    [java] view plaincopy
    1. Button btn01 = (Button)findViewById(R.id.Button01);  
    2. btn01.setOnClickListener(new Button.OnClickListener()  
    3. {  
    4.     publicvoid onClick(View v)  
    5.     {        
    6.         TextView tv = (TextView)findViewById(R.id.tv01);  
    7.         tv.setText(stringFromJNI());              
    8.   
    9.         showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());  
    10.     }  
    11. });  

    C代码:

    1. Jstring Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )  
    2.   
    3. {  
    4.     return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");  
    5. }  


    l         Test2 静态调用。JAVA代码和C代码分别为:

    JAVA 代码:

    [java] view plaincopy
    1. // 测试C/C++中对JAVA函数的静态回调  
    2. Button btn02 = (Button)findViewById(R.id.Button02);  
    3. btn02.setOnClickListener(new Button.OnClickListener()  
    4. {  
    5.     publicvoid onClick(View v)  
    6.     {  
    7.         int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2","test static callback Message");  
    8.         TextView tv = (TextView)findViewById(R.id.tv01);  
    9.         if(ret == 0)  
    10.         {  
    11.            tv.setText("test JNI static callback successed");  
    12.         }  
    13.         else  
    14.         {  
    15.            tv.setText("test JNI static callback fialed");  
    16.         }  
    17.     }  
    18. });  


    C代码:

    1. Jint Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env,   
    1.                         jobject thiz,jobject ctx, jstring strTitle, jstring strMessage)  
    2. {  
    3.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
    4. //  jclass cls = (*env)->GetObjectClass(env, thiz);  
    5.     if(cls != NULL)  
    6.     {  
    7.        jmethodID id = (*env)->GetStaticMethodID(env, cls,"staticShowMessage",  
    8.             "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
    9.        if(id != NULL)  
    10.        {  
    11.       return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);  
    12.        }  
    13.     }  
    14.     return 1;  
    15. }  


    l         Test3 当前实例调用:JAVA代码和C代码分别为:

    JAVA 代码:

    [java] view plaincopy
    1. Button btn03 = (Button)findViewById(R.id.Button03);  
    2. btn03.setOnClickListener(new Button.OnClickListener()  
    3. {  
    4.     publicvoid onClick(View v)  
    5.     {  
    6.         strTest = " [message has changed now]";  
    7.         int ret = jniShowMessage(JniDemoActivity.this,"JNI test3","test callback in current instance");  
    8.         TextView tv = (TextView)findViewById(R.id.tv01);              
    9.   
    10.         if(ret == 0)  
    11.         {  
    12.            tv.setText("test JNI callback successed");                        
    13.         }  
    14.         else  
    15.         {  
    16.            tv.setText("test JNI callback fialed");  
    17.         }  
    18.     }  
    19. });  

    C代码:

    1. Jint Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,  
    2.        jobject ctx, jstring strTitle, jstring strMessage)  
    3.   
    4. {  
    5.     jclass cls = (*env)->GetObjectClass(env, thiz);  
    6.     if(cls != NULL)  
    7.     {  
    8.        jstring str;  
    9.        jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");  
    10.   
    11.        if(strTest_id != NULL)  
    12.   
    13.        {  
    14.           str = (*env)->CallObjectMethod(env, thiz, strTest_id);  
    15.        }   
    16.   
    17.        jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",  
    18.     "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");   
    19.   
    20.        if(showMessage_id != NULL)  
    21.        {  
    22.           return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,  
    23.                  strTitle, combine_jstring(env, strMessage, str));  
    24.        }  
    25.     }  
    26.     return 1;  
    27. }  


    l         Test4新建实例调用:JAVA代码和C代码分别为:

    JAVA 代码:

    [java] view plaincopy
    1. Button btn04 = (Button)findViewById(R.id.Button04);  
    2. btn04.setOnClickListener(newButton.OnClickListener()  
    3. {  
    4.     publicvoid onClick(View v)  
    5.     {  
    6.         strTest = " [message has changed now]";  
    7.         int ret = jniInstanceShowMessage(JniDemoActivity.this,  
    8. JNI test4","test callback in new instance");  
    9.         TextView tv = (TextView)findViewById(R.id.tv01);              
    10.   
    11.         if(ret == 0)  
    12.         {  
    13.            tv.setText("test JNI new instance successed");        
    14.         }  
    15.        else  
    16.         {  
    17.            tv.setText("test JNI new instance fialed");  
    18.         }  
    19.     }  
    20. });  


    C代码:

    1. jint Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,  
    2.        jobject ctx, jstring strTitle, jstring strMessage)  
    3. {  
    4.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
    5.     if(cls != NULL)  
    6.     {  
    7.        // get instance  
    8.        jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>""()V");  
    9.        if(constuctor_id != NULL)  
    10.        {  
    11.           jobject obj = (*env)->NewObject(env, cls, constuctor_id);  
    12.           if(obj != NULL)  
    13.           {  
    14.              jstring str;  
    15.              jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString","()Ljava/lang/String;");  
    16.              if(strTest_id != NULL)  
    17.              {  
    18.                  str = (*env)->CallObjectMethod(env, obj, strTest_id);  
    19.              }  
    20.              jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",  
    21.                     "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
    22.              if(showMessage_id != NULL)  
    23.              {  
    24.                  return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,strTitle, combine_jstring(env, strMessage, str));  
    25.              }  
    26.           }  
    27.        }  
    28.     }  
    29.     return 1;  
    30. }  


    Test1 Test2都是常规的调用,在这里不做解释了。现在我们看看Test3Test4的区别,在Test3中,strTest =" [message has changed now]" 在相应的代码中都做了赋值。但是在Test4中并没有改变,还是初始值。这是因为Test创建了一个新实例,和应用的JAVA代码中所赋值的实例并不是同一个。因此才出现了不同的结果。

     

    附完整的JAVAC代码

    JAVAD代码: JniDemoActivity.java

    [java] view plaincopy
    1. package study.jnidemo;   
    2.   
    3. import android.app.Activity;  
    4. import android.app.AlertDialog;  
    5. import android.os.Bundle;  
    6. import android.widget.Button;  
    7. import android.view.View;  
    8. import android.widget.TextView;  
    9. import android.content.Context;  
    10. import android.content.DialogInterface;   
    11.   
    12. publicclass JniDemoActivityextends Activity {      
    13.   
    14.     public StringstrTest =" [initial message]";             
    15.   
    16.     /** Called when the activity is first created. */  
    17.     @Override  
    18.     publicvoid onCreate(Bundle savedInstanceState) {  
    19.         super.onCreate(savedInstanceState);  
    20.         setContentView(R.layout.main);         
    21.   
    22.         findAndModifyButton();  
    23.     }  
    24.   
    25.     public String getTestString()  
    26.     {  
    27.         returnstrTest;  
    28.     }     
    29.   
    30.     // 测试JAVA的NDK调用  
    31.     publicnative String stringFromJNI();      
    32.   
    33.     // 测试C/C++中对JAVA函数的静态回调  
    34.     publicnativestaticint jniStaticShowMessage(Context ctx, String strTitle, String strMessage);      
    35.   
    36.     // 测试实例中C/C++中对JAVA类的函数的调用  
    37.     publicnativeint jniShowMessage(Context ctx, String strTitle, String strMessage);      
    38.   
    39.     // 测试创建新实例C/C++对JAVA类的函数的调用  
    40.     publicnativeint jniInstanceShowMessage(Context ctx, String strTitle, String strMessage);      
    41.   
    42.     static {  
    43.         System.loadLibrary("demo-jni");  
    44.     }      
    45.   
    46.     staticint staticShowMessage(Context ctx, String strTitle, String strMessage)  
    47.     {     
    48.         AlertDialog.Builder builder = new AlertDialog.Builder(ctx);     
    49.         builder.setTitle(strTitle);  
    50.         builder.setMessage(strMessage);  
    51.         builder.setPositiveButton("确定",  
    52.          new DialogInterface.OnClickListener(){  
    53.   
    54.                public void onClick(DialogInterface dialog,int whichButton){               
    55.   
    56.                }  
    57.         });  
    58.         builder.show();      
    59.         return 0;  
    60.   
    61.     }     
    62.   
    63.     publicint showMessage(Context ctx, String strTitle, String strMessage)  
    64.     {  
    65.         returnstaticShowMessage(ctx, strTitle, strMessage);  
    66.     }         
    67.   
    68.     privatevoid findAndModifyButton()  
    69.     {  
    70.         // 测试JAVA的NDK调用  
    71.         Button btn01 = (Button)findViewById(R.id.Button01);  
    72.         btn01.setOnClickListener(new Button.OnClickListener()  
    73.         {  
    74.                 publicvoid onClick(View v)  
    75.              {        
    76.                 TextView tv = (TextView)findViewById(R.id.tv01);  
    77.                 tv.setText(stringFromJNI());              
    78.   
    79.                 showMessage(JniDemoActivity.this,"JNI test1", stringFromJNI());  
    80.             }  
    81.         });  
    82.   
    83.       
    84.   
    85.         // 测试C/C++中对JAVA函数的静态回调  
    86.         Button btn02 = (Button)findViewById(R.id.Button02);  
    87.         btn02.setOnClickListener(new Button.OnClickListener()  
    88.         {  
    89.   
    90.                 publicvoid onClick(View v)  
    91.              {  
    92.                 int ret =jniStaticShowMessage(JniDemoActivity.this,"JNI test2""test static callback Message");  
    93.                 TextView tv = (TextView)findViewById(R.id.tv01);  
    94.   
    95.                   if(ret == 0)  
    96.                 {  
    97.                     tv.setText("test JNI static callback successed");                        
    98.                 }  
    99.                 else  
    100.                 {  
    101.   
    102.                     tv.setText("test JNI static callback fialed");  
    103.                 }  
    104.                 }  
    105.   
    106.     });  
    107.    
    108.   
    109.     // 测试实例中C/C++中对JAVA类的函数的调用  
    110.     Button btn03 = (Button)findViewById(R.id.Button03);  
    111.     btn03.setOnClickListener(new Button.OnClickListener()  
    112.     {  
    113.         publicvoid onClick(View v)  
    114.         {  
    115.             strTest = " [message has changed now]";  
    116.             int ret = jniShowMessage(JniDemoActivity.this,"JNI test3""test callback in current instance");  
    117.             TextView tv = (TextView)findViewById(R.id.tv01);              
    118.   
    119.            if(ret == 0)  
    120.             {  
    121.                tv.setText("test JNI callback successed");                        
    122.             }  
    123.             else  
    124.             {  
    125.                tv.setText("test JNI callback fialed");  
    126.             }  
    127.         }  
    128.     });  
    129.   
    130.       
    131.     // 测试创建新实例C/C++对JAVA类的函数的调用  
    132.     Button btn04 = (Button)findViewById(R.id.Button04);  
    133.     btn04.setOnClickListener(new Button.OnClickListener()  
    134.     {  
    135.         publicvoid onClick(View v)  
    136.         {  
    137.             strTest = " [message has changed now]";  
    138.             int ret = jniInstanceShowMessage(JniDemoActivity.this,"JNI test4""test callback in new instance");  
    139.             TextView tv = (TextView)findViewById(R.id.tv01);              
    140.   
    141.             if(ret == 0)  
    142.             {  
    143.                tv.setText("test JNI new instance successed");                           
    144.             }  
    145.             else  
    146.             {  
    147.                tv.setText("test JNI new instance fialed");  
    148.             }  
    149.         }  
    150.     });  
    151.     }    
    152.   
    153. }  


     

    C代码 demo-jni.cpp

    1. #include<string.h>  
    2. #include<jni.h>  
    3.   
    4. // 加载此动态库时系统自动首先加载  
    5. jint JNI_OnLoad(JavaVM* vm, void *reserved)  
    6. {  
    7.     JNIEnv *env;  
    8.     if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)  
    9.     {  
    10.        return -1;  
    11.     }  
    12.     return JNI_VERSION_1_4;  
    13. }   
    14.   
    15. jstring  
    16. Java_study_jnidemo_JniDemoActivity_stringFromJNI( JNIEnv* env,jobject thiz )  
    17. {  
    18.     return (*env)->NewStringUTF(env,"JniDemo, Hello from JNI!");  
    19. }  
    20.   
    21. jstring  
    22. combine_jstring(JNIEnv* env, jstring str1, jstring str2)  
    23. {  
    24.     jboolean b_ret;  
    25.     constchar *s1 = (*env)->GetStringUTFChars(env, str1, &b_ret);  
    26.     constchar *s2 = (*env)->GetStringUTFChars(env, str2, &b_ret);  
    27.     int n1 = strlen(s1);  
    28.     int n2 = strlen(s2);  
    29.     char *new_str = (char *)malloc(n1+n2+1);  
    30.     memset(new_str, 0, n1+n2+1);  
    31.     strcat(new_str, s1);  
    32.     strcat(new_str, s2);  
    33.     jstring ret_str = (*env)->NewStringUTF(env,(constchar *)new_str);  
    34.     free(new_str);  
    35.   
    36.     return ret_str;  
    37. }  
    38.   
    39. jint  
    40. Java_study_jnidemo_JniDemoActivity_jniStaticShowMessage(JNIEnv* env, jobject thiz,  
    41.        jobject ctx, jstring strTitle, jstring strMessage)  
    42. {  
    43.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
    44. //  jclass cls = (*env)->GetObjectClass(env, thiz);  
    45.     if(cls != NULL)  
    46.     {  
    47.        jmethodID id = (*env)->GetStaticMethodID(env, cls,  
    48.              "staticShowMessage",  
    49.              "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
    50.        if(id != NULL)  
    51.        {  
    52.           return (*env)->CallStaticIntMethod(env, cls, id, ctx, strTitle, strMessage);  
    53.        }  
    54.     }  
    55.     return 1;  
    56. }  
    57.   
    58. // 在当前已有的JAVA实例中调用  
    59. jint  
    60. Java_study_jnidemo_JniDemoActivity_jniShowMessage(JNIEnv* env, jobject thiz,  
    61.        jobject ctx, jstring strTitle, jstring strMessage)  
    62. {  
    63.     jclass cls = (*env)->GetObjectClass(env, thiz);  
    64.     if(cls != NULL)  
    65.     {  
    66.        jstring str;  
    67.        jmethodID strTest_id = (*env)->GetMethodID(env, cls, "getTestString",  
    68.              "()Ljava/lang/String;");  
    69.        if(strTest_id != NULL)  
    70.        {  
    71.           str = (*env)->CallObjectMethod(env, thiz, strTest_id);  
    72.        }  
    73.   
    74.         jmethodID showMessage_id = (*env)->GetMethodID(env, cls, "showMessage",  
    75.              "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
    76.   
    77.        if(showMessage_id != NULL)  
    78.        {  
    79.           return (*env)->CallIntMethod(env, thiz, showMessage_id, ctx,  
    80.                  strTitle, combine_jstring(env, strMessage, str));  
    81.        }  
    82.     }  
    83.     return 1;  
    84. }  
    85.   
    86. // 在新建JAVA实例中调用  
    87. jint  
    88. Java_study_jnidemo_JniDemoActivity_jniInstanceShowMessage(JNIEnv* env, jobject thiz,  
    89.        jobject ctx, jstring strTitle, jstring strMessage)  
    90. {  
    91.     jclass cls = (*env)->FindClass(env, "study/jnidemo/JniDemoActivity");  
    92.     if(cls != NULL)  
    93.     {  
    94.        // get instance  
    95.        jmethodID constuctor_id = (*env)->GetMethodID(env, cls, "<init>""()V");  
    96.        if(constuctor_id != NULL)  
    97.        {  
    98.           jobject obj = (*env)->NewObject(env, cls, constuctor_id);  
    99.           if(obj != NULL)  
    100.           {  
    101.              jstring str;  
    102.              jmethodID strTest_id = (*env)->GetMethodID(env, cls,"getTestString",  
    103.                     "()Ljava/lang/String;");   
    104.   
    105.              if(strTest_id != NULL)  
    106.              {  
    107.                  str = (*env)->CallObjectMethod(env, obj, strTest_id);  
    108.              }   
    109.   
    110.              jmethodID showMessage_id = (*env)->GetMethodID(env, cls,"showMessage",  
    111.                     "(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I");  
    112.              if(showMessage_id != NULL)  
    113.              {  
    114.                  return (*env)->CallIntMethod(env, obj, showMessage_id, ctx,  
    115.                         strTitle, combine_jstring(env, strMessage, str));  
    116.              }  
    117.           }  
    118.        }  
    119.     }  
    120.     return 1;  
    121. }  


     

    源代码下载地址:http://download.csdn.net/detail/seniorwizard/4394466

  • 相关阅读:
    [Python] Python 学习
    [其它] 学习杂记
    [.NET] 《Effective C#》快速笔记(三)- 使用 C# 表达设计
    [.NET] 《Effective C#》快速笔记(二)- .NET 资源托管
    [python] 小游戏
    [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯
    [angularjs] AngularJs 知识回顾
    [C#] 使用 StackExchange.Redis 封装属于自己的 RedisHelper
    [.NET] 一步步打造一个简单的 MVC 电商网站
    [.NET] 一步步打造一个简单的 MVC 电商网站
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318692.html
Copyright © 2020-2023  润新知