作者:Sam (甄峰) sam_code@hotmail.com


例1:JNI程序使用libhello-jni.so的符号
libhello-jni.so由hello-jni.c组成。

hello-jni.c如下:

#include <string.h> #include <jni.h> #include <android/log.h>

#define LOG_TAG "libhello-jni" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz) { LOGE("SamInfo: Enter Native functionA"); return; }
Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
../../../ndk-build -B V=1
可以正常编译,再使用Eclipse编译Android工程,可正常运行。

例2:JNI程序使用libhello-jni.so的符号
libhello-jni.so由hello-jni.c, hell-jniB.c,头文件hello-jni.h组成。

hello-jni.h如下:
#ifndef _HELLO_JNI_H #define _HELLO_JNI_H
#include <string.h> #include <jni.h> #include <android/log.h>
#define LOG_TAG "libhello-jni" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#endif
hello-jni.c如下:
#include "hello-jni.h"
void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz) { LOGE("SamInfo: Enter Native functionA"); return; }
hell-jniB.c如下:
#include "hello-jni.h" void Java_com_example_hellojni_HelloJni_functionB(JNIEnv* env, jobject thiz) { LOGE("SamInfo: Enter Native functionB"); return; }
Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c hell-jniB.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

注意: LOCAL_SRC_FILES := hello-jni.c hell-jniB.c 此模块hello-jni由两个C文件组成,因为hello-jni.h只是依赖文件,所以不必加入。
又因为hello-jni.h在project/jni目录中,此目录本身为-I,所以也不用再Android.h中指出。

例3:JNI程序使用 libhello-jni.so的符号
libhello-jni.so依赖于libB.a.
libhello-jni.so由hello-jni.c, hell-jniB.c,头文件hello-jni.h组成。

libB.a由libstatic/B1.c,libstatic/B2.c头文件libstatic/B.h组成。

B.h 如下:

#ifndef _B_H #define _B_H
#include <string.h> #include <jni.h> #include <android/log.h>
int iFunctionB1(); int iFunctionB2();
#define LOG_TAG "libStatic" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#endif
B1.c:
#include "B.h"
int iFunctionB1() { LOGI("SamInfo: Enter static function iFunctionB1()"); return 0; }
B2.c
#include "B.h"
int iFunctionB2() { LOGI("SamInfo: Enter static function iFunctionB2()"); return 0; }

hello-jni.h:
#ifndef _HELLO_JNI_H #define _HELLO_JNI_H
#include <string.h> #include <jni.h> #include <android/log.h>
#include "libstatic/B.h"
#define LOG_TAG "libhello-jni" #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#endif hello-jni.c:

#include "hello-jni.h"


void Java_com_example_hellojni_HelloJni_functionA(JNIEnv* env, jobject thiz) { LOGE("SamInfo: Enter Native functionA"); iFunctionB1(); return; }

hell-jniB.c:
#include "hello-jni.h"

void Java_com_example_hellojni_HelloJni_functionB(JNIEnv* env, jobject thiz) { LOGE("SamInfo: Enter Native functionB"); iFunctionB2(); return; }


Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-B LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c hell-jniB.c LOCAL_STATIC_LIBRARIES := hello-B LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
这就是典型的一个Android.mk中包含2个Modules的例子。其中一个是产生静态库,另一个产生动态库。
动态库依赖于静态库。(一定要添加 LOCAL_STATIC_LIBRARIES := hello-B,否则不生成静态库)



例4:JNI程序使用libA.so(由A1.c,A2,c,A.h组成)
libA.so依赖于libB.so(由B1.c,B2.c,B.h组成)


情况分析:
因为libB.so被libA.so使用。所以肯定要加入:
LOCAL_LDLIBS := -L$(LOCAL_PATH)/../libs/armeabi/ -lhello-B

但请注意:此时libA.so中所用到的libB.so 的符号只是一个空穴。并为将实现加进来。

而如果使用:
LOCAL_SHARED_LIBRARIES := hello-B
也仅仅是将libhello-B.so 添加进编译选项。并未将符号添加进去。

在Linux下,此类情况可以将动态库放置于某个目录下,然后使用export LD_LIBRARY_PATH 来解决。但Android下并无此方法。导致运行时会找不到libhello-B.so中的符号。


针对此类情况,有两种方法,但都不是特别好用。分别描述如下:

方法1.

将libhello-B.so放置于/system/lib下。
且Android.mk如下:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := hello-B LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c hell-jniB.c #LOCAL_SHARED_LIBRARIES := hello-B LOCAL_LDLIBS := -llog -L$(LOCAL_PATH)/../libs/armeabi/ -lhello-B
include $(BUILD_SHARED_LIBRARY)

