【问题标题】:Android Studio Native CMake No implementation found for nativeAndroid Studio Native CMake 没有找到原生的实现
【发布时间】:2018-05-23 19:01:41
【问题描述】:

我已更新到 Android Studio 3.0,我正在尝试从已弃用的 NDK 迁移到 CMake,以构建我的 Android 应用的本机组件。

我已按照https://developer.android.com/studio/projects/configure-cmake.html 的指南进行操作,这是我的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
         myappNative

         # Sets the library as a shared library.
         SHARED

         # Provides a relative path to your source file(s).
         src/main/cpp/src
         )


include_directories(src/main/cpp/include)
SET_TARGET_PROPERTIES(myappNative PROPERTIES LINKER_LANGUAGE CXX)

(最后一行不在教程中,但在添加之前我遇到了错误)。

这是我的文件夹结构:

这是我的原生方法:

public class Native {

    static {
        System.loadLibrary("myappNative");
    }

    public native static String sign(String[] tokens);
}

这是我的头文件(由javah生成):

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_myapp_system_Native */

#ifndef _Included_com_myapp_system_Native
#define _Included_com_myapp_system_Native
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_myapp_system_Native
 * Method:    sign
 * Signature: ([Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_myapp_system_Native_sign
  (JNIEnv *, jclass, jobjectArray);

#ifdef __cplusplus
}
#endif
#endif

而且我有相应的 C++ 文件可以正确编译。我的 APK 包含 libmyapp.so 文件,一切看起来都符合预期。我的应用程序构建,它开始运行,它加载库:(logcat)

D/dalvikvm: Trying to load lib /data/app-lib/com.myapp.myapp-1/libmyappNative.so 0x41e09aa0
D/dalvikvm: Added shared lib /data/app-lib/com.myapp.myapp-1/libmyappNative.so 0x41e09aa0

然后,当我尝试调用本机方法时,我得到了这个:

W/dalvikvm: No implementation found for native Lcom/myapp/system/Native;.sign:([Ljava/lang/String;)Ljava/lang/String;

接下来是:

E/AndroidRuntime: FATAL EXCEPTION: com.myapp.client.queue
                                     Process: com.myapp.myapp, PID: 19542
                                     java.lang.UnsatisfiedLinkError: Native method not found: com.myapp.system.Native.sign:([Ljava/lang/String;)Ljava/lang/String;
                                         at com.myapp.system.Native.sign(Native Method)
[...]

我的应用程序崩溃了。我已经看到很多关于此的问题,包括 Android NDK C++ JNI (no implementation found for native...),但这些解决方案也无济于事。

在日志中,我看到:

:app:externalNativeBuildDebug
Build myappNative armeabi-v7a
[1/1] Linking CXX shared library ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libmyappNative.so
:app:compileDebugSources

这似乎没问题。

我还在某处读到 Proguard 可能会修改方法名称,因此我也为此添加了一条规则:

-keep class com.myapp.system.Native

我不知道它是否会改变任何东西。

这也是我的gradle文件的相关部分:

android {
    compileSdkVersion 26
    buildToolsVersion '26.0.2'

    defaultConfig {
        applicationId "com.myapp.myapp"
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 2043
        versionName "2.1"
        ndk {
            moduleName "myappNative"
            cFlags "-DNATIVE_DEBUG=1"
        }

    }


    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }
}

我也尝试过实现JNI_OnLoad 方法并在标头中声明它,但似乎也没有找到,这可能是我的配置通用的线索,而不是特定方法:

No JNI_OnLoad found in /data/app-lib/com.myapp.myapp-2/libmyappNative.so 0x41e10aa0, skipping init

为什么 Android 找不到我的原生方法?

【问题讨论】:

    标签: android c++ c cmake android-ndk


    【解决方案1】:

    显然,教程中没有的错误(通过添加SET_TARGET_PROPERTIES)是关键。

    我发现了问题所在。在我的CMakeLists.txt 中,我引用了文件夹src/main/cpp/src。它并没有真正编译任何文件。我检查了nm(ARM 版本),在.so 文件中没有看到任何实际方法。然后,我在我的 CPP 文件中添加了一些垃圾(不应该编译),但构建成功完成。我最初关于编译 CPP 文件的假设是不正确的:工具链甚至没有尝试编译我的文件。看来我需要列出要显式编译的文件:

    add_library( # Specifies the name of the library.
             myappNative
    
             # Sets the library as a shared library.
             SHARED
    
             # Provides a relative path to your source file(s).
             src/main/cpp/src/com_myapp_system_Native.cpp
             src/main/cpp/src/sha256.c
             )
    

    我不知道如何包含文件夹。我试过src/main/cpp/srcsrc/main/cpp/src/*src/main/cpp/src/*.cpp,但它们似乎都不起作用。更改文件后,我的应用程序开始正确运行(并加载本机组件)。

    【讨论】:

    • 按名称明确列出文件是一种公认​​的方法,我什至会说,这是一种推荐的处理方法。如果你迫切需要通配符,可以使用file (GLOB …)
    • @AlexCohn 我实际上是 CMake 的新手,尽管以“即发即弃”的方式添加文件夹可能是个好主意。但如果明确引用是要走的路,我会保持这种方式。感谢您的评论:)
    【解决方案2】:

    嘿,使用 target_include_directories 代替 include_directories。使用此功能,您将私下将目录添加到该库。如果您仍然收到有关源文件的错误,请在源路径行中添加 {CMAKE_CURRENT_SOURCE_DIR}。它有效!

    【讨论】:

      猜你喜欢
      • 2011-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-14
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 2020-09-10
      相关资源
      最近更新 更多