I just started to use NDK and i ran Hello_Jni and i know how that works but i wanted to try do something like this and cant get it to work (Im doing this manually)
simple.c
#include "simple.h"
#include <jni.h>
JNIEXPORT jdouble JNICALL
Java_com_example_Test_round_decimals (JNIEnv * env, jobject obj, jdouble value, jint decimals) {
double m = pow (10, decimals);
return (double) round (value * m) / m;
}
JNIEXPORT jstring JNICALL Java_com_example_Test_hello(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from ME!");
}
simple.h
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include <string.h>
#include <jni.h>
JNIEXPORT jdouble JNICALL Java_com_example_Test_round_decimals (JNIEnv * env, jobject obj,jdouble value, jint decimals);
JNIEXPORT jstring JNICALL Java_com_example_Test_hello(JNIEnv* env, jobject javaThis);
Activity
public class Test{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
double test = round_decimals(10.1234,2);
double test2 = hello();
Log.i("Round","Number" + test); // i would like to get this
Log.i("String","hello? " + test2); // this works it shows "Hello From ME!"
}
public native double round_decimals(double value, int decimals);
public native String hello();
static {
System.loadLibrary("simple");
}
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := simple
LOCAL_SRC_FILES := simple.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
android.mk, simple.c and simple.h are in JNI folder of my Activity.
And also running Build-ndk in folder of my Activity shows no errors
But when i try to build it on my tablet i get this error.
java.lang.UnsatisfiedLinkError:round_decimals
You generated the .h file from a version of the .java that had a package statement in it, then you modified the .java file to remove the package statement, then you compiled and ran, and nothing matched up.
There's something else wrong here. The method signature should be (JNIEnv*, jobject, jdouble, jint) if you've generated the files correctly.
Regenerate the .h file and adjust the .c file accordingly.
i Found the problem it was with Java_com_example_Test_round_decimals had to rename it to
Java_com_example_Test_roundDecimals and with that i had to rename public native double round_decimals(double value, int decimals); to public native double roundDecimals(double value, int decimals);
You had an underscore (_) inside your method name and underscores are name delimiters in JNI convention.
Changing the java method name to camel case is a solution but you can also escape underscores using _1 in your native method name, like so: Java_com_example_Test_round_1decimals.
Related
It looks like it is the popular problem,
And I still not find out the solution.
package name : app.cloudstringers
Java file : Completed.java
static {
try {
System.loadLibrary("ffmpeg");
} catch (UnsatisfiedLinkError e) {
Log.d("", "Error : " + e.toString());
}
}
// Define native method
public native int getString();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page_completed);
// Call native method
Log.d("", "" + getString());
C++ file : ffmpeg.cpp
#include <jni.h>
#include <android/log.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_app_cloudstringers_Completed_getString(JNIEnv* env, jobject thiz)
{
jstring strRet = env->NewStringUTF("HelloWorld from JNI !");
return strRet;
}
#ifdef __cplusplus
}
#endif
Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := ffmpeg.cpp
include $(BUILD_SHARED_LIBRARY)
I run application but still get the error exception UnsatisfiedLinkError : getString
People who know the how to fix this problem,
Please tell me,
Thanks
UPDATE
Follow #dextor answer. Sorry because I get the mistake. Only thing I need for this question is change from public native int getString() to public native String getString().
It works now.
Not sure (didn't actually try), but the only wrong thing I've noticed is the return type of your method declarations.
Java-side
public native int getString()
NDK-side
JNIEXPORT jstring JNICALL Java_app_cloudstringers_Completed_getString(JNIEnv* env, jobject thiz)
In Java, you have an int. On the C-side, you have a jstring.
I'm using Eclipse ADT with: CDT. Along with NDK interfacing with JNI, to c/c++, compiling c/c++ with Cygwin through Eclipse. Everything should be running the latest versions as this was just setup over the last two weeks.
When Building I get the following.
jni/testSocketClass.hpp:33:1: error: unknown type name 'class'
jni/testSocketClass.hpp:33:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
jni/ndkfoo.c:13:1: error: unknown type name 'mYNewClass'
JNI C file
#include <string.h>
#include <jni.h>
#include "testSocketClassWrapper.hpp"
void *m_GBLpmyCSocket;
ndkfoo.c
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object){
m_GBLpmyCSocket = MyClass_create();
MyClass_sendCommandToSerialDevice(m_GBLpmyCSocket, 0, 0, 0);
return (*env)->NewStringUTF(env, "started");
}
Class Wrapper .hpp
//file testSocketClassWrapper.hpp
#ifndef _MY_SOCKETCLASS_WRAPPER_H
#define _MY_SOCKETCLASS_WRAPPER_H
#include"testSocketClass.hpp"//<<<<<<<<<<<<<<<<<<<<<Wrong inclusion
#ifdef __cplusplus
extern "C" void* MyClass_create() {
return new mYNewClass;
}
extern "C" void MyClass_release(void* myclass) {
delete static_cast<mYNewClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
static_cast<mYNewClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}
#endif
#endif /* _MY_SOCKETCLASS_WRAPPER_H_INCLUDED */
Class wrapper .cpp
//file testSocketClassWrapper.cpp
#include "testSocketClassWrapper.hpp"
Class .h
// file testSocketClass.hpp
class mYNewClass{///////////////////////ERROR HERE////////////////////////////////
//public:
void sendCommandToSerialDevice(int Command, int Parameters, int DeviceID);
//int sockfd;
};
Class .cpp
// file testSocketClass.cpp
#include "testSocketClass.hpp"
void mYNewClass::sendCommandToSerialDevice(int Command, int Parameters, int DeviceID){
char testc[100];
sprintf(testc, "%d, %d, %d", Command, Parameters, DeviceID);
}
I've read countless questions on this topic and have had quite a few issues getting this far with Eclipse configurations too. But from what I've pulled together from other questions on this topic, I have hit a wall and do not know how to proceed at this point. Suggestions?
EDIT BELOW - ANSWER
After review with a colleague(sometimes a second pair of eyes helps bring things out), we located my error. See the line labeled improper inclusion in the Class wrapper .hpp. That header should be relocated as follows in the Class wrapper .cpp NOTE: the functions where also moved to the .cpp and the .hpp is now empty.
//file testSocketClassWrapper.cpp
#include "testSocketClassWrapper.hpp"
#include "testSocketClass.hpp"
extern "C" void* MyClass_create() {
return new mYNewClass;
}
extern "C" void MyClass_release(void* myclass) {
delete static_cast<mYNewClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
static_cast<mYNewClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}
Also for completeness as this has been no walk in the park, are the MK files.
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c testSocketClassWrapper.cpp testSocketClass.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL:=stlport_static
Thank you for the prompt reply krsteeve. And yet another way to do this. Will keep it in mind.
testSockedClass.hpp is being included from a .c file, so it's being compiled with a C-compiler. class doesn't exist in C. Change ndkfoo.c to a .cpp file.
You will have to format things a bit differently in C++:
extern "C"
{
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object);
}
jstring Java_com_example_hydrobedcontrol1_MainActivity_inintNativeClass(JNIEnv * env, jobject object){
m_GBLpmyCSocket = MyClass_create();
MyClass_sendCommandToSerialDevice(m_GBLpmyCSocket, 0, 0, 0);
return env->NewStringUTF("started");
}
Note the form of the NewStringUTF call in C++ vs C.
im attempting to build c++ code with ndk-build but i keep getting this error base operand of '->' has non-pointer type 'JNIEnv <aka _JNIEnv>'
i have tried every solution on the first 2 pages of google with no luck, the ndk just isnt being good to me.
nativemain.h
#ifndef NATIVEMAIN_H
#define NATIVEMAIN_H
#include <string.h>
#include <jni.h>
extern "C"
{
JNIEXPORT jstring JNICALL Java_com_ndktest3_MyRenderer_stringFromJNI( JNIEnv* env,
jobject thiz );
}
#endif
nativemain.cpp
#include <nativemain.h>
JNIEXPORT jstring JNICALL Java_com_ndktest3_MyRenderer_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return env->NewStringUTF("Hello from JNI !");
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativemain
LOCAL_SRC_FILES := nativemain.cpp
include $(BUILD_SHARED_LIBRARY)
Try changing your syntax slightly
I believe the error is the miss-use of the '->' operator
"
{
return env->NewStringUTF("Hello from JNI !");
}
try casting env as a pointer like so
{
return (*env)->NewStringUTF(env, str);
}
where str is a predefined string such as your hello message.
check this post as a cross reference: Do I need to clean up the char* passed to NewStringUTF?
I am trying to build android application using native code so i want to test if ndk runs successfully.When i try to run my first hello world project
log cat says,
01-21 23:30:06.780: E/AndroidRuntime(939): FATAL EXCEPTION: main
01-21 23:30:06.780: E/AndroidRuntime(939): java.lang.UnsatisfiedLinkError:
Native method not found: com.example.ndktesting.MainActivity.invokeNativeFunction:()Ljava/lang/String;
I checked some stackoverflow answers but could not find my answer.Here is my code for java and c.I am using android ndk r8d version.
//ndktest.c
#include <string.h>
#include <jni.h>
extern "C"{
JNIEXPORT jstring JNICALL Java_com_example_ndktesting_ndktest_MainActivity_invokeNativeFunction(JNIEnv* env, jobject thiz)
};
JNIEXPORT jstring JNICALL Java_com_example_ndktesting_ndktest_MainActivity_invokeNativeFunction(JNIEnv* env, jobject thiz){
return (*env)->NewStringUTF(env, "Hello from native code!");
}
Here is my MainActivity java code:
package com.example.ndktesting;
public class MainActivity extends Activity {
//declare the native code function - must match ndktest.c
private native String invokeNativeFunction();
public native String unimplementedinvokeNativeFunction();
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndktest");
}
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this is where we call the native code
String hello = invokeNativeFunction();
new AlertDialog.Builder(this).setMessage(hello).show();
}
}
Android make file code:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := ndktest
LOCAL_SRC_FILES := ndktest.c
include $(BUILD_SHARED_LIBRARY)
Your package/class names do not match.
JNIEXPORT jstring JNICALL Java_com_example_ndktesting_ndktest_MainActivity_invokeNativeFunction(JNIEnv* env, jobject thiz)
Would be a method in the class
com.example.ndktesting.ndktest.MainActivity
However your actual code
package com.example.ndktesting;
public class MainActivity extends Activity
causes it to look for
com.example.ndktesting.MainActivity.invokeNativeFunction
without the "ndktest"
Once you make the names match it should either work, or expose the next issue.
I got a crash when i call my native functions in my android application here is my code :
lib libo=new lib();
public void onPreviewFrame(byte[] data, Camera camera)
{
int s;// where w and h are width and height are the parameters of the camera
s=libo.getdata(data);/: and getdata is my native function
}
my getdata.c :
#include "getdata.h"
JNIEXPORT int JNICALL JAVA_android_video8_libo_som
(JNIEnv* env, jobject obj,jbyte* data)
{
return (data[1]);
}
getdata.h :
#include <jni.h>
#ifndef _Included_android_video8_lib
#define _Included_android_video8_lib
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT int JNICALL JAVA_android_video8_libo_som(JNIEnv* env, jobject obj, jbyte*);
#ifdef __cplusplus
}
#endif
#endif
Android.mk :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := opcv
LOCAL_SRC_FILES := getdata.c
include $(BUILD_SHARED_LIBRARY)
and the class where i call the lib :
package android.video8;
public class libo {
static {
System.loadLibrary("opcv");
}
public native static int som(int s);
}
the library is generated without a problem but the exécution of the apps give me a crash
i don't no where ehe error is
thanks
Seems there're some errors in your question. Anyway, you're using wrong prototypes for JNI functions. You should use these signatures:
JNIEXPORT
jint JNICALL JAVA_android_video8_libo_getData(JNIEnv*, jclass, jbyteArray);
JNIEXPORT
jint JNICALL JAVA_android_video8_libo_som(JNIEnv*, jclass, jint);
And use javah tool every time you change native method's prototype.