前些天要写Android 双摄打包工作,由于任务紧,要实现调用底层so库功能 ,因此需要写jni来实现。
如下:
1.先应用需要导入so库,定义方法 :
public class Compress {
static {
System.loadLibrary("compress_jni");
}
public native static byte[] compress(byte[] pBokeh,byte[] pMain,byte[] pDepth);
public native static String test(byte[] pBokeh,byte[] pMain,byte[] pDepth,int lBoken,int lMain,int lDepth);
}
定义了两个方法 分别是打包和测试方法 ,现在需要生成编译这个类文件和生成jni头文件,在android studio 使用
javac 路径/Compress.java 。
然后生成Jni头文件
javah -jni 包名.Compress
注意以上路径不要写错
2.编写JNI
生成了头文件,写个Compress.cpp文件 将头文件的内容复制到Compress.cpp文件 ,然后将定义的方法改写并实现就可以了。
#include
#include
#include "libDepthBokehEffectBase.h"
//#include "FileUtil.h"
/* Header for class com_xthinks_myapplication_Compress */
#ifndef _Included_com_mediatek_camera_feature_mode_vsdof_Compress
#define _Included_com_mediatek_camera_feature_mode_vsdof_Compress
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jbyteArray JNICALL Java_com_mediatek_camera_feature_mode_vsdof_Compress_compress
(JNIEnv *env, jclass jobj, jbyteArray Bokeh , jbyteArray Main, jbyteArray Depth,int Lboken){
BstJpgCompressData mpo;
mpo.pBokehBuffer = (uint8_t *) env->GetByteArrayElements(Bokeh, 0);
mpo.pMainBuffer = (uint8_t *) env->GetByteArrayElements(Main, 0);
mpo.pDepth = (uint8_t *) env->GetByteArrayElements(Depth, 0);
mpo.lBokeh =(jint) env->GetArrayLength(Bokeh);
mpo.lMain = (jint) env->GetArrayLength(Main);
mpo.lDepth =(jint) env->GetArrayLength(Depth);
uint8_t *compressed = nullptr;
uint32_t compressed_len = 0;
int res = bst_jpg_compress(&mpo, &compressed, &compressed_len);
if (res == 0 && compressed != nullptr) {
jbyteArray jarr = env->NewByteArray(compressed_len);
env->SetByteArrayRegion(jarr, 0, compressed_len, (jbyte*)compressed);
delete[] compressed;
return jarr;
} else {
return NULL;
}
// compressed buffer is in "compressed"
// compressed buffer len is "compressed_len"
// 用完了buffer后要delete
// bst_jpg_compress(&mpo, uint8_t** out, uint32_t* lOut);
//int res = bst_jpg_compress(&mpo, "test.jpg");
}
/*
* Class: com_xthinks_myapplication_Compress
* Method: test1
* Signature: ([B[B[B)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_mediatek_camera_feature_mode_vsdof_Compress_test
(JNIEnv *env, jclass jobj, jbyteArray Bokeh , jbyteArray Main, jbyteArray Depth,jint Lboken,jint Lmain,jint Ldepth){
BstJpgCompressData mpo;
mpo.pBokehBuffer = (uint8_t*) env->GetByteArrayElements(Bokeh, 0);
mpo.pMainBuffer = (uint8_t*)env->GetByteArrayElements(Main, 0);
mpo.pDepth =(uint8_t*) env->GetByteArrayElements(Depth, 0);
mpo.lBokeh=Lboken;
mpo.lMain=Lmain;
mpo.lDepth=Ldepth;
int res = bst_jpg_compress(&mpo, "/sdcard/Pictures/test.jpg");
char array[30];
snprintf(array,30,"jni accept num : %d",res);
return env->NewStringUTF(array);
}
#ifdef __cplusplus
}
#endif
#endif
注意
由于代码中使用了第三方的so库,因此会出现编译异常,如果不需要调用第三方so库的话 ,很简单 配置NDK,
打开app Module的build.gradle文件,在defaultConfig节点里添加以下代码
注意这里的moduleName,是我们在之前自己编写的类里面加载的so库名
ndk {
moduleName "jniCompress"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
还要在gradle.properties里面加上这么一句话:
android.useDeprecatedNdk=true
然后编译一下 将 生成了so文件放代码在目录,重新打包编译就可以了。
3.调用第三方so库编译。
曾经搜了很多种方法 都没有编译通过 ,老是报无法匹配该方法,因此就没有使用Android studio编译了 用ubantu环境编译,因此需要写mk文件,单独编译jni,将应用单独编译,然后包含jni的mk文件就可以了 。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libDepthBokehEffectBase
LOCAL_MODULE_CLASS = SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX = .so
LOCAL_PROPRIETARY_MODULE = true
LOCAL_MODULE_TAGS = optional
LOCAL_SHARED_LIBRARIES_64 = libc++
LOCAL_MULTILIB = 64
LOCAL_SRC_FILES := libDepthBokehEffectBase.so
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := libcompress_jni
LOCAL_SRC_FILES := Compress.cpp
LOCAL_MULTILIB = 64
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libDepthBokehEffectBase
include $(BUILD_SHARED_LIBRARY)
注意编译生成的是64位so库
如果要生成32位的话 需要将64改为32就可以了。