为了账号安全,请及时绑定邮箱和手机立即绑定

请问该如何加载ndk库?如何在jni中注册native函数?

/ 猿问

请问该如何加载ndk库?如何在jni中注册native函数?

烙印99 2019-09-14 14:11:43

如何加载ndk库?如何在jni中注册native函数


查看完整描述

5 回答

?
万千封印

Android中JNI是编译so库的源代码,编译成功后会生成SO库,android中最终是使用SO库的。
1.android的NDK开发需要在linux下进行: 因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。
2.安装android-ndk开发包,这个开发包可以在google android 官网下载: 通过这个开发包的工具才能将android jni 的C/C++的代码编译成库
3.android应用程序开发环境: 包括eclipse、java、 android sdk、 adt等。


查看完整回答
反对 回复 2019-09-17
?
函数式编程

android源码中native方法的使用并不是你所想的那样,能够去查看的它的具体定义。其实它的具体的定义是在库(比如lib/hello-jni.c或者.cpp文件)中实现的。比如在package\app下有个ServiceMenu,它里面有相应的.cpp文件,用native方法修饰的函数就...

查看完整回答
反对 回复 2019-09-17
?
繁星淼淼

1. ndk支持的库很少,所以用以前最好先看看自己需要的功能是不是已经包括了,省得白忙活。
2. 注册函数的方法是不同的。举例说,在com/evan129/jnitest/jniutils.java有个native int foo()方法,需要在jni中实现
在ndk中,只要实现这个函数,然后函数名是以jint java_com_evan129_jnitest_jniutils_foo(jnienv* env, jobject thiz) 命名既可。也就是说,如果jni只要实现这个函数,并且功能也很简单的话,那么jni c/cpp文件里只需要这一个函数就完事了。
但在android源码中编译jni代码是不同的,jni中的函数名无所谓。不过至少还需要加一个
jniexport jint jnicall jni_onload(javavm* vm, void* reserved)方法,这个方法可以找个现有的复制一把就行,检查运行环境的。然后主要是这个方法中会调用(*env).registernatives函数,在这里把jni中的方法和java文件中的方法关联起来。
3. 有个很诡异的区别,自动传入的jnienv* env好像不是一个东西。因为在android源码中使用这个env一般是如env->newstringutf(…),而ndk中sample里的一处是(*env)->newstringutf(…) 这env和*env差很大。但两处函数传入的都是jnienv* env,只能怀疑jnienv的定义是不是都是不同的。


查看完整回答
反对 回复 2019-09-17
?
慕森王

1. ndk支持的库很少,所以用以前最好先看看自己需要的功能是不是已经包括了,省得白忙活。不过人家是有解释的,说ndk里有的库才是稳定的,其它的建议你不要用。嗯,google总是这一套说辞,不公开的api也是。至于要看android源码中多了哪些库,make modules后grep一下lib开头的应该就是了,不过也不是所有都能用啦。

2. 注册函数的方法是不同的。举例说,我在com/evan129/jnitest/jniutils.java有个native int foo()方法,需要在jni中实现
在ndk中,你只要实现这个函数,然后函数名是以jint java_com_evan129_jnitest_jniutils_foo(jnienv* env, jobject thiz) 命名既可。也就是说,如果你的jni只要实现这个函数,并且功能也很简单的话,那么你的jni c/cpp文件里只需要这一个函数就完事了。
但在android源码中编译jni代码是不同的,jni中的函数名无所谓。不过你至少还需要加一个
jniexport jint jnicall jni_onload(javavm* vm, void* reserved)方法,这个方法你可以找个现有的复制一把就行,检查运行环境的。然后主要是这个方法中会调用(*env).registernatives函数,在这里把jni中的方法和java文件中的方法关联起来。
看起来像是ndk自动补上了这部分工作,我并不清楚原理啦。

3. 有个很诡异的区别,自动传入的jnienv* env好像不是一个东西。因为在android源码中使用这个env一般是如env->newstringutf(…),而ndk中sample里的一处是(*env)->newstringutf(…) 这env和*env差很大吧。但两处函数传入的都是jnienv* env,我只能怀疑jnienv的定义是不是都是不同的。
末了,就是说下我这个很简单的jni折腾了我两天的一个问题。如前所说,我是用android源码来编译的,自己在packages/app/下建了pinyinjni工程,下面有个jni目录,每次直接用mmm packages/app/pinyinjni/jni来编译。jni目录下的android.mk中指定的名字是这样的local_module := libpinyin 每次编译都很顺利,生成了libpinyin.so。但是我在java文件里,system.loadlibrary(“libpinyin”)总是失败。感谢paranoia@newsmth帮我解决了这个问题,告诉我在loadlibrary时用”pinyin”。但是,这个事情实在太奇怪了,那文件名是libpinyin.so啊,而且我在这里用/data/data/…/libpinyin.so这种完整路径也会失败,我以前虽然没写过jni,但调用过,用完整路径指定jni so文件应该不会有问题的。或者,从另一个角度想,如果我local_module的名字不是用lib开头的,那它调用时应该用什么名字?这个”lib”前缀又是哪步删除的?我没有多做测试了,但是猜想ndk中应该是没有这种诡异的问题的。


查看完整回答
反对 回复 2019-09-17
?
慕标5265247

NDK:
1、包含头文件
#include <android/log.h>
2、Android.mk中包含库
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
上面这个一定要,不然出现error: undefined reference to '__android_log_print'
LOCAL_SHARED_LIBRARIES := libdl\
liblog\ #经测试在Eclipse中用NDK编译可有可无,没啥用!但在源码中就必须是他,所以都加上吧!
libpre_AppUpgrade\
libpre_AppArea\
3、在你的jni文件中定义
#define LOGD() __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) // 定义LOGD类型
#define LOGI() __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // 定义LOGI类型
#define LOGW() __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) // 定义LOGW类型
#define LOGE() __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // 定义LOGE类型
#define LOGF() __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) // 定义LOGF类型
adnroid4.2源码中已经将LOGD等都加了一个头,
#define ALOGD() __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) // 定义LOGD类型
#define ALOGI() __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // 定义LOGI类型
#define ALOGW() __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) // 定义LOGW类型
#define ALOGE() __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // 定义LOGE类型
#define ALOGF() __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) // 定义LOGF类型
注意如果你不想在每一个jni文件中都定义上述宏,投机方法即可以定义在:D:\android-ndk-r9d\platforms\android-19\arch-arm\usr\include\android\log.h中!当然这种编译也只能在你本机上使用啦~
源码开发:
1、Android.mk中包含库
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
LOCAL_SHARED_LIBRARIES := libdl\
liblog\ //源码中开发一定的加上
libpre_AppUpgrade\
libpre_AppArea\
2、包含头文件#include <utils/Log.h>
3、注意在使用时记得包含库的头文件



查看完整回答
反对 回复 2019-09-17

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信