android ndk开发经常遇到了动态库的问题,本文主要介绍:
① 动态链接库的生成;
② 在Java和C混合编程的情况下如何调用第三方动态链接库;
③ 通过jar包的方式间接调用第三方动态链接库;
④ 使用dlopen程序运行时直接调用;
⑤ 纯c的方式开发调用;
本文重点推荐②和⑤,第④中太麻烦每个函数都需要dlsym调用一次,第③中主要用在有第三方jar包的情况下;
方便他人亦是方便自己,如果觉得还行就点下右边的投票吧,这样可以帮助其他人更快的找到解决问题的方法;有疑问的也可留言哦, 谢谢!
代码的百度云链接:http://pan.baidu.com/s/1dD3qkQ9 密码:c5s3
工具/原料
Win7 x64
adt-bundle-windows-x86_64-20140702
android-ndk-r10
生成动态库
1
android ndk下面生成动态库so文件的方法很多,但是这里只提供一种方法,更多的生成方法可以看,“ndk 编译静态库”:
http://jingyan.baidu.com/article/63f236280b90690208ab3d12.html
2
fkAdd.c 的内容如下:
#include
int fkAdd(int nX, int nY)
{
returnnX + nY;
}
3
Android.mk 的内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= fkAdd
LOCAL_SRC_FILES:= fkAdd.c
include $(BUILD_SHRRED_LIBRARY)
4
1、打开 eclipse
2、点击 文件
3、点击 新建
4、点击 other...
5
1、展开 Android 选项;
2、选择 Android Project from Existing Code;
3、点击 Next
6
1、输入 Root Director;
2、取消 tests;
3、选中 Copy projects into workspace;
4、点击 Finish;
7
1、右键工程;
2、选择 Android Tools;
3、Add Native Support...;
8
点击 Finish
9
修改android sdk 版本为 4.0.3;
关于如何修改 android sdk 版本:
http://jingyan.baidu.com/article/c910274bfdd000cd371d2d4b.html
10
修改 Min SDK version:15
修改 Target SDK version:19
11
在jni目录下面新建文件fkAdd.c 的内容如下:
int fkAdd(int nX, int nY)
{
returnnX + nY;
}
12
临时修改 Android.mk 文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#LOCAL_MODULE := hello-jni
#LOCAL_SRC_FILES := hello-jni.c
LOCAL_MODULE := fkaddso
LOCAL_SRC_FILES := fkAdd.c
include $(BUILD_SHARED_LIBRARY)
13
使用快捷键Ctrl+B编译后可以在libs目录下面看到生成的一些列的
libfkaddso.so文件,如下图所示
END
Java和c编程调so
1
1、将libs复制一份到jni目录下面,删掉其中不相关的文件
2、删掉文件 jni/fkadd.c 文件
3、将 Android.mk 文件还原成最开始的样子;
2
修改 hello-jni.c 中的部分代码,如下:
char szMsg[1024] = {0};
int nSum = fkAdd(100, 10);
sprintf (szMsg, "Hello from JNI ! Compiled with ABI " ABI ". %d ", nSum);
return (*env)->NewStringUTF(env, szMsg);
3
修改 Android.mk 文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fkaddso
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libfkaddso.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SHARED_LIBRARIES := fkaddso
include $(BUILD_SHARED_LIBRARY)
4
修改 HelloJni.java 在其中增加一行:
System.loadLibrary("fkaddso");
5
运行工程看效果:
END
用jar调用so
1
菜单->File->New->Android Application Project
2
创建一个没有主题的android project
3
1、取消复选框 Create activity
2、选择复选框 Mark this project as a library
3、Next
4
点击 Next
5
点击 Finish
6
新建一个类: NativeSo,包名:fuke.nativeso
7
在 NativeSo.java 中添加如下内容:
package fuke.nativeso;
package fuke.nativeso;
public class NativeSo {
static {
System.loadLibrary("fkaddso");
System.loadLibrary("nativeso");
}
public static native int GetTestValue();
}
8
1、右键工程->Anroid Tools->Add Native Support
2、将 生成动态库 部分生成的jni目录下面的: libs目录,Android.mk,Application.mk 三个文件拷贝到本工程的jni目录下面
3、修改 Android.mk中的内容为:
LOCAL_PATH := $(call my-dir)
### 把动态链接库重新名一个模块名
include $(CLEAR_VARS)
LOCAL_MODULE := fkaddso
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libfkaddso.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := nativeso
LOCAL_SRC_FILES := NativeSo.c
LOCAL_SHARED_LIBRARIES := fkaddso
include $(BUILD_SHARED_LIBRARY)
9
通过javah生成 fuke_nativeso_NativeSo.h,关于如何利用javah生成native方法对应的头文件,见“ndk java 和 c 互掉”:
http://jingyan.baidu.com/article/f54ae2fcde72be1e92b84916.html
10
在 NativeSo.c 文件中添加内容:
#include
#include "fuke_nativeso_NativeSo.h"
extern int fkAdd(int nX, int nY);
JNIEXPORT jint JNICALL Java_fuke_nativeso_NativeSo_GetTestValue
(JNIEnv *pJniEnv, jclass pJclass){
returnfkAdd(100, 1000);
}
11
Application.mk 中内容如下:
APP_ABI := all
12
按照 生成动态库部分中的1-10这10个步骤导入ndk测试用例 HelloJni
13
1、右键工程属性
2、选择android分页
3、增加 NativeSo 库
4、点击Apply
5、点击OK
14
修改 HelloJni.java 文件的方法 onCreate:
tv.setText( stringFromJNI() + NativeSo.GetTestValue());
15
编译运行后效果如下:
16
在 HelloJni.java 中增加:
System.loadLibrary("fkaddso");
System.loadLibrary("nativeso");
删除 NativeSo.java 中删除对应的几行:
17
为了方便验证修改下过,修改 NativeSo.c 中的数据:
returnfkAdd(100, 999);
18
编译运行后的效果如下:
END
用dlopen调用so
1
重复“生成动态库”中的过程1到10,
2
把需要调用so文件的目录libs拷贝到jni目录下面,并修改 Android.mk 文件的内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fkaddso
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libfkaddso.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
3
修改 hello-jni.c 的内容如下:
char*szSo = "/data/data/com.example.hellojni/lib/libfkaddso.so";
void* fkAddSo = dlopen(szSo, RTLD_LAZY);
int (*fpAdd)(int,int) = (int (*)(int,int))dlsym(fkAddSo, "fkAdd");
char szMsg[1024] = {0};
int nSum = fpAdd(100, 200);
dlclose(fkAddSo);
sprintf (szMsg, "%s %d", szSo, nSum);
return (*env)->NewStringUTF(env, szMsg);
4
关于如何获取 so在手机中的路径,可以通过在控制台下输入 adb shell 后,
在手机上查询:
5
编译后运行效果:
6
方便他人亦是方便自己,如果觉得还行就点下下边的投票吧,这样可以帮助其他人更快的找到解决问题的方法;有疑问的也可留言哦, 谢谢!
END
纯c的方式开发调用
1
此方法需要感谢ndk吧的吧友提供哦,本人只是负责将其进行了整理,归纳后发帖,谢谢,原始地址:http://tieba.baidu.com/p/3247530080
2
根据“生成动态库”中的过程1到10,新建一个纯c的ndk程序:
“D:\Android\android-ndk-r10\samples\native-activity"
3
把会用的so文件的目录libs拷贝到 jni目录下面
4
修改 Android.mk 文件,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fkAdd
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libfkAdd.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_SRC_FILES := main.c
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
LOCAL_STATIC_LIBRARIES := android_native_app_glue
LOCAL_SHARED_LIBRARIES := fkAdd
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := native-activity
LOCAL_SRC_FILES := NativeActivity.c
LOCAL_LDLIBS := -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
5
增加 NativeActivity.c 文件,添加内容如下:
#include
#include
#include
#include
void android_main(struct android_app* state) {
// Make sure glue isn't stripped.
app_dummy();
void* soAdd = dlopen("/data/data/com.example.native_activity/
lib/libfkAdd.so",RTLD_NOW);
void* soMain = dlopen("/data/data/com.example.native_activity/
lib/libmain.so",RTLD_NOW);
void (*fp_android_main)(struct android_app*) =
(void (*)(struct android_app*))dlsym(soMain,"android_main");
fp_android_main(state);
dlclose(soMain);
dlclose(soAdd);
}
6
在 main.c 文件中添加一行,方便测试:
__android_log_print(ANDROID_LOG_DEBUG, "fuke", "engine_handle_input 100 + 200 = [%d] ", fkAdd(100, 200));
7
编译运行,点击手机屏幕后,观察logcat 效果如下:
END
注意事项
c++的函数在写动态链接库的时候,需要注意的是c++的函数会被系统修改,所以做动态库测试的使用最好用c语言