I am working setting up the NDK for my android project.
I have an android project with a textview that outputs to the emulator
"Output="
I have a native function called somefunc() that i add to this string and it throws an error stating.
E/AndroidRuntime(2242): java.lang.UnsatisfiedLinkError: Native method not found: com.ndktest.MainActivity.somefunc:()I
I have three files that I believe are needed. MainActivity.java , test.c, and Android.mk.
In test.c I have
#include <string.h>
#include <jni.h>
JNIEXPORT int JNICALL
Java_com_ndktest_MainActivity_somefunc(JNIEnv * env, jobject obj)
{
return 2;
}
And Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILE := test.c
include $(BUILD_SHARED_LIBRARY)
And MainActivity.java
package com.ndktest;
import com.ndktest.R;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
static
{
System.loadLibrary("test");
}
public native int somefunc();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = new TextView(getBaseContext());
tv.setTextSize(30);
String s = "Ouput="+somefunc();
tv.setText(s);
this.setContentView(tv);
}
}
I understand from the various guides online that spelling mistakes are the most common cause of this error. I have tried my best to check for a spelling mistake in the package and in the c function code and so far I don't see it. I also am able to run "ndk-build" on the makefile and it compiles without errors. It produces libtest and i load the library. I have tried a try catch around it and the try passes for the system load library. So i assume there is a spelling mistake or an error in how i named my c function. I have read that the c function should be called in Java_[package with underscores instead dots][java class][function name]. I think i am abiding by this. I apologize i the first half of question looks like a stereotypical "solve this for me" question. I just wanted the code there so it shows what the packages are called and what the make looks like.
Thank you
You can get the correct prototypes for your native functions by calling
javah -classpath bin/classes -d jni com.ndktest.MainActivity
from your source directory. This will create a header com_ndktest_MainActivity.h which can be included in your C file.
(BTW: if your native file is compiled as C++ you would need extern "C" {...})
Can you try changing from
JNIEXPORT int JNICALL
to
JNIEXPORT jint JNICALL
Related
I am using Android Studio 2.1.2 I am not using Experimental Plugin
Please Check the following files and Check the error I am getting.
I solved the issue. Edited file is as follows. They way I fixed it may not be the correct way as I am setting property to use deprecated way, but it works. Experimental plugin can still be unstable. I will try with experimental plugin soon.
build.gradle from Module
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
/*jni.srcDirs = [] not using this, I commented this. Please check SO links which explained when to use this and when not to use this*/
}
following 4 files are in jni folder of main
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := HelloJni.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
HelloJni.cpp
#include <jni.h>
#include <Header.h>
JNIEXPORT jstring JNICALL Java_com_example_m1035325_ndksampleapp_MainActivity_getStringFromJni(JNIEnv *env,jobject thiz)
{
env-> NewStringUTF ( "Hellofrom JNI!");
}
Header.h
#include <jni.h>;
using namespace std;
#ifndef HEADER
#define HEADER
extern "C" {
JNIEXPORT jstring JNICALL Java_com_example_m1035325_ndksampleapp_MainActivity_getStringFromJni(JNIEnv *env, jobject obj);
}
#endif //NDKSAMPLEAPP_HEADER_H
MainActicity.java
static
{
System.loadLibrary("mylib");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvHello=(TextView)findViewById(R.id.tvHello);
tvHello.setText(getStringFromJni());
}
public native String getStringFromJni();
Here when I hover on method getStringFromJni it shows Can't resolve corresponding JNI function
I have set NDK path in Project Structure and in Path environment variable too.
I am getting following error
Process: com.example.m1035325.ndksampleapp, PID: 12831
java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.example.m1035325.ndksampleapp.MainActivity.getStringFromJni() (tried Java_com_example_m1035325_ndksampleapp_MainActivity_getStringFromJni and Java_com_example_m1035325_ndksampleapp_MainActivity_getStringFromJni__)
at com.example.m1035325.ndksampleapp.MainActivity.getStringFromJni(Native Method)
I searched a lot on SO also but I am not getting what I missed?
No error now , above error is fixed. Please check my answer to this question.
I think the problem is in your Android.mk file:
LOCAL_SOURCE_FILE := HelloJni.cpp
AFAIK the Android build system doesn't use variable of that name. It should be:
LOCAL_SRC_FILES := HelloJni.cpp
One important change I made is in file gradle.properties, is as follows
android.useDeprecatedNdk=true
so its related to Android Studio version 2.1.2 , for this version experimental plugin is the default option to use and the approach I am using is deprecated.
I will be trying with experimental plugin soon.
I have written a small C program using JNI which I would like to call from inside the NFC system app, specifically the NfcDispatcher.java class. I have done the following so far:
Created a /jni directory inside the /AOSP/packages/apps/Nfc/ where I have written the following JNI code. Nfc/jni/ dir has 2 files, viz mycustomlib.c and Android.mk which are as follows
mycustomlib.c at
/AOSP/packages/apps/Nfc/jni/mycustomlib.c
#include <string.h>
#include <jni.h>
jstring Java_com_android_nfc_NfcDispatcher_gettagkey( JNIEnv* env, jobject thiz, jstring tagKey )
{
// do something
return tagKey;
}
Android.mk at /AOSP/packages/apps/Nfc/jni/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mycustomlib
LOCAL_SRC_FILES := mycustomlib.c
include $(BUILD_SHARED_LIBRARY)
I am calling the native method "gettagkey" from inside the NfcDispatcher.java file as follows.
NfcDispatcher.java at /AOSP/packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java
public class NfcDispatcher {
..
..
public static native String gettagkey(String tagKey);
..
static class DispatchInfo {
..
}
public boolean dispatchTag(Tag tag) {
..
..
Log.d(TAG, "NFC Key Tag from C code : " + gettagkey(sb.toString()));
..
}
..
static {
System.loadLibrary("mycustomlib");
}
}
Then we compile the C code using ndk-build -C path_to_c_code
and then we did a "make -j32" to compile the code changed in the Nfc system app
and then we flash the new system.img to the Nexus 7 device. The OS boot properly but we get the following error:
W/dalvikvm( 767): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lcom/android/nfc/NfcDispatcher;
E/AndroidRuntime( 767): at com.android.nfc.NfcDispatcher.<clinit>(NfcDispatcher.java:571)
E/AndroidRuntime( 767): at com.android.nfc.NfcService.<init>(NfcService.java:390)
E/AndroidRuntime( 767): at com.android.nfc.NfcApplication.onCreate(NfcApplication.java:43)
I have read all related question but I am still not sure what's happening. Does anyone have any clue? Thanks!
I have the feeling that the native library is not being loaded before the native call to the native method.
I would try to replace the gettagkey body, with the library load call, and then call the native method. Something like:
public static String gettagkey(String tagKey){
System.loadLibrary("mycustomlib");
gettagkeyNative(tagKey);
}
public static native String gettagkeyNative(String tagKey);
Don't forget to modify the native part:
#include <string.h>
#include <jni.h>
jstring Java_com_android_nfc_NfcDispatcher_gettagkeyNative( JNIEnv* env, jobject thiz, jstring tagKey)
{
// do something
return tagKey;
}
This solution would work, unless the system call to the native method requires that the gettagkey method is native.
Hope it helps!
I am trying to use libusb.so How can I make use of libusb library in my android project.
I have compiled libusb library for my android project using libusb source.Now I want to use the functions of newly generated library libusb.so in my code.
I've used following code..to just check the functions are loading or not..
What should I do to list device information in my app using libusb library.
code in jni directory..
libTest.c
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <sys/types.h>
JNIEXPORT jstring JNICALL Java_com_example_loadlibrary_MainActivity_libTask(JNIEnv* env, jobject obj)
{
if( libusb_init(NULL) )
return (*env)->NewStringUTF(env, "Library Loaded Successfuly!");
else
return (*env)->NewStringUTF(env, "Can not load library........");
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_MODULE := libusb-1.0
LOCAL_SRC_FILES := libusb-1.0.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libTest
LOCAL_SRC_FILES := libTest.c
include $(BUILD_SHARED_LIBRARY)
libusb-1.0.so
and src contains this java file:
MainActivity.java
package com.example.loadlibrary;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = new TextView(this);
tv.setText(libTask());
setContentView(tv);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
private native String libTask();
static{
System.loadLibrary("usb-1.0");
System.loadLibrary("libTest");
}
}
but It shows error in ndk compilation:
**error: undefined reference to 'libusb_init'
collect2: ld returned 1 exit status
make: [obj/local/armeabi/libTest.so] Error 1*
it shows that function is not defined in my code.
So how I will be able to get all the functions get working....
and atlast if I do
replace:
if( libusb_init(NULL) )
with:
if(1)
all files are generated but shows this error:
recipe for target Loadlibrary.exe' failed makefile /Loadlibrary/Debug line 31 C/C++ Problem
undefined reference to_WinMain#16' Loadlibrary line 39, external location: \usr\src\debug\cygwin-1.7.17-1\winsup\cygwin\lib\libcmain.c C/C++ Problem
make: * [Loadlibrary6.exe] Error 1 Loadlibrary C/C++ Problem
First load your libraries and then use function inside it
static{
System.loadLibrary("usb-1.0");
System.loadLibrary("libTest");
}
public final static native String libTask(String st); //libTask is returning a string also...
.so files are in "jni" folder so first check that after build are they created in "libs/armeabi" folder also??
What I used to build with NDK and libusb support is the following: Add into you Android.mk LOCAL_LDLIBS :=-L/path/to/your/compiled/libusb.so -lusb Give it a try. Hope this helps.
I have small C++ library project with one class.
class Test
{
public:
Test(){};
~Test(){};
int SomeFunc() { return 5; }
}
I can build this class via Android NDK. (Question 1).
I can use .so file into Java application. How I can call SomeFunc method from Java code (Question 2).
Here are the steps:
1.) Create Android.mk in the project's "jni" folder:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main_jni
LOCAL_CFLAGS :=
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS :=
include $(BUILD_SHARED_LIBRARY)
2.) Create main.cpp in the "jni" folder:
#include <jni.h>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
class Test {
public:
Test(){};
~Test(){};
int SomeFunc() { return 5; }
};
jint Java_com_example_activity_MainActivity_SomeFunc(JNIEnv *env, jobject thiz)
{
Test *test = new Test();
return test->SomeFunc();
}
#ifdef __cplusplus
}
#endif
3.) Add a call to load the library in your calling activity (MainActivity.java in this example):
static {
System.loadLibrary("main_jni");
}
4.) Define the native function in the calling activity:
native int SomeFunc();
5.) Call it from the activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text = (TextView) this.findViewById(R.id.text);
text.setText(String.valueOf(SomeFunc()));
}
6.) Run the "ndk-build" command from the project's root folder (Note: refresh the project in Eclipse after this step)
7.) Re-build and run the application
I'm not sure I understand the questions correctly but this link could be useful to you.
I'm personally do not know much of C except for the very basics, but I look forward to getting to more C with the NDK.
Whatever code you write in c you need to define it like java_urpackagename_class_methodname then before using this code u need to first create a native method in java class like public native int ABC(); telling it that you are going to use this method.To use it do create an Android.mk or Application.mk as per your need. .so will help your java class know ,what your c code wants to do.
I am trying to import an android project to my Eclipse.
When i run this project, i got an error, "library is null".
I figured out that this project was different, it contain a file named "jni". My library is in that file.
I guess the library in this file was never compiled (i don't know why)
I have seen in some topic that i need to use NDK?
Did any one have a clear answer about this?
Refer the below links. link to download ndk sample 1 sample 2
Step1: First create a project then create a folder named jni in your project directory
Step2: Create addition.c file in jni folder and add the below lines.
#include "com_ndkadd_Addition.h"
JNIEXPORT jint JNICALL Java_com_ndkadd_Addition_messageFromNativeCode
(JNIEnv * env, jobject jObj,jint value1, jint value2)
{
return (value1 + value2);
}
Step3: Create Android.mk file in jni folder and the below code
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Addition
LOCAL_SRC_FILES := addition.c
include $(BUILD_SHARED_LIBRARY)
Step4: navigate to bin folder of your project from command prompt. type the below line and press enter.
javah -jni com.ndkadd.Addition
Step5: Move the created com_ndkadd_Addition.h file to jni folder.
Step6: Now Compiling the Native Code as below from command prompt.
location_of_ndk\project_name> location_of_ndk\ndk-build
Step7: below the code code for your activity and usage of created .so file in your libs folder.
public class Addition extends Activity {
TextView txtHello;
static
{
System.loadLibrary("Addition");
}
public native int messageFromNativeCode(int v1,int v2);
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView txtHello = new TextView(this);
txtHello.setText(""+messageFromNativeCode(5,5));
setContentView(txtHello);
}
}
Note:: Better to have NDK in the place where you have SDK and the project containing JNI in android-ndk-r8 folder.