在安卓中使用 JNI 'multiply'的未定义引用

undefined reference to 'multiply' using JNI in android

本文关键字:multiply 引用 未定义 JNI      更新时间:2023-10-16

我是android JNI的新手,正在尝试以下代码:

程序包名称:com.example.jnitest

Java类:

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    MainActivity mainActivity = new MainActivity();

    System.out.println("Sum of two variables : "+ sumOfTwovariable((int)mainActivity.multiply(10, 25), 10));
}
public native long sumOfTwovariable(int v1, int v2);
static {
    System.loadLibrary("JNITest");
}
public native long multiply(int v1, int v2);
static{
    System.loadLibrary("com_example_pdemo_MainActivity");
}
}

Android.mk文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := JNITest
LOCAL_SRC_FILES := JNITest.cpp
LOCAL_SHARED_LIBRARIES := Prebuild_com_example_pdemo_MainActivity
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includes
LOCAL_STATIC_LIBRARIES := Prebuild_com_example_pdemo_MainActivity
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := Prebuild_com_example_pdemo_MainActivity
LOCAL_SRC_FILES :=    $(TARGET_ARCH_ABI)/libcom_example_pdemo_MainActivity.so
include $(PREBUILT_SHARED_LIBRARY)

我在Android.mk文件中的JNI->armeabi(写入多功能)文件夹中预构建了com_example_pdemo_MainActivity.so库


JNI:内部

使用:javah-jni-classpath…创建头文件。。。。

Header file created using javah : com_example_jnitest_MainActivity.h
  /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jnitest_MainActivity */
#ifndef _Included_com_example_jnitest_MainActivity
#define _Included_com_example_jnitest_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jnitest_MainActivity
  * Method:    sumOfTwovariable
  * Signature: (II)J
*/
JNIEXPORT jlong JNICALL    Java_com_example_jnitest_MainActivity_sumOfTwovariable(JNIEnv *, jobject, jint, jint);
 #ifdef __cplusplus
 }
#endif

#endif

本机函数的定义:JNITest.cpp

  #include "com_example_jnitest_MainActivity.h"
extern "C" {
long multiply(int val1,int val2);
}
   JNIEXPORT jlong JNICALL      Java_com_example_jnitest_MainActivity_sumOfTwovariable(
    JNIEnv *env, jobject obj, jint val1, jint val2) {
int val=multiply(val1,val2);
return (val+val1);

}

当我编译它时,我得到了对"multiply"的未定义引用。让我知道我犯了什么错误

提前感谢

multiply也是本机方法。应将其定义为与sumOfTwovarable:相同

JNIEXPORT jlong JNICALL    Java_com_example_jnitest_MainActivity_multiply(JNIEnv *, jobject, jint, jint);

在com_example_pdemo_MainActivity.so的本地代码中,定义乘法如下:

// this can be called from native code, including in different .so files:
long multiply(int val1,int val2)
{
    long result;
    // ...compute result...
    return result;
}
// this can be called from Java via JNI:
JNIEXPORT jlong JNICALL Java_com_example_pdemo_MainActivity_multiply(JNIEnv *env, jobject obj, jint a, jint b)
{
     return multiply(a, b);
}

这将允许您从本机代码或通过JNI调用它。

将你的Android.mk文件更改为这个,将预构建的.so文件放在第一位:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := Prebuild_com_example_pdemo_MainActivity
LOCAL_SRC_FILES :=    $(TARGET_ARCH_ABI)/libcom_example_pdemo_MainActivity.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE    := JNITest
LOCAL_SRC_FILES := JNITest.cpp
LOCAL_SHARED_LIBRARIES := Prebuild_com_example_pdemo_MainActivity
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/includes
include $(BUILD_SHARED_LIBRARY)

最后,在Java代码中,在一个静态块中加载两个库,顺序如下:

static{
    System.loadLibrary("com_example_pdemo_MainActivity");
    System.loadLibrary("JNITest");
}

JNITest需要com_example_pdemo_MainActivity,所以它需要先进行,否则会出现运行时链接错误。

此外,在JNITest.cpp中,删除围绕multiply()声明的extern "C"。如果您使用C++链接编译了com_example_pdemo_MainActivity.so文件,那么在尝试链接JNITest:时,使用C extern将导致链接错误

// extern "C"{ <-- remove
    long multiply(int v1,int v2);
//} <-- remove

如何在字节缓冲区中将数据传递到JNI和从JNI传递数据:

JNIEXPORT int JNICALL Java_com_example_jnitest_MainActivity_compressImage(JNIEnv *pEnv, jobject this, jobject inputByteBuffer, jobject outputByteBuffer)
{
    jbyte* pInBuf = (jbyte*)(*pEnv)->GetDirectBufferAddress(pEnv, inputByteBuffer);
    jbyte* pOutBuf = (jbyte*)(*pEnv)->GetDirectBufferAddress(pEnv, outputByteBuffer);
    int lenOutImage = 0; char *pOutputImage;
    pOutputImage = CompressImage((char *)pInBuf,&lenOutImage);
    // copy to byte buffer
    memcpy((char)pOutBuf, pOutputImage, lenOutImage);        
    free(pOutputImage); // free pOutputImage?
    return lenOutImage;
}