gpt4 book ai didi

java - 示例 hello-jni 上的 Android NDK java.lang.UnsatisfiedLinkError

转载 作者:行者123 更新时间:2023-12-02 04:46:37 25 4
gpt4 key购买 nike

我需要在 android 上运行一些 native C 代码,并尝试设置 NDK。我正在使用 Android studio。

我已经导入了 hello-jni 示例,但它根本不起作用。我总是收到 java.lang.UnsatisfiedLinkError 错误。

ndk 构建:

$ ndk-build
[arm64-v8a] Gdbserver : [aarch64-linux-android-4.9] libs/arm64-v8a/gdbserver
[arm64-v8a] Gdbsetup : libs/arm64-v8a/gdb.setup
[x86_64] Gdbserver : [x86_64-4.9] libs/x86_64/gdbserver
[x86_64] Gdbsetup : libs/x86_64/gdb.setup
[mips64] Gdbserver : [mips64el-linux-android-4.9] libs/mips64/gdbserver
[mips64] Gdbsetup : libs/mips64/gdb.setup
[armeabi-v7a] Gdbserver : [arm-linux-androideabi-4.8] libs/armeabi-v7a/gdbserver
[armeabi-v7a] Gdbsetup : libs/armeabi-v7a/gdb.setup
[armeabi] Gdbserver : [arm-linux-androideabi-4.8] libs/armeabi/gdbserver
[armeabi] Gdbsetup : libs/armeabi/gdb.setup
[x86] Gdbserver : [x86-4.8] libs/x86/gdbserver
[x86] Gdbsetup : libs/x86/gdb.setup
[mips] Gdbserver : [mipsel-linux-android-4.8] libs/mips/gdbserver
[mips] Gdbsetup : libs/mips/gdb.setup
[arm64-v8a] Compile : hello-jni <= hello-jni.c
[arm64-v8a] SharedLibrary : libhello-jni.so
[arm64-v8a] Install : libhello-jni.so => libs/arm64-v8a/libhello-jni.so
[x86_64] Compile : hello-jni <= hello-jni.c
[x86_64] SharedLibrary : libhello-jni.so
[x86_64] Install : libhello-jni.so => libs/x86_64/libhello-jni.so
[mips64] Compile : hello-jni <= hello-jni.c
[mips64] SharedLibrary : libhello-jni.so
[mips64] Install : libhello-jni.so => libs/mips64/libhello-jni.so
[armeabi-v7a] Compile thumb : hello-jni <= hello-jni.c
[armeabi-v7a] SharedLibrary : libhello-jni.so
[armeabi-v7a] Install : libhello-jni.so => libs/armeabi-v7a/libhello-jni.so
[armeabi] Compile thumb : hello-jni <= hello-jni.c
[armeabi] SharedLibrary : libhello-jni.so
[armeabi] Install : libhello-jni.so => libs/armeabi/libhello-jni.so
[x86] Compile : hello-jni <= hello-jni.c
[x86] SharedLibrary : libhello-jni.so
[x86] Install : libhello-jni.so => libs/x86/libhello-jni.so
[mips] Compile : hello-jni <= hello-jni.c
[mips] SharedLibrary : libhello-jni.so
[mips] Install : libhello-jni.so => libs/mips/libhello-jni.so

jni/Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

jni/hello-jni.c:

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a/NEON (hard-float)"
#else
#define ABI "armeabi-v7a/NEON"
#endif
#else
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a (hard-float)"
#else
#define ABI "armeabi-v7a"
#endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif

return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");
}

com.example.hellojni.HelloJni:

public class HelloJni extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

/* Create a TextView and set its content.
* the text is retrieved by calling a native
* function.
*/
TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}

/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI();

/* This is another native method declaration that is *not*
* implemented by 'hello-jni'. This is simply to show that
* you can declare as many native methods in your Java code
* as you want, their implementation is searched in the
* currently loaded native libraries only the first time
* you call them.
*
* Trying to call this function will result in a
* java.lang.UnsatisfiedLinkError exception !
*/
public native String unimplementedStringFromJNI();

/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.hellojni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("hello-jni");
}
}

错误:

11-13 22:38:40.227  19386-19386/com.example.hellojni E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.hellojni, PID: 19386
java.lang.UnsatisfiedLinkError: Couldn't load hello-jni from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.hellojni-7.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.hellojni-7, /vendor/lib, /system/lib]]]: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:358)
at java.lang.System.loadLibrary(System.java:526)
at com.example.hellojni.HelloJni.<clinit>(HelloJni.java:64)
at java.lang.Class.newInstanceImpl(Native Method)
at java.lang.Class.newInstance(Class.java:1208)
at android.app.Instrumentation.newActivity(Instrumentation.java:1067)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2399)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2599)
at android.app.ActivityThread.access$900(ActivityThread.java:174)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1321)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5748)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(Native Method)

如果您知道是什么原因造成的,请帮助我。我已经在这上面浪费了一整天的时间了,准备跳出窗外(带着电脑)。

最佳答案

这是因为 Android Studio 会忽略您的 Android.mk 并即时生成自己的 Android.mk,从 gradle 脚本获取设置。因此,您应该在 gradle 脚本中指定正确的设置(由于 Android Studio 中的 NDK 支持不完整,该脚本仅在最简单的情况下有效),或者完全禁用 Android Studio 有限的 NDK 支持并直接从 gradle 调用 ndk-build。

要在 gradle 脚本中指定 NDK 相关设置,请添加以下部分:

defaultConfig {
...
ndk {
moduleName "my-module-name"
cFlags "-std=c++11 -fexceptions"
ldLibs "log"
stl "gnustl_shared"
abiFilter "armeabi-v7a"
}
}

并在那里设置您的项目特定值。然后,Android Studio 的 gradle 插件将考虑这些设置,并使用这些设置自动生成 Android.mk。

但请注意,唯一可用的 NDK 选项是上面列出的选项。如果您有更复杂的 NDK 设置(例如,多个 NDK 模块,相互依赖,或者您想要使用预构建的库,或其他什么),您应该完全禁用 Android Studio 有限的 NDK 支持并直接从 gradle 调用 ndk-build。为此,首先禁用 Android.mk 自动生成:

android {
.....
// disable automatic ndk-build call, which ignore our Android.mk
sourceSets.main.jni.srcDirs = []
}

然后添加以下行:

android {
.....
sourceSets.main.jniLibs.srcDir 'src/main/libs'

// call regular ndk-build(.cmd) script from app directory
task ndkBuild(type: Exec) {
workingDir file('src/main')
commandLine getNdkBuildCmd()
}

tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}

task cleanNative(type: Exec) {
workingDir file('src/main')
commandLine getNdkBuildCmd(), 'clean'
}

clean.dependsOn cleanNative
}

最后,将辅助函数添加到 gradle 脚本的末尾:

def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkdir = properties.getProperty('ndk.dir', null)
if (ndkdir == null)
throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.")

return ndkdir
}

def getNdkBuildCmd() {
def ndkbuild = getNdkDir() + "/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkbuild += ".cmd"

return ndkbuild
}

啊,别忘了在 gradle 脚本的开头添加“import”:

import org.apache.tools.ant.taskdefs.condition.Os

Here我已经描述得更详细了。

关于java - 示例 hello-jni 上的 Android NDK java.lang.UnsatisfiedLinkError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29609188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com