【发布时间】:2014-07-25 20:35:45
【问题描述】:
重点:
我想从 Java 调用 C/C++ 函数。
我的工作:
我可以使用“javah”程序生成一个 .h 文件。它正确地吐出我的头文件。完美的。我添加了两个包含此头文件的 .c 文件,其中只有一个实现了该功能。第二个是一个完全空的 .c 文件,原因是 Android NDK 构建系统中的一个错误。到目前为止一切都很好。
我使用 Android NDK“ndk-build”脚本为多个不同平台生成我的 .so 文件。再次,完美运行。
我将这些库文件(在它们各自的文件夹中)添加到我的 Android Studio 项目的 jniLibs 文件夹中。 Gradle 会看到它们,并在构建时将它们正确添加到我的 .apk 文件中。
在我的应用程序源代码中,我使用
static { System.loadLibrary("testLib"); }。 (是的,这是正确的文件名)。并且它成功加载它没有问题。
问题:
当我尝试调用本机函数(在 java 中定义并在 C++ 中实现)时,我得到以下异常:
java.lang.UnsatisfiedLinkError: Native method not found:
com.example.nativeapp.MainActivity.testNativeMethod:()Ljava/lang/String;"
这就是事情变得奇怪的地方:/:我使用 NDK 成功编译,使用 Gradle 成功构建,并在我的应用程序代码中使用 Java 成功“loadLibrary”。但是当简单地调用函数“testNativeMethod();”时,我得到了运行时异常和应用程序崩溃。
这是我的“javah”生成的头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_nativeapp_MainActivity */
#ifndef _Included_com_example_nativeapp_MainActivity
#define _Included_com_example_nativeapp_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_example_nativeapp_MainActivity_MODE_PRIVATE
#define com_example_nativeapp_MainActivity_MODE_PRIVATE 0L
#undef com_example_nativeapp_MainActivity_MODE_WORLD_READABLE
#define com_example_nativeapp_MainActivity_MODE_WORLD_READABLE 1L
#undef com_example_nativeapp_MainActivity_MODE_WORLD_WRITEABLE
#define com_example_nativeapp_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef com_example_nativeapp_MainActivity_MODE_APPEND
#define com_example_nativeapp_MainActivity_MODE_APPEND 32768L
#undef com_example_nativeapp_MainActivity_MODE_MULTI_PROCESS
#define com_example_nativeapp_MainActivity_MODE_MULTI_PROCESS 4L
#undef com_example_nativeapp_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define com_example_nativeapp_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef com_example_nativeapp_MainActivity_BIND_AUTO_CREATE
#define com_example_nativeapp_MainActivity_BIND_AUTO_CREATE 1L
#undef com_example_nativeapp_MainActivity_BIND_DEBUG_UNBIND
#define com_example_nativeapp_MainActivity_BIND_DEBUG_UNBIND 2L
#undef com_example_nativeapp_MainActivity_BIND_NOT_FOREGROUND
#define com_example_nativeapp_MainActivity_BIND_NOT_FOREGROUND 4L
#undef com_example_nativeapp_MainActivity_BIND_ABOVE_CLIENT
#define com_example_nativeapp_MainActivity_BIND_ABOVE_CLIENT 8L
#undef com_example_nativeapp_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#define com_example_nativeapp_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef com_example_nativeapp_MainActivity_BIND_WAIVE_PRIORITY
#define com_example_nativeapp_MainActivity_BIND_WAIVE_PRIORITY 32L
#undef com_example_nativeapp_MainActivity_BIND_IMPORTANT
#define com_example_nativeapp_MainActivity_BIND_IMPORTANT 64L
#undef com_example_nativeapp_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define com_example_nativeapp_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef com_example_nativeapp_MainActivity_CONTEXT_INCLUDE_CODE
#define com_example_nativeapp_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undef com_example_nativeapp_MainActivity_CONTEXT_IGNORE_SECURITY
#define com_example_nativeapp_MainActivity_CONTEXT_IGNORE_SECURITY 2L
#undef com_example_nativeapp_MainActivity_CONTEXT_RESTRICTED
#define com_example_nativeapp_MainActivity_CONTEXT_RESTRICTED 4L
#undef com_example_nativeapp_MainActivity_RESULT_CANCELED
#define com_example_nativeapp_MainActivity_RESULT_CANCELED 0L
#undef com_example_nativeapp_MainActivity_RESULT_OK
#define com_example_nativeapp_MainActivity_RESULT_OK -1L
#undef com_example_nativeapp_MainActivity_RESULT_FIRST_USER
#define com_example_nativeapp_MainActivity_RESULT_FIRST_USER 1L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_DISABLE
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_DIALER
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_DIALER 1L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SHORTCUT
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define com_example_nativeapp_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
* Class: com_example_nativeapp_MainActivity
* Method: testNativeMethod
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_nativeapp_MainActivity_testNativeMethod
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
这是我的 .c 实现文件:
#include "com_example_nativeapp_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_example_nativeapp_MainActivity_testNativeMethod(JNIEnv* environment, jobject obj)
{
return ( *env )->NewStringUTF(env, "HELLO FROM C Native!");
}
最后但同样重要的是,这是我的 .java 应用程序文件:
package com.example.nativeapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends Activity
{
static { System.loadLibrary("testLib"); }
private TextView mDebugText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDebugText = (TextView)findViewById(R.id.debug_text);
// Here is where my native function call takes place. Without this, the app does (NOT) crash.
mDebugText.setText(testNativeMethod());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public native String testNativeMethod();
}
提前致谢。这绝对是监视器类型的问题之一。
请注意:
我试过这个:https://www.youtube.com/watch?v=okLKfxfbz40连续三次完美地按照步骤操作,仍然失败。
另外,我一直在 Stackoverflow 上阅读,但没有一个问题与我的情况相符。他们都在使用 opencv 等,我只想制作自己的“Hello World”Android NDK 库。再次感谢您。
已编辑以修复格式问题以提高可读性。
【问题讨论】:
-
UnsatisfiedLinkError明确表示函数没有加载。如果您确定共享库libtestLib.so是在运行时加载的,则可能是符号不在库中(即函数尚未在库中编译)。您确定您在Android.mk文件中添加了源代码吗?您可以通过列出符号在共享库中查找testNativeMethod(查看here)。 -
我确实在 .so 上运行了 readelf。实际上,该函数不在符号表中。那么也许 Android NDK 编译阶段没有像我想象的那样工作?我现在就调查一下……
-
感谢您的评论,我走上了正轨,并在下面发布了解决方案。以防万一其他人有这个问题。
-
这就是它的工作原理;-)。然后尽快验证您自己的答案,以结束问题。
-
会的,再过 7 个小时,我就可以这样做了。
标签: java android c++ android-ndk