此Android.mk有两个模块,分别产生libhello-B.so, libhello-jni.so. 后者依赖于前者。

而因为Java层程序使用: System.loadLibrary("hello-jni");
则libhello-jni.so的符号加入到Java应用程序中。而它使用到的libhello-B.so,则能够在/system/lib下找到。


方法2. 将libhello-B.so也添加如Java程序中。且放置于hello-jni之前。
System.loadLibrary("hello-B"); System.loadLibrary("hello-jni");

方法3:
可以使用dlopen()方式调用。
据说使用-rpath可以指定应用程序查找库的目录。但Sam觉得理论上并不可能(因为Java无法指定Wl,-rpath).也没有尝试出来。

例5:JNI程序使用libA.so(由A1.c A2.c, A.h组成)
libA.so依赖于libB.so(由B1.c, B2.c, B.h组成)
libB.so依赖于libC.so(由c.c组成)和libD.a(由d.c组成)
libC.so依赖于libD.a(由d.c组成)


Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-B LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c LOCAL_STATIC_LIBRARIES := D LOCAL_LDLIBS := -llog -lC -L$(LOCAL_PATH)/../libs/armeabi/ include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c hell-jniB.c #LOCAL_SHARED_LIBRARIES := hello-B LOCAL_LDLIBS := -llog -L$(LOCAL_PATH)/../libs/armeabi/ -lhello-B include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := C LOCAL_SRC_FILES := c.c LOCAL_LDLIBS := -llog LOCAL_STATIC_LIBRARIES := D include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := D LOCAL_SRC_FILES := d.c LOCAL_LDLIBS := -llog include $(BUILD_STATIC_LIBRARY) 请注意:如此写法:则libD.a中的符号分别被:libC.so, libB.so两次引用。

例6: JNI程序使用libA.so(由A1.c A2.c, A.h组成)
并引用外部生成的:libE.so, libF.a.

Sam:经常发生这样的情况,某NDK工程A生成一个动态库,供另一个NDK工程B使用。我们常把此动态库放到B工程的lib/armeabi下。 但ndk-build时,它会首先删除lib/armeabi下所有.so文件。
所以可以使用 PREBUILT_SHARED_LIBRARY
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-B LOCAL_SRC_FILES := libstatic/B1.c libstatic/B2.c LOCAL_SHARED_LIBRARIES := prelib
LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c hell-jniB.c #LOCAL_SHARED_LIBRARIES := hello-B LOCAL_LDLIBS := -llog -L$(LOCAL_PATH)/../libs/armeabi/ -lhello-B include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS) LOCAL_MODULE := prelib LOCAL_SRC_FILES := libE.so
include $(PREBUILT_SHARED_LIBRARY)
注意:当PREBUILT_SHARED_LIBRARY时,LOCAL_SRC_FILES不再是.c文件,而是动态库。它可以放置在jni下。编译时,它会自动被copy到lib/armaebi下。
请注意模块名。它将被用作LOCAL_SHARED_LIBRARIES

注1:
NDK实用技巧:

1. 显示NDK Build过程中所有编译选项和动作:
../../ndk-build V=1
这样就可以看到编译时所用编译选项是否我们期望使用的。

2.重新编译:
../../ndk-build -B
或者:
../../ndk-build clean
../../ndk-build

注意:此处NDK版本为NDK R7C.(不同NDK版本,ndk-build所产生的Makefile并不完全相同)

更多相关文章

  1. 50个安卓开发者应该熟悉的Android(安卓)Studio技巧和资源
  2. [Android]定制RadioButton样式
  3. Android中ExpandableListView的使用
  4. Freeline 一款 Android平台上的秒级编译方案
  5. 开源终端Android(安卓)Terminal Emulator
  6. CoordinatorLayout使用自定义Behavior实现UC浏览器顶栏效果
  7. Android下使用Socket连接网络电脑
  8. Android自动化测试工具——Monkey
  9. Android中Gallery的应用

随机推荐

  1. Android studio和Eclipse使用的简单感受
  2. QGIS on Android
  3. 海康威视视频监控demo 源码+库文件
  4. Android adb(Android Debug Bridge)常用命
  5. [入门三]Android应用开发入门五问
  6. Android 属性动画(Property Animation) 完
  7. Android 中 OnTouch事件的研究
  8. android include 控件详解
  9. Android和Unity混合开发——Activity和Un
  10. Android ListView 滑动背景为黑色的解决