java jni开发_JNI开发

本文详细介绍了Java JNI开发中的关键概念,包括JNIEnv的线程相关性和作用,以及JavaVM的区别。同时,阐述了Application.mk文件中各个变量的作用,如APP_PROJECT_PATH、APP_MODULES等,解释了其在Android应用编译过程中的重要性。此外,还讲解了Android.mk文件的用途,包括模块类型定义、编译选项设置和头文件路径等。通过对这两个文件的深入理解,开发者能够更好地掌握JNI开发和Android应用的编译配置。
摘要由CSDN通过智能技术生成

一、JNIEnv与JavaVM

1.  JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ;

2.  JNIEnv 与 JavaVM :

JavaVM : JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个;

JNIEnv : JavaVM 在线程中的代表, 每个线程都有一个, JNI 中可能有很多个 JNIEnv;

3.  JNIEnv 作用 :

调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码;

操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象;

4.  JNIEnv 体系结构

线程相关 : JNIEnv 是线程相关的, 即 在 每个线程中 都有一个 JNIEnv 指针, 每个JNIEnv 都是线程专有的, 其它线程不

能使用本线程中的 JNIEnv, 线程 A 不能调用 线程 B 的 JNIEnv;

JNIEnv 不能跨线程 :  当前线程有效 : JNIEnv 只在当前线程有效, JNIEnv 不能在 线程之间进行传递, 在同一个线程中,

多次调用 JNI层方法, 传入的 JNIEnv 是相同的;

本地方法匹配多JNIEnv : 在 Java 层定义的本地方法, 可以在不同的线程调用, 因此 可以接受不同的 JNIEnv;

JNIEnv 结构 : 由上面的代码可以得出, JNIEnv 是一个指针,  指向一个线程相关的结构, 线程相关结构指向 JNI 函数指针

数组, 这个数组中存放了大量的 JNI 函数指针, 这些指针指向了具体的 JNI 函数;

注意:JNIEnv只在当前线程中有效。本地方法不能将JNIEnv从一个线程传递到另一个线程中。相同的 Java 线程中对本地

方法多次调用时,传递给该本地方法的JNIEnv是相同的。但是,一个本地方法可被不同的 Java 线程所调用,因此可以接受

不同的 JNIEnv。

二、Application.mk:

1. Application.mk目的是描述在你的应用程序中所需要的模块(即静态库或动态库)。Application.mk文件通常被放置在 $PROJECT/jni/Application.mk

下,$PROJECT指的是您的项目。

2. 该文件内变量的作用:

2.1 APP_PROJECT_PATH:这个变量是强制性的,并且会给出应用程序工程的根目录的一个绝对路径。这是用来复制或者安装一个没有任何版本限制的JNI库,从而给APK生成工具一个详细的路径。

2.2  APP_MODULES:这个变量是可选的,如果没有定义,这个模块名字被定义在Android.mk文件中的LOCAL_MODULE   中。NDK将由在Android.mk中声明的默认的模块编译,并且包含所有的子文件(makefile文件), NDK会自动计算模块的依赖。如果APP_MODULES定义了,它必须是一个空格分隔的模块列表( 注意:NDK在R4开始改变了这个变量的行为,在此之前: 在Application.mk中,该变量是强制的必须明确列出所有需要的模块)。

2.3  APP_OPTIM:这个变量是可选的,用来定义“release”或"debug"。在编译您的应用程序模块的时候,可以用来改变优先级。“release”模式是默认的,并且会生成高度优化的二进制代码。"debug"模式生成的是未优化的二进制代码,但可以检测出很多的BUG,可以用于调试。注意:如果你的应用程序是可调试的(即: 如果你的清单文件在它的标签中把android:debuggable属性设为true),默认将是debug而非release。把APP_OPTIM设置为release可以覆写它。注意:可以调试release和debug版二进制,但release版构建倾向于在调试会话中提供较少信息:一些变量被优化并且不能被检测,代码重新排序可能致使代码步进变得困难,堆栈跟踪可能不可靠,等等。

2.4   APP_CFLAGS : 这个变量是可选的, 一个C编译器开关集合,在编译任意模块的任意C或C++源代码时传递。它可以用于改变一个给定的应用程序需要依赖的模块的构建,而不是修改它自身的Android.mk文件。

2.5   APP_BUILD_SCRIPT : 默认,NDK构建系统将在 $(APP_PROJECT_PATH)/jni下寻找一个名为 Android.mk 的文件。即,对于这个文件 $(APP_PROJECT_PATH)/jni/Android.mk。如果你想重载这个行为,你可以定义APP_BUILD_SCRIPT指向一个不同的构建脚本。一个非绝对路径将总是被解析为相对于NDK顶级目录的路径。

2.6   APP_ABI : 默认情况下,NDK的编译系统根据 "armeabi" ABI生成机器代码。可以使用APP_ABI 来选择一个不同的ABI。比如:为了在ARMv7的设备上支持硬件FPU指令。可以使用  APP_ABI := armeabi-v7a或者为了支持IA-32指令集,可以使用  APP_ABI := x86或者为了同时支持这三种,可以使用 APP_ABI := armeabi armeabi-v7a x86。

