#8 预编译宏
# define the macro to compile through support/zip_support/ioapi.c
LOCAL_CFLAGS := -DUSE_FILE32API
LOCAL_EXPORT_CFLAGS := -DUSE_FILE32API
#9 声明生成静态库
include $(BUILD_STATIC_LIBRARY)
#10 添加外部导入库目录
$(call import-add-path,$(LOCAL_PATH))
#11 添加导入库(基于上一行添加的导入库目录)
1,、 项目实现了一个简单的四则运算,项目的目录层次如下:AndroidManifest.xml Android.mk jni res src
资源文件简简单单,一个布局文件,稍后会有demo的下载地址
主要记录备忘的内容如下:
MainActivity.Java
[html] view plain copypublic native int add(int x, int y)
public native int substraction(int x, int y)
public native float multiplication(int x, int y)
public native float division(int x, int y)
static{
System.loadLibrary("arithmetic")
}
2、生成lib的名称为libarithmetic.so.注意load的时候写"arithmetic"
jni 目录下有两个文件,一个是Android.mk,一个是c++源文件long.cpp
jni/Android.mk如下:
[html] view plain copyLOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= libarithmetic
LOCAL_SRC_FILES:= \
long.cpp
LOCAL_SHARED_LIBRARIES := \
libutils
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
LOCAL_CFLAGS +=
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
3、 注释:
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 plain copy#define LOG_TAG "LongTest2 long.cpp"
#include
#include
#include "jni.h"
jint add(JNIEnv *env, jobject thiz, jint x, jint y){
return x + y
}
jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){
return x - y
}
jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){
return (float)x * (float)y
}
jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){
return (float)x/(float)y
}
static const char *classPathName = "com/inspur/test2/MainActivity"
static JNINativeMethod methods[]= {
{"add", "(II)I", (void*)add},
{"substraction", "(II)I", (void*)substraction},
{"multiplication", "(II)F", (void*)multiplication},
{"division", "(II)F", (void*)division},
}
typedef union{
JNIEnv* env
void* venv
}UnionJNIEnvToVoid
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods){
jclass clazz
clazz = env->FindClass(className)
if (clazz == NULL)
return JNI_FALSE
if (env->RegisterNatives(clazz, gMethods, numMethods)<0)
return JNI_FALSE
return JNI_TRUE
}
static int registerNatives(JNIEnv *env){
if (!registerNativeMethods(env, classPathName,
methods, sizeof(methods)/sizeof(methods[0])))
{
return JNI_FALSE
}
return JNI_TRUE
}
jint JNI_OnLoad(JavaVM* vm, void* reserved){
UnionJNIEnvToVoid uenv
uenv.venv = NULL
jint result = -1
JNIEnv *env = NULL
if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){
goto bail
}
env = uenv.env
env = uenv.env
if (registerNatives(env) != JNI_TRUE){
goto bail
}
result = JNI_VERSION_1_4
bail:
return result
}
除了利用 编写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组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。
4、 项目根目录下Android.mk文件:
[html] view plain copyLOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JNI_SHARED_LIBRARIES := libarithmetic
LOCAL_PACKAGE_NAME := LongTest
LOCAL_SHARED_LIBRARIES := \
libutils\
liblog
include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/jni/Android.mk
# Also build all of the sub-targets under this one: the.shared library.
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中,会更加方便
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)