Android JNI编程实例

     在Android编程过程中,有时会出于程序效率或代码复用的考虑,使用到JNI编程,即用Java调用C/C++的内容,本文将纪录一个简单的JNI调用实例,用以备忘。

     1.新建一Android工程,命名HelloJNI,目录如下图

      

         建立JNI调用的类Hello.java,如下

        

[java]  view plain copy
  1.   
[java]  view plain copy
  1. package com.hellojni;  
  2.   
  3. public class Hello {  
  4.       
  5.     static {  
  6.         try{  
  7.         System.loadLibrary("hellojni");  
  8.         }catch(UnsatisfiedLinkError e){  
  9.             System.err.println( "Cannot load hello library:\n " +  
  10.                     e.toString() );  
  11.         }  
  12.     }  
  13.       
  14.     public Hello(){  
  15.           
  16.     }  
  17.       
  18.     public native void SayHello(String strName);  
  19.   
  20. }  

         主要用上上述代码中的native本地方法调用。

        2.Java和C的链接主要是使用命名空间的一致性,为了保证命名不会出现错误,我们采取直接编译java文件的形式直接生成C的头文件,方法如下:

           1)将Hello.java编译成Hello.class

[plain]  view plain copy
  1. simmatoMacBook-Pro:~ me$ javac Documents/workspace/HelloJNI/src/com/hellojni/Hello.java   
           2) 此时将com.hellojni包copy到bin目录(指android工程的bin目录)下,进入bin目录执行:            

[plain]  view plain copy
  1. simmatoMacBook-Pro:~ me$ javah -classpath . -jni com.hellojni.Hello  
                此时会在bin下生成com_hellojni_Hello.h,即我们想要的h头文件,如下:

[cpp]  view plain copy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. #include"common.h"  
  4. /* Header for class com_hellojni_Hello */  
  5.   
  6. #ifndef _Included_com_hellojni_Hello  
  7. #define _Included_com_hellojni_Hello  
  8. #ifdef __cplusplus  
  9. extern "C" {  
  10. #endif  
  11. /* 
  12.  * Class:     com_hellojni_Hello 
  13.  * Method:    SayHello 
  14.  * Signature: (Ljava/lang/String;)V 
  15.  */  
  16. JNIEXPORT void JNICALL Java_com_hellojni_Hello_SayHello  
  17.   (JNIEnv *, jobject, jstring);  
  18.   
  19. #ifdef __cplusplus  
  20. }  
  21. #endif  
  22. #endif  



         3.实现JNI部分

           1)在android工程中新建jni目录,将com_hellojni_Hello.h拷入其中,并实现,如下实现com_hellojni_Hello.cpp       

[cpp]  view plain copy
  1. #include "com_hellojni_Hello.h"  
  2. #include  <stdlib.h>  
  3.   
  4. JNIEXPORT void JNICALL Java_com_hellojni_Hello_SayHello  
  5.   (JNIEnv * env, jobject obj, jstring msg){  
  6.   
  7.      LOGI("JNI - hello:\n");  
  8.   
  9.      if (msg == NULL) {  
  10.                       //该方法为打印的方法  
  11.                       LOGI( "Your params is null");  
  12.                      }  
  13.   
  14.      char* rtn = NULL;  
  15.          jclass clsstring = env->FindClass("java/lang/String");  
  16.          jstring strencode = env->NewStringUTF("utf-8");  
  17.          jmethodID mid = env->GetMethodID(clsstring, "getBytes""(Ljava/lang/String;)[B");  
  18.          jbyteArray barr = (jbyteArray)env->CallObjectMethod(msg, mid, strencode);  
  19.          jsize alen = env->GetArrayLength(barr);  
  20.          jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  
  21.          if (alen > 0)  
  22.          {  
  23.              rtn = (char*)malloc(alen + 1);  
  24.              memcpy(rtn, ba, alen);  
  25.              rtn[alen] = 0;  
  26.          }  
  27.          env->ReleaseByteArrayElements(barr, ba, 0);  
  28.                //该方法为打印的方法  
  29.                LOGI("Get Param:  %s  From Java", rtn);  
  30.   
  31. }  


               补充一个头文件:common.h

