关于android studio使用cmake 编写jni调用静态库、动态库的方式

9 篇文章 0 订阅

最近在帮助项目的大神测试编译出来的安卓动态库,需要用到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在这个基础上加上自己所需要的静态库


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值