围绕C ++方法编写JNI包装器

时间:2016-01-08 17:27:40

标签: java c++ android-studio android-ndk java-native-interface

我想在Android工作室中使用三个C ++文件。

  • Header.h
  • A.cpp(包含主要方法+其他方法)
  • B.cpp

我已将它们编译成静态库。现在我想围绕C ++方法编写JNI包装器并将其调用到java部分。到目前为止,这是我的包装器:

#include <jni.h>
#include <string.h>
#include <stdlib.h>

extern "C" {


   JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?) {

   IplImage * byteQueryImage = loadByteImage ( ? );
  if ( !byteQueryImage )
  {
    printf ( "couldn't load query image\n" );
    return -1;
  }

  // Detect text in the image
  IplImage * output = textDetection ( byteQueryImage, atoi(1));
  cvReleaseImage ( &byteQueryImage );
  cvSaveImage ( ? , output );
  cvReleaseImage ( &output );
  return 0;
}
}

我想给它两张图片作为参数:加载IplImage * byteQueryImage = loadByteImage ( ? );的图片和保存cvSaveImage ( ? , output );的图片。 这两个参数的jni类型JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?)应该是什么(如果我认为图片是.png)?

2 个答案:

答案 0 :(得分:0)

您可以将包装函数放在任何将被编译的文件中,无论是新的还是现有的。与Java不同,在C ++中,文件名对编译器没有意义。

如果您不打算独立于Java调用它们,则不需要包装其他方法。

PS:请注意,包装函数的名称Java_cgi_pi_detect派生自定义此detect本机方法的Java类。使用javah工具生成实现本机Java方法的C函数的正确名称。

答案 1 :(得分:0)

这样调用main()充满了危险。 将要调用哪个 main()? JVM可执行文件也有main()。 (是的,我忽略了“未定义的行为”,因为问题是关于如何使其发挥作用。)

获取所需main()的困难方法是将其编译为共享对象,加载该共享对象,并使用{{3自行查找该共享对象中的main()运行时动态链接}和dlopen()(省略错误检查):

#include <dlfcn.h>
...
// use a typedef for the function pointer
typedef int ( *main_func_t )( int, char ** );
...
// Handle to your .so with your "main()" in it
// make them static so they're only loaded once
static void *libHandle = NULL;
static main_func_t libMain = NULL;

if ( NULL == libHandle )
{
    libHandle = dlopen( "yourLibName.so", RTLD_NOW );
    libMain = ( main_func_t ) dlsym( libHandle, "main" );
}
...

// now call the main() in that library
int mainRetVal = libMain( argc, argv );
...

这意味着您需要两个共享对象:第一个保存JNI调用的“普通”对象,第二个保存您要调用的“main()”。第一个“普通”JNI库需要使用libdl.so链接器参数与-ldl的依赖关联。

简单方法?

将要调用的main()重命名为其他内容并将其放入普通的JNI共享对象中。然后只需调用它 - 它不再被称为main(),因此不再存在任何名称冲突。

尽管如此,我怀疑你仍然可能会遇到问题 - 立即想到名称冲突或不兼容的库。

的更简单方法是什么?

在子进程中运行它,因为它是设计运行的方式,无论如何它实际上是一个黑盒子:你用参数调用它,它做它做的任何事情,你得到一个int返回值。对于函数调用或子进程来说,这是相同的。