最近在帮助项目的大神测试编译出来的安卓动态库,需要用到jni,但是使用ndk去编译有太麻烦(还是懒),毕竟库太多了。然后以前听说android studio被谷歌搞得可以使用cmake
去编译源码库,于是乎,就更新了许久未用的android studio。在这个过程中真的是很恶心。使用jni动态注册函数时,总是注册不过,最后就是用android studio原声的
native-lib.cpp通过静态注册的方式搞定。
在CmakeList.txt文件中需要最一些配置更改。
这个是项目打开时原版本的CmakeList.txt在这个基础上加上自己所需要的静态库
cmake_minimum_required(VERSION 3.4.1)
#将静态库的头文件添加进来
include_directories(
${CMAKE_SOURCE_DIR/src/main/include} #头文件多的话可以继续往下加
${CMAKE_SOURCE_DIR/src/main/include/..}
${CMAKE_SOURCE_DIR/src/main/include/...}
。。。。
)
add_library( # 自己的库名字
native-lib
# 将自己的库编译成动态库
SHARED
# 自己的cpp源码所在的路径即jni源码的路径
src/main/cpp/native-lib.cpp )
#添加自己所需的静态库 库多的话,可以使用下面的方式添加
add_library( event #库名字 去掉了 lib 与 .a
STATIC #必须的
IMPORTED #必须的
)
set_target_properties(
event
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/libevent.a #库在的路径,以cmakeList.txt所在的路径起
)
#添加自己所需的静态库 库多的话,可以使用下面的方式添加
add_library( event #库名字 去掉了 lib 与 .a
STATIC #必须的
IMPORTED #必须的
)
set_target_properties(
event
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/libevent.a #库在的路径,以cmakeList.txt所在的路径起
)
find_library( log-lib log ) target_link_libraries( native-lib #我自己的需要生成的动态库 event #将所需的库和自己要生成的动态库连接起来,多的话一次向下追加 x264 faac ${log-lib} )
在native-lib.cpp文件中写上的是关于自己的jni函数,将所需头文件包含进来,就可以通过jni函数调用静态库的函数。
#include <jni.h>
#include <string>
#include <stdio.h>
#include "ares.h"
#include "faac.h"
#include "uuid.h"
#include "turbojpeg.h"
#include "x264.h"
void insertSort(int *data,int len);
//调用libcares的例子
extern "C"
JNIEXPORT jint JNICALL Java_com_skylight_testlibs_JNIHeader_AreasLibInit(JNIEnv *env, jobject )
{
jint result=ares_library_init(1);
return result;
}
//调用libuuid的例子
extern "C"
JNIEXPORT jint JNICALL Java_com_skylight_testlibs_JNIHeader_UuidIsNull(JNIEnv *env, jobject)
{
const uuid_t uu= {0};
jint result=uuid_is_null(uu);
return result;
}
//调用libturbojpeg的例子
extern "C"
JNIEXPORT jint JNICALL Java_com_skylight_testlibs_JNIHeader_TJAlloc(JNIEnv *env, jobject )
{
unsigned char* c= tjAlloc(128);
const char* result=(const char*)c;
if (c == NULL)
{
return -1;
} else{
return 0;
}
}
//调用libx264库的例子
extern "C"
JNIEXPORT jint JNICALL Java_com_skylight_testlibs_JNIHeader_X264PictureAlloc(JNIEnv *env, jobject )
{
x264_picture_t *ipic= nullptr;
x264_picture_init( ipic );
jint result= x264_picture_alloc( ipic, 32, 512, 256 );
return result;
}
//调用faac库的函数例子
extern "C"
JNIEXPORT jint JNICALL Java_com_skylight_testlibs_JNIHeader_FaacEncClose(JNIEnv *env, jobject )
{
jint result=-2;
unsigned long nSampleRate = 44100;
unsigned int nChannels = 2;
unsigned int nPCMBitSize = 16;
unsigned long nInputSamples = 0;
unsigned long nMaxOutputBytes = 0;
faacEncHandle hEncoder = {0};
faacEncHandle handle= faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes);
if (handle == NULL)
{
result= -1;
} else{
result= 0;
}
return result;
}
//调用insertSort函数
extern "C"
JNIEXPORT void JNICALL Java_com_skylight_testlibs_JNIHeader_insertSortArray(JNIEnv *env, jobject obj,jintArray array)
{
jint *data=env->GetIntArrayElements(array,NULL);
jsize len=env->GetArrayLength(array);
insertSort(data,len);
env->ReleaseIntArrayElements(array,data,0);
}
//排序
void insertSort(int *data,int len)
{
int temp = 0;
int i = 1;
int j = 0;
for (; i < len; i++)
{
temp = data[i];
j = (i - 1);
for (; j >= 0; j--)
{
if (data[j] > temp)
{
data[j + 1] = data[j];
}
else
{
break;
}
}
data[j + 1] = temp;
}
}
在java层的代码就很简单了直接写上native方法就行可以了。
public class JNIHeader
{
static {
System.loadLibrary("native-lib");
}
public native void insertSortArray(int[] data);
public native int AreasLibInit();
public native int UuidIsNull();
public native int TJAlloc();
public native int X264PictureAlloc();
public native int FaacEncClose();
}
在build.gradle中还需要加入以下配置,在defaultConfig中加入下面的配置,
externalNativeBuild {
cmake {
arguments '-DANDROID_PLATFORM=android-23',
'-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
}
}
ndk {
abiFilters 'armeabi-v7a' // armeabi-v7a 这里需要过滤一下处理器类型
}
在defaultConfig的下面加入这个配置
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
这样就可以使用cmake在android studio中调用静态库的函数了
android studio在调用动态库时和调用静态库的方式略有不同,不知道别人是
怎么解决的,目前我的android studio碰到调用动态库的问题如下:
1、在src/main/目录下新建一个文件夹jniLibs,在该文件夹中需要建立区分ABI的类型的文件夹
-->即armeabi-v7a armeabi-arm 等子文件夹,最终的目录会是
------>src
---------->main
--------------->jniLibs
----------------------->armeabi-v7a(armeabi-arm)等
路径会是--->src/main/jniLibs/armeabi-v7a 或者对应的ABI
2、将自己所要调用的动态库.so文件放置在上述目录中 例如(src/main/jniLibs/armeabi-v7a/xxxx.so)
3、在CmakeList.txt文件中添加动态库
add_library( 库名 SHARED IMPORTED )
set_target_properties( 库名 PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/lib库名.so )
注:ANDROID_ABI就是ABI类型--->armeabi-v7a或者对应的
4、在java代码中加载动态库
System.loadLibrary("库名");
建议:将调用的动态库放在native-lib库的上面。先加载三方动态库
5、在target_link_libraries()中将动态库添加进去
最近在帮助项目的大神测试编译出来的安卓动态库,需要用到jni,但是使用ndk去编译有太麻烦(还是懒),毕竟库太多了。然后以前听说android studio被谷歌搞得可以使用cmake
去编译源码库,于是乎,就更新了许久未用的android studio。在这个过程中真的是很恶心。使用jni动态注册函数时,总是注册不过,最后就是用android studio原声的
native-lib.cpp通过静态注册的方式搞定。
在CmakeList.txt文件中需要最一些配置更改。
这个是项目打开时原版本的CmakeList.txt在这个基础上加上自己所需要的静态库