2.7   APP_STL :默认,NDK构建系统提供由Android系统给出的最小C++运行时库(/system/lib/libstdc++.so)的C++头文件。然而,NDK带有另一个C++实现,你可以在你自己的应用程序中使用或链接它。定义APP_STL以选择它们其中的一个:

APP_STL := stlport_static    -->   static STLport library

APP_STL := stlport_shared  -->   shared STLport library

APP_STL := system             -->   default C++ runtime library

三、 Android.mk

1. Android.mk的作用:

Android.mk 用来向编译系统描述你的源代码。具体来说:该文件是GNU Makefile的一小部分,会被

编译系统解析一次或多次。你可以在每一个Android.mk 文件中定义一个或多个模块,你也可以在几个模块

中使用同一个源代码文件。每个模块属下列类型之一:

a.  APK程序,一般的Android程序,编译打包生成apk文件;

b.  JAVA库,java类库,编译打包生成jar文件;

c.  C\C++应用程序,可执行的C\C++应用程序;

d.  C\C++静态库,编译生成C\C++静态库,并打包成.a文件;

e.  C\C++共享库, 编译生成共享库(动态链接库),并打包成.so, 有且只有共享库才能被安装/复制到

您的应用软件(APK)包中。

以下面代码为例:

LOCAL_PATH: = $(call my-dir)

JNI_PATH: =$(LOCAL_PATH)

include $(CLEAR_VARS)

# This is the target being built.

LOCAL_MODULE:= liblike

LOCAL_SRC_FILES := liblike.a

#include $(PREBUILT_STATIC_LIBRARY)

#include $(CLEAR_VARS)

# This is the target being built.

LOCAL_MODULE: = libhellojni

LOCAL_C_INCLUDES : = $(JNI_PATH) /include \

$(JNI_PATH) /test/inc \

$(JNI_PATH) /test/ble/inc \

$(JNI_PATH) /testlib/inc

#LOCAL_C_INCLUDES := $(JNI_PATH)/include

# All of the source files that we will compile.

LOCAL_SRC_FILES: = native_func.cpp \

test/src/test1.cpp \

test/src/test2.cpp \

test/src/test3.c

#LOCAL_C_INCLUDES  += system/core/include/cutils

# All of the shared libraries we link against.

LOCAL_SHARED_LIBRARIES : = liblog libcutils libutils

#LOCAL_STATIC_LIBRARIES := liblike

LOCAL_PROGUARD_ENABLED : = disabled

# Also need the JNI headers.

LOCAL_C_INCLUDES + = \

$(JNI_H_INCLUDE)

LOCAL_PRELINK_MODULE : = false

LOCAL_LDLIBS : = -llog -lz -lm

include $(BUILD_SHARED_LIBRARY)

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

(2). include $(CLEAR_VARS),CLEAR_VARS由编译系统提供((可以在 android 安装目录的

/build/core/config.mk 文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

(3).   LOCAL_MODULE:= liblike 、LOCAL_SRC_FILES := liblike.a 和 LOCAL_STATIC_LIBRARIES := libshlib 其中LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块,名称必须是唯一的,而且不包含任何空格。 LOCAL_SRC_FILES := liblike.a 用于引用由C或者C++封装.a的库文件且该库文件的所在目录为jni的根目录。LOCAL_STATIC_LIBRARIES := liblike ,表示该模块需要使用哪些静态库,以便在编译时进行链接 。

(4).   LOCAL_MODULE:=  libhellojni ,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'like'的共享库模块,将会生成'liblike.so'文件(也可以直接已libxxx命名好)。

(5).   LOCAL_SRC_FILES := test/src/test1.cpp \ ,LOCAL_SRC_FILES变量必须包含需要编译的.c文件或.cpp文件的C或C++源代码文件 。

(6).   LOCAL_C_INCLUDES : = $(JNI_PATH) /include \ 表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。注意"\"后面不能为空格,但可以为换行符。

(7).   TARGET_ARCH:目标 CPU平台的名字;TARGET_PLATFORM:Android.mk 解析的时候,目标 Android 平台的名字;TARGET_ARCH_ABI暂时只支持两个值:armeabi 和 armeabi-v7a。

(8).    LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。

(9).   LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。

(10).   LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。注意:它不会附加列出的模块到编译图,也就是仍然需要在Application.mk 中把它们添加到程序要求的模块中。

(11).    LOCAL_LDLIBS:  编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的。例如,LOCAL_LDLIBS := -lz表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so可查看 docs/STABLE-APIS.TXT 获取使用 NDK发行版能链接到的开放的系统库列表。

(12).    LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的 module 是以 32 位指令的形式。

'arm' (32-bit instructions) mode. E.g.:

LOCAL_ARM_MODE :=

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值