• android NDK开发及调用标准linux动态库.so文件


    预备知识及环境搭建

    1、NDK(native development Kit)原生开发工具包,用来快速开发C、C++动态库,并能自动将so文件和java应用一起打包成apk.对应:jni层c++开发

    2、Cygwin:是windows平台上模拟Linux运行环境的工具,即window平台上的linux环境工具,so文件需要在linux平台上编译运行。对应:arm linux平台

    3、CDT:eclipse下的C/C++开发工具,需要在eclipse下安装这个插件。对应:标准C++开发。应该可以通过这个工具开发、编译arm平台的C++程序

    4、Sequoyah:Sequoyah插件用于设置Android工程对Native开发的支持,make文件生成工具,帮助我们自动生成mk文件,需要在eclipse下安装这个插件。对应:make文件生成

    开发调用流程

    一、新建一个android项目,此处命名为WsJniPlayer.

    二、NDK本地支持

    1、添加NDK本地支持:在新建项目上,右键-》Android Tools->Add Native Support,弹出对话框

    按默认设置即可,点击Finish按钮后,在项目目录中,多了一个名为jni的目录,这个目录便是Sequoyah自动生成的用于存放C/C++源代码的目录

    jni目录中有两个文件Android.mk和cpp文件WsJniPlayer.cpp

    2、mk文件说明

     菜鸟级别解释::=是赋值的意思,$是引用某变量的值,include是执行动作。GNU:(GNU's Not Unix),GNU计划,为保证GNU软件可以自由地“使用、复制、修改和发布”,GNU通用公共许可证(GNU General Public License,GPL)。即“反版权”(或称Copyleft)概念。

    一个Android.mk file用来向编译系统描述你的源代码。具体来说:-该文件是GNU Makefile的一小部分。这个文件的语法允许把你的源代码组织成模块:静态库.a和共享库.so。你可以在每一个Android.mk file中定义一个或多个模块。下面是常用语句的解释:

    *LOCAL_PATH:= $(call my-dir):首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。宏函数’my-dir,由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。

    *include $( CLEAR_VARS):CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量,除LOCAL_PATH

    *LOCAL_MODULE := helloworld:LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。重要注意事项:如果你把库命名为‘libhelloworld’,编译系统将不会添加任何的lib前缀,也会生成libhelloworld.so,这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。

    *LOCAL_SRC_FILES := helloworld.c:变量必须包含将要编译打包进模块中的CC++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好.

    *include $(BUILD_SHARED_LIBRARY):BUILD_SHARED_LIBRARY是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。并根据其规则生成共享库

     make文件变量:GNU Make变量:在你的Android.mk文件解析之前,就由编译系统定义好了;自己定义的变量:为了方便在Android.mk中定义自己的变量,我们建议使用MY_前缀

    Android.mk使用模板

    在一个Android.mk中可以生成多个可执行程序、动态库和静态库。

    编译应用程序

    1. #Test Exe  
    2.   
    3.     LOCAL_PATH := $(call my-dir)  
    4.     include $(CLEAR_VARS)  
    5.     LOCAL_SRC_FILES:= main.c  
    6.     LOCAL_MODULE:= test_exe  
    7.     #LOCAL_C_INCLUDES :=        //加入所需要包含的头文件路径  
    8.     #LOCAL_STATIC_LIBRARIES :=  //加入所需要链接的静态库(*.a)的名称,库在系统的lib目录下  
    9.     #LOCAL_SHARED_LIBRARIES :=  //加入所需要链接的动态库(*.so)的名称  
    10.     include $(BUILD_EXECUTABLE) //表示以一个可执行程序的方式进行编译  

     编译静态库的模板:

    1. LOCAL_PATH := $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3. LOCAL_SRC_FILES:= main.c  
    4. LOCAL_MODULE:= test_exe  
    5. #LOCAL_C_INCLUDES :=        //加入所需要包含的头文件路径  
    6. #LOCAL_STATIC_LIBRARIES :=  //加入所需要链接的静态库(*.a)的名称,库在系统的lib目录下  
    7. #LOCAL_SHARED_LIBRARIES :=  //加入所需要链接的动态库(*.so)的名称  
    8. include $(BUILD_STATIC_LIBRARY) //表示以静态库的方式进行编译  
    1. <span style="color:#993300;">包含的头文件路径特别说明:</span>  
    1. LOCAL_C_INCLUDES:=android/ftplib  
    2. LOCAL_C_INCLUDES+=android   
    3. LOCAL_C_INCLUDES+=android/adapi  
    1. android、android/ftplib、android/ftplib:其中的android是在工程根目录下的文件夹  

    编译动态库模版:

    1. LOCAL_PATH := $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3. LOCAL_MODULE:= helloworld  
    4. LOCAL_SRC_FILES := helloworld.c  
    5. include $(BUILD_SHARED_LIBRARY)  

    编译两个动态库模块:

    1. LOCAL_PATH := $(call my-dir)  
    2.   
    3. include $(CLEAR_VARS)    
    4. #清除一些变量    
    5. LOCAL_MODULE := test    
    6. #要生成的库名    
    7. LOCAL_SRC_FILES := testso.cpp   
    8. #库对应的源文件    
    9. include $(BUILD_SHARED_LIBRARY)    
    10.   
    11. include $(CLEAR_VARS)    
    12. #清除一些变量    
    13. LOCAL_MODULE := WsJniPlayer    
    14. #定义另外一个库的名    
    15. LOCAL_SRC_FILES := WsJniPlayer.cpp    
    16. #定义库对应的源文件    
    17. LOCAL_LDLIBS := -ldl -llog    
    18. #编译你的模块要使用的附加的链接器选项  
    19. include $(BUILD_SHARED_LIBRARY)  

    编译两个动态库,其中一个是第三方库:

    1. LOCAL_PATH := $(call my-dir)  
    2. include $(CLEAR_VARS)       
    3. LOCAL_MODULE := libtest      
    4. LOCAL_SRC_FILES := libtest.so       
    5. include $(PREBUILT_SHARED_LIBRARY)    
    6.   
    7. include $(CLEAR_VARS)    
    8. #清除一些变量     
    9. LOCAL_SRC_FILES := WsJniTest.cpp    
    10. #定义库对应的源文件    
    11. LOCAL_MODULE := WsJniTest    
    12. #定义另外一个库的名   
    13. LOCAL_LDLIBS := -ldl -llog//运行时需要动态加载库     
    14. include $(BUILD_SHARED_LIBRARY)    

    隐式调用第三方库

    [java] view plaincopy
    1. LOCAL_PATH := $(call my-dir)  
    2. include $(CLEAR_VARS)    
    3. LOCAL_SRC_FILES := test.cpp   
    4. LOCAL_PRELINK_MODULE := false  
    5. LOCAL_MODULE := libtest   
    6. LOCAL_MODULE_TAGS := optional  
    7. include $(BUILD_SHARED_LIBRARY)    
    8.   
    9. include $(CLEAR_VARS)    
    10. LOCAL_SRC_FILES := WsJniPlayer.cpp  
    11. LOCAL_CFLAGS := -ltest  
    12. LOCAL_LDFLAGS := -L$(LOCAL_PATH)//要隐式调用库的位置  
    13. LOCAL_SHARED_LIBRARIES :=libtest//要隐式调用库的名称  
    14.   
    15. LOCAL_MODULE := WsJniPlayer    
    16. LOCAL_MODULE_TAGS := optional  
    17.   
    18. include $(BUILD_SHARED_LIBRARY)   

    LOCAL_SHARED_LIBRARIES和LOCAL_LDLIBS区别:

    LOCAL_LDLIBS:链接的库不产生依赖关系,一般用于不需要重新编译的库,如库不存在,则会报错找不到。且貌似只能链接那些存在于系统目录下本模块需要连接的库。

    LOCAL_SHARED_LIBRARIES :会生成依赖关系,当库不存在时会去编译这个库。例如:开发中出现过这种情况,会编译出一个错误的库

    3、cpp文件说明

    自动生成的cpp文件是C++源代码文件,这个默认的文件是空的,只包含两include语句:#include <string>和#include <jni.h>

    jni.h文件,定义了本地的数据类型,本地数据类型对应java类型前加上一个j,如int--->jint、jstring-->java.lang.String。本地数据类型是介于java类型和C++类型的中间类型,jni就是java和C++调用的桥。

    特别需要注意的JNI调用的两点规则:

    a、java程序只能调用C语言接口,因此接口前要加上:extern "C"关键字。这是因为NDK主要是配合C语言开发,但是Sequoyah插件帮我们生成的是cpp文件。在默认情况下,会使用C++的编译方式来进行编译,这样导致java调用时无法找到对应的接口函数。C和C++编译时,可能函数名不一样,也即:JAVA调用C编译类型的函数名。

    b、函数定义规则:在编写函数时,函数名必须符合规则,不然JNI调用时无法找到需要的函数。

    4、添加依赖包

    代码编写后,可能发现报错,提示找不到于与JNI相关的一些定义,这就需要添加NDK依赖包:项目右键-》properties->C/C++Gerneral->paths and symbols->includes->GNU C->add->file system,添加<ndk根目录>platformsandroid-8arch-armusrinclude,添加完成后,重新build项目,即可解决。

    注意:NDK的android-8版本同项目开发android版本对应关系:如android4.1<->android-14、android2.2<->android-8等,版本对应不上仍可能编译不过。

    三、编译设置:

    1、bash设置,即Cygwin设置:bash是一个为GNU计划编写的Unix shell,由于以bash命令运ndk-build等效于在Unix环境下运行ndk-build,所以要在windows环境变量path里加入bash所在目录,即cygwinin.

    2、ndk-build设置:项目右键-》properties->C/C++Build,在Builder Settings选项卡中,取消Use default build command选项,并在Build Command 中填入:bash <ndk> dk-build,其中<ndk>为安装的NDK的根目录。

  • 相关阅读:
    PowerShell2.0之与COM对象交互(二)Word自动化
    PowerShell2.0之与COM对象交互(三)Excel自动化
    PowerShell 2.0之使用WMI管理Windows(一)WMI基础
    PowerShell2.0之与COM对象交互(五)与脚本宿主代码协同工作
    PowerShell2.0之与COM对象交互(四)IE自动化
    PowerShell2.0之与COM对象交互(一)COM基础
    php中一些常用的语句收集
    NET第三方控件AspNetPager设置样式
    JAVAMyEclipse 自动提示(按alt+/)时假死现像
    NET数据访问基础类(基于OleDb)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318689.html
Copyright © 2020-2023  润新知