I'm trying to use the NDK with C++ and can't seem to get the method naming convention correct. my native method is as follows:
extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
//
}
}
with a header wrapped in extern "C" {} aslo.
Everything compiles fine, creates a .so file and copies to the libs folder under my project, but when I debug and run in Eclipse I keep getting a log cat message that of "no implementation found for native...". Is there something i'm missing as all the NDK examples are in C?
Thanks.
There are a couple of things that can lead to "no implementation found". One is getting the function prototype name wrong, another is failing to load the .so at all. Are you sure that System.loadLibrary() is being called before the method is used?
If you don't have a JNI_OnLoad function defined, you may want to create one and have it spit out a log message just to verify that the lib is getting pulled in successfully.
You already dodged the most common problem -- forgetting to use extern "C" -- so it's either the above or some slight misspelling. What does the Java declaration look like?
An additional cause for this error: your undecorated native method name must not contain an underscore!
For example, I wanted to export a C function named AudioCapture_Ping(). Here is my export declaration in C:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object); //Notice the underscore before Ping
Here was my Java class importing the function:
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapture_Ping(); // FAILS
...
I could not get Android to dynamically link to my native method until I removed the underscore:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object);
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapturePing(); // THIS WORKS!
...
I had the same problem, but to me the error was in the file Android.mk. I had it:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp
but should have this:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp
note the detail += instead :=
I hope that helps.
Called extern "C" as provided in the automatically-generated Studio example, but forgot to wrap the entire rest of the file, including following functions, in {} brackets. Only the first function worked.
An additional reason: Use LOCAL_WHOLE_STATIC_LIBRARIES instead of LOCAL_STATIC_LIBRARIES in android.mk. This stops the library from optimizing out unused API calls because the NDK cannot detect the use of the native bindings from java code.
There is a cpp example under apps in ndk:
https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp
Use javah (part of Java SDK). Its the tool exactly for this (generates .h header from .class file).
If your package name includes _ character, you should write 1(one) after _ character as shown below:
MainActivity.java
package com.example.testcpp_2;
native-lib.cpp
JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
I try all above solutions, but no one can solved my build error(jni java.lang.UnsatisfiedLinkError: No implementation found for...),
at last I found that I forget to add my verify.cpp source file to CMakeList.txt add_library segement(verify.cpp is auto generate by Ctrl + Enter short key, maybe other file name), hope my response can help some one.
my build environment: Gradle + CMake
I Faced the same problem, and in my case the reason was that I had underscore in package name "RFID_Test"
I renamed the Package and it worked.
Thanks user1222021
I faced the same problem twice. It happened, that the phone I tried to start the app from Android Studio used an API level that I haven't downloaded yet in Android Studio.
Upgrade Android Studio to the latest version
Download the necessary API from within Android Studio
Related
I have a simple C++ function compiled into a dylib file that I'm trying to run on an Android phone. The function is super simple, it just adds to numbers and returns the result. However, I keep getting this error:
Another exception was thrown: Invalid argument(s): Failed to load dynamic library 'libadd.dylib': dlopen failed: library "libadd.dylib" not found .
I'm really not sure what I'm doing wrong. I've done the following steps:
My Dart implementation:
import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
typedef C_ADD = ffi.Int Function(
ffi.Int a, ffi.Int b); // FFI signature of C function
typedef ADD = int Function(int a, int b);
void linkAndCallFunction() {
var libraryPath = path.join(Directory.current.path, "libadd.dylib");
final dylib = ffi.DynamicLibrary.open(libraryPath);
final ADD add = dylib.lookup<ffi.NativeFunction<C_ADD>>("add").asFunction();
final result = add(40, 2);
print(result);
}
I've added these to the build.gradle files:
build.gradle:
buildscript{
ext{
ndkVersion = "25.1.8937393"
}
...
and app/build.gradle:
android {
ndkVersion rootProject.ext.ndkVersion
externalNativeBuild {
cmake {
path "../../lib/CMakeLists.txt"
}
}
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10.2)
project(add LANGUAGES CXX C)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
add_library(add SHARED ./add.cpp)
and my file structure of the project looks like this:
lib/
- add.cpp
- add.o
- CMakeLists.txt
- libadd.dylib
- main.dart
it also may be worth mentioning that in order to compile add.cpp into a dylib I ran the following commands:
g++ -c add.cpp
ar rvs libadd.dylib add.o
and if you're wondering, add.cpp looks like this:
#define EXPORT extern "C" __attribute__((visibility("default")))
__attribute__((used))
EXPORT
int add(int a, int b){
return a + b;
}
Where is this error coming from? am I compiling to a dylib incorrectly?
The answer to this problem was relatively simple, it just stemmed from my lack of knowledge on how Android actually compiles to a static library. Hopefully it helps someone else who is trying to understand how to setup external C++ code in a flutter program.
The static library is generated automatically and is set up in CMakeLists.txt.
Firstly, I moved all the C++ files into the android folder. Then, I set up CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.10.2)
add_library( add // library name, will create libadd.so
SHARED
add.cpp
)
The problem before was that I was trying to manually compile the file myself, when I should have been letting CMakeLists do it instead. According to the android documentation:
"The convention CMake uses to name the file of your library is as follows:
liblibrary-name.so
For example, if you specify "native-lib" as the name of your shared library in the build script, CMake creates a file named libnative-lib.so. "
https://developer.android.com/studio/projects/configure-cmake
So when I run the program, the static library is created automatically and placed in the correct place. Then, the Dart FFI can find it with the DynamicLibrary.open() function. In this case, CMakeLists will generate a file called libadd.so, and I can callDynamicLibrary.open('libadd.so') and the program works.
I have problem when I try to use C++ library in Android studio project.
I am using statically built Qt 5.14.2 for Android.
I have Qt library project which has only 1 class with this 2 functions:
testclass.h
#include <QDebug>
#include <jni.h>
extern "C"
{
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log();
void logNormal();
}
testclass.cpp
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log()
{
qDebug() << "---> log from Qt library";
}
void logNormal()
{
qDebug() << "---> log from Qt library";
}
An in the .pro file I am using shared or staticlib to switch from shared(.so) and static(.a) library.
TEMPLATE = lib
CONFIG += shared
#CONFIG += staticlib
CONFIG += c++11
After successfully building the lib (shared and static) I got this files(for ABI x86 but others ABIS have similar sizes too):
libTestLibrary.so ---> 3,359 KB
libTestLibrary.a ---> 7 KB
For the shared (.so) library I was able to successfully call the function from android app.
In Android Studio I am creating new Native C++ project. I have Java JNI LibraryClas which is used to load the library and call the log() function from the library. I placed the library in jniLibs folder.
But for the static(.a) library there are a lot of problems. I tried to call the logNormal() function from the C++ part of the android app(from native-lib.cpp). I am not using JNI like in the shared library case. Here is what I tried:
Create new Native C++ project
Created libs(for the static library) and include(for testclass.h) folders inside app\src\main\cpp
Inside CMakeList.txt I have added this:
add_library(TestLibrary STATIC IMPORTED)
set_target_properties(TestLibrary PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libTestLibrary.a)
target_link_libraries( native-lib TestLibrary ${log-lib} )
And I called logNormal(); from native-lib.cpp.
First I got Error about missing Qt5Core library. After adding it the same way like my library I got errors for others missing libraries and files.
I have this questions:
Why static library is so much smaller then the shared library? (7KB vs 3,359KB) I found this which is opposite from my case:
Can I somehow build my static lib with all libraries and files that it need, so I don't get errors for missing libraries?
Can I use JNI to call C++ functions from static lib? Or when calling C++ functions from static lib it must be done from the C++ part of the android project?
Sorry for the long post and more then 1 question. Any hint or help is welcome. Thank you so much in advance.
It's the first time I try to create a library c++ for Android/iOS.
I'm using Visual Studio 2015 - Xamarin.
First I created a project : Visual C++ -> Cross Platform -> Shared Library. In the hared library, I created 2 files.
SayHello.h :
#pragma once
#include <string.h>
class SayHello {
public:
SayHello();
~SayHello();
static char* Hello();
};
SayHello.cpp :
#include "SayHello.h"
extern "C"
{
SayHello::SayHello(){}
SayHello::~SayHello(){}
char * SayHello::Hello()
{
return "Hello !";
}
}
Then I generated a file libSayHello.so and created a project Android with xamarin to try to call the function hello.
There is my MainActivity.cs :
[DllImport("libSayHello.so")]
static extern String Hello();
protected override void OnCreate(Bundle bundle)
{
// I paste only my added code :
String hello = Hello();
Toast.MakeText(this.ApplicationContext, hello, ToastLength.Long);
}
I did all steps in this tutorial, but I have an exception :
System.DllNotFoundException: libSayHello.so
I searched for this, but I must be so noob cause I did not find anything. How should I use my libSayHello.so ?
EDIT:
There is my libSayHello.so seen with 7zip:
And my project :
I think this will be the best sample for you.
This all works according to the following scheme:
Android supports 7 CPU architectures.
But Xamarin supports 5 of them. So in the settings of your Xamarin.Android project check which architectures you will support:
[Xamarin.Droid.project]->[Properties]->[Android Options]->[Advanced]->[Supported architectures]
Check which archs are necessary for your project. According to this your shared library should be compiled for these archs. And you should put your shared libraries in Xamarin.Droid.project's folder lib:
To see them in Solution Explorer you should mention them in your Xamarin.Android project's .CSPROJ.
Add there next item groups:
<ItemGroup>
<AndroidNativeLibrary Include="lib\{ARCH}\libCLib.so">
<Abi>{ARCH}</Abi>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AndroidNativeLibrary>
</ItemGroup>
{ARCH} could be next: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64.
Now you can put DllImport in your code:
[DllImport("libCLib", EntryPoint = "clib_add")]
public static extern int Add(int left, int right);
I think you have to tell about entry point, because i had runtime errors without this statement System.EntryPointNotFoundException.
And don't forget to add next in your code:
using System.Runtime.InteropServices;
Confirm the library is put in "/lib/{arch}/" folder.
Try [DllImport("SayHello")]. the engine may add "lib" and ".so" automatically.
Environment: Latest NDK + Eclipse Juno + ADT + CDT. Everything is up to date.
When I try to debug my Android application natively, I get the following error:
warning: Unable to find dynamic linker breakpoint function.
GDB will retry eventurally. Meanwhile, it is likely
that GDB is unable to debug shared library initializers
or resolve pending breakpoints after dlopen().
To ensure it is not my specific application, I created a simple dummy application. Here are the steps I took.
From Eclipse, create a new Android application project (with min-sdk 16 and target-sdk 21)
Added a class:
package com.test.mytest1;
public class MyNative {
static {
android.os.Debug.waitForDebugger();
System.loadLibrary("mytest1");
}
native public static void init();
}
Note that I have added a line to wait for the debugger to initialize.
Called MyNative.init() from MainActivity's onCreate() method.
From preferences, fixed NDK to point to C:\adt\ndk directory.
From the project menu, selected Android Tools-->Add Native Support.
From Properties->C++ Build, set build command to "ndk-build NDK_DEBUG=1"
Here is the code in mytest1.cpp:
static int x = 0;
JNIEXPORT void JNICALL Java_com_test_mytest1_MyNative_init(JNIEnv *, jclass)
{
x++;
}
Added Application.mk in jni directory:
APP_ABI := armeabi-v7a
APP_PLATFORM := android-16
Now, when I try to run the app as native application, it fails with the above mentioned message.
When I look at the apk file, lib/armeabi-v7a does contain gdbserver as well as libmytest1.so files.
The app does work. If I add a log() statement in my native method, it does get displayed in LogCat.
I am confused and tired. A simple thing like thing should just work. Wondering if you can share what you did differently to make it work. Regards.
android.os.Debug.waitForDebugger() is for JAVA debugging.
To debug Native code add sleep(seconds) before your first breakpoint , that's way gdb have to to connect gdbserver
JNIEXPORT void JNICALL Java_com_test_mytest1_MyNative_init(JNIEnv *, jclass)
{
sleep(10);
x++;
}
I have a core project which I'm building as a shared library. In one of the headers, I've defined a simple class shown below:
typedef pthread_mutex_t Mutex;
class CORE_API AutoLock
{
public:
AutoLock(Mutex& m);
~AutoLock();
private:
AutoLock();
AutoLock(const AutoLock&);
AutoLock& operator=(const AutoLock&);
Mutex m_Mutex;
};
where CORE_API is defined as:
#ifdef CORE_DLL
#define CORE_API __attribute__ ((dllexport))
#else
#define CORE_API __attribute__ ((dllimport))
#endif
In the Android.mk for core, I've defined CORE_DLL under LOCAL_CFLAGS. However, when building, I get the warning:
warning: 'dllimporot' attribute directive ignored
When ndk-build gets to the other project where I want to use the AutoLock class, I get the error:
error: 'AutoLock::AutoLock()' is private
error: within this context
Why would the compiler ignore the dllexport attribute? I would hope that once that's fixed, my other project should build and be able to use the AutoLock class without any problems.
Shared libraries are created differently on Android (Linux) than with Windows.
In Windows you have the special dllimport and dllexport directives but not on Android (Linux).
When using your shared library, you should just compile with -lYourLibraryName
This might help you: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
Have a look at the sample code available in the android-ndk, specially the Android.mk file this might solve your problem.