Reputation: 34830
I've updated to Android Studio 3.0 and I'm trying to migrate from deprecated NDK to CMake for building the native components of my Android app.
I've followed the guide at https://developer.android.com/studio/projects/configure-cmake.html and here is my CMakeLists.txt file:
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)
(the last line isn't in the tutorial but I was getting errors before adding it).
Here is my folder structure:
Here is my native method:
public class Native {
static {
System.loadLibrary("myappNative");
}
public native static String sign(String[] tokens);
}
Here is my header file (generated by 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
And I have corresponding C++ files that compile correctly. My APK contains the libmyapp.so
file, everything looks as expected. My app builds, it starts running, it loads the library: (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
Then, the moment I try to call the native method, I get this:
W/dalvikvm: No implementation found for native Lcom/myapp/system/Native;.sign:([Ljava/lang/String;)Ljava/lang/String;
Followed by this:
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)
[...]
And my app crashes. I've seen many questions about this including Android NDK C++ JNI (no implementation found for native...) but those solutions don't help either.
In the log, I see:
:app:externalNativeBuildDebug
Build myappNative armeabi-v7a
[1/1] Linking CXX shared library ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libmyappNative.so
:app:compileDebugSources
Which seems to be alright.
I've also read somewhere that Proguard might be mangling the method names, so I've also added a rule for that too:
-keep class com.myapp.system.Native
I don't know if it changes anything though.
Here is also the related part of my gradle file:
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'
}
}
}
I've also tried implementing a JNI_OnLoad
method and declaring it in the header but it doesn't seem to be found either, which might be a clue for something general with my configuration, rather than a specific method:
No JNI_OnLoad found in /data/app-lib/com.myapp.myapp-2/libmyappNative.so 0x41e10aa0, skipping init
Why is Android unable to find my native method?
Upvotes: 1
Views: 1043
Reputation: 84
hey use target_include_directories instead include_directories. Using this function you will add directories privately to that library. And if still you are get error about source file Add {CMAKE_CURRENT_SOURCE_DIR} in source path line. It works !
Upvotes: 0
Reputation: 34830
Apparently that error that wasn't in the tutorial (which went by adding SET_TARGET_PROPERTIES
) was the key.
I've found out the problem. In my CMakeLists.txt
I was referencing the folder src/main/cpp/src
. It wasn't really compiling any files. I've checked with nm
(ARM version) and I've seen no actual method inside the .so
file. Then, I've added some garbage into my CPP file (which shouldn't compile) but the build completed successfully. My initial assumption about CPP file being compiled was incorrect: the toolchain wasn't even trying to compile my file. It seems that I need to list files to compile explicitly:
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
)
I have no idea how to include a folder. I've tried src/main/cpp/src
, src/main/cpp/src/*
, src/main/cpp/src/*.cpp
but none of them seem to work. After changing the file, my app started to run (and load the native component) correctly.
Upvotes: 1