zoukankan      html  css  js  c++  java
  • 【转】Android 源码下利用jni编译自己的项目(参考系统development/samples/SimpleJNI)

    原文网址:http://blog.csdn.net/qiuxiaolong007/article/details/7860481

    记于正文前:环境是ubuntu10.10,android 源码是2.0的,在第一次编译源码的时候遇到不少问题,第二次一次make通过。

                   1)可能用到的文件或库全部安装(sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev);

                   2)建议用jdk1.5编译android源码,1.6也是可以编译通过的,不过需要修改一个文件(这里以2.0为例,要修改文件/build/core/main.mk,将文件中的javac_version := $(shell javac -version 2>&1 | head -n 1 | grep '[ "]1.5[. "

    ]') 全部改为javac_version := $(shell javac -version
     2>&1 | head -n 1 | grep '[ "]1.6[. "

    ]'),总共两处)

                 Android 源码下利用jni编译自己的项目

                  我的练习项目实现了一个简单的四则运算,项目的目录层次如下:

                  AndroidManifest.xml  Android.mk  jni  res   src

                       资源文件简简单单,一个布局文件,稍后会有demo的下载地址

                        主要记录备忘的内容如下:

                         MainActivity.java

    [html] view plaincopy
     
    1. public native int add(int x, int y);  
    2. public native int substraction(int x, int y);  
    3. public native float multiplication(int x, int y);  
    4. public native float division(int x, int y);  
    5.   
    6. static{  
    7.     System.loadLibrary("arithmetic");  
    8. }  


                生成lib的名称为libarithmetic.so.注意load的时候写"arithmetic"

             jni 目录下有两个文件,一个是Android.mk,一个是c++源文件long.cpp

             jni/Android.mk如下:

    [html] view plaincopy
     
    1. LOCAL_PATH:= $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3.   
    4. LOCAL_MODULE_TAGS := optional  
    5.   
    6. LOCAL_MODULE:= libarithmetic  
    7.   
    8. LOCAL_SRC_FILES:=   
    9.   long.cpp  
    10.   
    11. LOCAL_SHARED_LIBRARIES :=   
    12.     libutils  
    13.   
    14. LOCAL_STATIC_LIBRARIES :=  
    15.   
    16. LOCAL_C_INCLUDES +=   
    17.     $(JNI_H_INCLUDE)  
    18.   
    19. LOCAL_CFLAGS +=  
    20.   
    21. LOCAL_PRELINK_MODULE := false  
    22.   
    23. include $(BUILD_SHARED_LIBRARY)  


    注释:

    LOCAL_PATH(必须定义,而且要第一个定义),宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录);

    include $( CLEAR_VARS),
    CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的;

    LOCAL_MODULE_TAGS :=user eng tests optional

    user: 指该模块只在user版本下才编译

    eng: 指该模块只在eng版本下才编译

    tests: 指该模块只在tests版本下才编译

    optional:指该模块在所有版本下都编译

    LOCAL_MODULE(必须定义),标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。Note:编译系统会自动产生合适的前缀和后缀,例如:arithmetic编译成功后将生成libarithmetic.so库文件

    LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中源代码文件。不用在这里列出头文件和包含文件。

    LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称

      LOCAL_STATIC_LIBRARIES加入所需要链接的静态库(*.a)的名称

    LOCAL_CFLAG可选的编译器选项,用法之一是定义宏,例如LOCAL_CFLAGS    := -Werror作用是编译警告也作为错误信息

    LOCAL_PRELINK_MODULE:=false,不作prelink处理,默认是要prelink操作的,有可能造成地址空间冲突(这地方目前还不明白)              long.cpp源代码如下:

    [html] view plaincopy
     
    1. #define LOG_TAG "LongTest2 long.cpp"  
    2. #include <utils/Log.h>  
    3. #include <stdio.h>  
    4. #include "jni.h"  
    5.   
    6. jint add(JNIEnv *env, jobject thiz, jint x, jint y){  
    7.     return x + y;  
    8. }  
    9.   
    10. jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){  
    11.   
    12.     return x - y;  
    13. }  
    14.   
    15. jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){  
    16.   
    17.     return (float)x * (float)y;  
    18. }  
    19.   
    20. jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){  
    21.     return (float)x/(float)y;  
    22. }  
    23.   
    24. static const char *classPathName = "com/inspur/test2/MainActivity";  
    25.   
    26. static JNINativeMethod methods[]= {  
    27.       
    28.     {"add", "(II)I", (void*)add},  
    29.     {"substraction", "(II)I", (void*)substraction},  
    30.     {"multiplication", "(II)F", (void*)multiplication},  
    31.     {"division", "(II)F", (void*)division},  
    32. };  
    33.   
    34.   
    35. typedef union{  
    36.     JNIEnv* env;  
    37.     void* venv;  
    38. }UnionJNIEnvToVoid;  
    39.   
    40.   
    41.   
    42. static int registerNativeMethods(JNIEnv* env, const char* className,  
    43.     JNINativeMethod* gMethods, int numMethods){  
    44.   
    45.     jclass clazz;  
    46.     clazz = env->FindClass(className);  
    47.   
    48.     if (clazz == NULL)  
    49.         return JNI_FALSE;  
    50.     if (env->RegisterNatives(clazz, gMethods, numMethods)<0)  
    51.         return JNI_FALSE;  
    52.     return JNI_TRUE;  
    53.   
    54. }  
    55.   
    56.   
    57. static int registerNatives(JNIEnv *env){  
    58.   
    59.     if (!registerNativeMethods(env, classPathName,  
    60.         methods, sizeof(methods)/sizeof(methods[0])))  
    61.     {  
    62.         return JNI_FALSE;  
    63.     }  
    64.   
    65.     return JNI_TRUE;  
    66.   
    67. }  
    68.   
    69.   
    70.   
    71. jint JNI_OnLoad(JavaVM* vm, void* reserved){  
    72.   
    73.     UnionJNIEnvToVoid uenv;  
    74.     uenv.venv = NULL;  
    75.     jint result = -1;  
    76.     JNIEnv *env = NULL;  
    77.   
    78.     if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){  
    79.         goto bail;  
    80.     }  
    81.       
    82.     env = uenv.env;  
    83.   
    84.     env = uenv.env;  
    85.   
    86.     if (registerNatives(env) != JNI_TRUE){  
    87.   
    88.         goto bail;  
    89.     }  
    90.   
    91.     result = JNI_VERSION_1_4;  
    92.   
    93. bail:  
    94.     return result;  
    95. }  

    除了利用     编写native   JAVA类,通过javah生成.h文件,根据.h文件编写.c/cpp文件 方法外(名字像老太太的裹脚步,又臭又长,而且不灵活),Android还可以通过引用JNI_Onload方式实现。jint JNI_onLoad(JavaVM* vm, void* reverced),改方法在so文件被加载时调用。

    JNI_OnLoad()有两个重要的作用:

      指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。

      初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

      JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。

    更多更详细内容请参考使用RegisterNatives方法传递和使用Java自定义类 

    项目根目录下Android.mk文件:

    [html] view plaincopy
     
    1. LOCAL_PATH:= $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3.   
    4. LOCAL_MODULE_TAGS := optional   
    5.   
    6. LOCAL_SRC_FILES := $(call all-java-files-under, src)  
    7.   
    8.   
    9. LOCAL_JNI_SHARED_LIBRARIES := libarithmetic  
    10.   
    11.   
    12. LOCAL_PACKAGE_NAME := LongTest  
    13.   
    14. LOCAL_SHARED_LIBRARIES :=   
    15.         libutils  
    16.         liblog  
    17.   
    18. include $(BUILD_PACKAGE)  
    19. include $(LOCAL_PATH)/jni/Android.mk   
    20.   
    21. # Also build all of the sub-targets under this one: the shared library.  
    22. include $(call all-makefiles-under,$(LOCAL_PATH))  


    LOCAL_PACKAGE_NAME:项目名称,即最终生成apk的名字

    LOCAL_JNI_SHARED_LIBRARIES := libxxx就是把so文件放到apk文件里的libs/armeabi里

    执行BUILD_PACKAGE。它的定义也是在config.mk中定义如下:BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

    $(call all-java-files-under, src)编译的源代码文件列表添加src目录下所有的java 源文件

    $(call all-makefiles-under, $(LOCAL_PATH))编译器会在编译完当前目录下的文件后再深入子目录编译

    如果make过android源码,可以在项目根目录下执行mm命令进行编译。前提是执行过source androidSRC/build/envsetup.sh

    或者直接把source androidSRC/build/envsetup.sh添加到~/.bashrc中,会更加方便

    示例代码下载

  • 相关阅读:
    Ubuntu执行命令时,不sudo提示权限不足,sudo提示找不到该命令
    ubuntu中执行可执行文件时报错“没有那个文件或目录”的解决办法(非权限问题)
    不同编译器下,定义一个地址按x字节对齐的数组
    对冒泡排序法的个人理解
    通过py2exe打包python程序的过程中,解决的一系列问题
    IAR工程名修改
    stm8编程tips(stvd)
    获取单片机唯一id(stm32获取单片机唯一id)
    按键抖动的处理方法(按键外部中断)
    stm32--USB(作为U盘)+FatFs的实现
  • 原文地址:https://www.cnblogs.com/wi100sh/p/4616171.html
Copyright © 2011-2022 走看看