[cpp]  view plain copy
  1. #ifndef COMMON_HEADER  
  2. #define COMMON_HEADER  
  3.   
  4. //enable re-enter code  
  5. #define _REENTRANT  
  6.   
  7. #include <sys/types.h>  
  8. #include <sys/socket.h>  
  9. #include <sys/un.h>  
  10. #include <stdio.h>  
  11. #include <stdlib.h>  
  12. #include <unistd.h>  
  13. #include <netinet/in.h>  
  14. #include <arpa/inet.h>  
  15. #include <netinet/tcp.h>  
  16. #include <fcntl.h>  
  17. #include <time.h>  
  18. #include <fstream>  
  19. #include <pthread.h>  
  20. #include <string.h>  
  21. #include <memory>  
  22. #include <string>  
  23. #include <errno.h>  
  24. #include <semaphore.h>  
  25.   
  26. // for android debug  
  27. #include <android/log.h>  
  28.   
  29. #define debug  
  30.   
  31. #ifdef debug  
  32. #define  LOG_TAG    "hello_jni"  
  33. #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG,__VA_ARGS__)  
  34. #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,__VA_ARGS__)  
  35. #define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN, LOG_TAG,__VA_ARGS__)  
  36. #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  37. #else  
  38. #define  LOG_TAG   
  39. #define  LOGI(...)   
  40. #define  LOGD(...)   
  41. #define  LOGW(...)   
  42. #define  LOGE(...)   
  43. #endif  //debug  
  44.   
  45.   
  46. typedef void (*Notify)(int);  
  47.   
  48. using namespace std;  
  49.   
  50. #define SINGLETON(CLASS) \  
  51. friend class auto_ptr<CLASS>; \  
  52. public: \  
  53.     static CLASS*  GetInstance(){ \  
  54.         if (_mInstance.get() == NULL){ \  
  55.             _mInstance.reset(new CLASS()); \  
  56.         } \  
  57.         return _mInstance.get(); \  
  58.     } \  
  59. private: \  
  60.     CLASS(); \  
  61.     static auto_ptr<CLASS> _mInstance; \  
  62. public: \  
  63.     virtual ~CLASS();  
  64.   
  65. #define INITINSTANCE(CLASS) \  
  66. auto_ptr<CLASS> CLASS::_mInstance(NULL);  
  67.   
  68. #endif //COMMON_HEADER  


        2)编写Android.mk和Application.mk

            Android.mk是一个makefile,用来告诉NDK需要编译哪些文件,生成哪些模块。我们创建<jni>/Android.mk文件: 

[python]  view plain copy
  1. # =============================  
  2. # lib hello  
  3. # =============================  
  4.   
  5. LOCAL_PATH := $(call my-dir)  
  6.   
  7. include $(CLEAR_VARS)  
  8.   
  9. LOCAL_MODULE := hellojni  
  10.   
  11. LOCAL_C_INCLUDES := $(LOCAL_PATH)/  
  12.   
  13. LOCAL_SRC_FILES :=  \  
  14.     com_hellojni_Hello.cpp \  
  15.       
  16. #LOCAL_CFLAGS += -DENABLE_TRACE  
  17. #LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)  
  18.   
  19. LOCAL_LDLIBS := -llog -lm -ldl  
  20.   
  21. include $(BUILD_SHARED_LIBRARY)  

         其中LOCAL_PATH表示c源代码文件的位置;LOCAL_MODULE表示生成的共享库的名称;LOCAL_SRC_FILES代表c代码的文件。不需要把头文件列在里面;头文件的依赖关系是ndk自动计算的。 
         Application.mk的作用是告诉Android SDK需要哪些库文件。有了它,NDK就可以把库放在正确的位置。我们创建<project>/Application.mk: 

[python]  view plain copy
  1. APP_STL := stlport_static  
  2. STLPORT_FORCE_REBUILD := true  
  3. APP_MODULES := hellojni  
          APP_PROJECT_PATH代表android工程所在目录,在本例中它被放在<project>中; APP_MODULES表示工程需要的库,如果有多个以空格分开。

       4.编译hellojni.so

          使用eclipse工具runConfigurations,如下:


       其中,Location选ndk-build, Working Directory选为本android工程目录下的jni目录,然后“Apply”-》“Run”。

       即可在本工程的Libs/armeabi下生成libhellojni.so,取出使用即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值