I'm trying simple addition program in android ndk. But I'm getting the following exception -
java.lang.exceptionininitializererror
Java File-
public class MainActivity extends Activity {
private native void MyMethod(int a,int b);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyMethod(4,5);
}
static {
System.loadLibrary("native"); // here i'm getting exception
}
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := native
LOCAL_SRC_FILES := native.c
include $(BUILD_STATIC_LIBRARY)
native.c
#include <jni.h>
#include <string.h>
#include <android/log.h>
#define DEBUG_TAG "NDKSetupActivity"
void Java_com_example_additionndk_MainActivity_MyMethod(JNIEnv * env, jobject this, jint a,jint b)
{
jint c=a+b;
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "addition: %d", c);
}
I ran into this error once when running the sample ndk (hello-jni). It's because the android sdk version is not compatible (default of the example is 1.5). Try to switch the compatible sdk and modifiy manifest .
Another case is you haven't build the .c to .so. Use ndk-build from cygwin64.
Related
I'm new to NDK and JNI and not sure how to fix this error. I manually copy libMathFuncLib.so, mathFuncsLibs.cpp and MathFuncLibs.h files to Eclipse project. When I run this command 'ndk-build' and I get back 'workspace/test/jni/TestMath.cpp: error: 'Add' was not declared in this scope.'
Here is my folder structure:
-test
|__src
|__ExecuteTest.java
|__MainActivity.java
|__jni
|__Android.mk
|__Application.mk
|__TestMath.cpp
|__libs
|__armeabi
|__myLibs
|__armeabi
|__libMathFuncLib.so
|__myNatives
|__MathFuncLibs.cpp
|__MathFuncLib.h
Here is MathFuncLib.h file:
//This is static library example
#ifndef MathFuncLib_INCLUDED
#define MathFuncLib_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
class MyMathFunc
{
public:
static int Add(int a, int b);
static int Subtract(int a, int b);
static int Multiply(int a, int b);
static double Divide(int a, int b);
};
#ifdef __cplusplus
} // extern "C"
#endif
#endif
Here is MathFuncLib.cpp file:
#include "MathFuncLib.h"
int MyMathFunc::Add(int a, int b)
{
return a + b;
}
int MyMathFunc::Subtract(int a, int b)
{
return a - b;
}
int MyMathFunc::Multiply(int a, int b)
{
return a * b;
}
double MyMathFunc::Divide(int a, int b)
{
return a / b;
}
Here is MainActivity.java file:
package com.example.test;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;//to use TextView
import android.widget.GridLayout.LayoutParams;//to use LayoutParams
public class MainActivity extends AppCompatActivity {
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int retVal = 0;
ExecuteTest et = new ExecuteTest();
retVal = et.TestAdd();
TextView tv = new TextView(this);
LayoutParams lp = new LayoutParams();
lp.setMargins(150, 50, 200, 0);
tv.setLayoutParams(lp);
tv.setText(String.valueOf(retVal));
setContentView(tv);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Here is ExecuteTest.java file:
package com.example.test;
import android.util.Log;
public class ExecuteTest {
public int ReturnValue(){
return 50;
}
public native int TestAdd();
static
{
System.loadLibrary("MathFuncLib");
System.loadLibrary("Arithmetic");
Log.i ("ExecuteTest", "Shared Libs loaded");
}
}
Here is TestMath.cpp file:
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "../myNatives/MathFuncLib.h"
extern "C"
{
JNIEXPORT int JNICALL Java_com_example_test_ExecuteTest_TestAdd(JNIEnv *env, jobject obj)
{
__android_log_print(ANDROID_LOG_INFO, "Test", "Inside TestAdd()");
int retVal= Add(50,50);//Add(,) is a method inside MathFuncLib.so file
return retVal;
}
}
Here us my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MathFuncLib-prebuilt
LOCAL_SRC_FILES := ../myLibs/armeabi/libMathFuncLib.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Arithmetic
LOCAL_SRC_FILES := TestMath.cpp
LOCAL_LDLIBS := -llog -lz
include $(BUILD_SHARED_LIBRARY)
Here is Application.mk file:
APP_STL := gnustl_shared
Thanks.
This is the correct form for
Application.mk
APP_ABI := x86 ## -- set to whatever platform you need
APP_PLATFORM := android-9
APP_STL := stlport_static ## -- USE IT
.
As for Android.mk you will need 2, because I see you want to build a solution using two projects --
a native (non-JNI) library
2nd native (JNI) library, that loads the first and makes it available to JAVA through JNI
Application.mk should be duplicated.
.
Android.mk (the native part)
include $(CLEAR_VARS)
#
# --------------- C / C++ Project settings ---------------
#
LOCAL_PATH := _path_to__myNatives
# Application/Library Name
LOCAL_MODULE := MathFunc
# Project Source files
LOCAL_SRC_FILES := MathFuncLibs.cpp
# Compiler Flags
LOCAL_CFLAGS := -mfpu=neon
### THIS BIT BELOW IS IMPORTANT -- used so that projects that include this build output will find the correct headers ###
# Location of headers
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.
#
# ------------------------- .. ----------------------------
#
include $(BUILD_STATIC_LIBRARY)
.
You would be using Eclipse, so you can then find the output in _path_to__myNatives/obj/local/$(TARGET_ARCH_ABI)/libMathFunc.a. $(TARGET_ARCH_ABI) evaluates to x86 in this example.
Need to build once for your platform (specified in Application.mk).
.
Android.mk (the native JNI part )
replace "Static" with "Shared" (no quotes ofc)
#
# -------------- Dependant Static Libraries Linkage ---------------
#
include $(CLEAR_VARS)
LOCAL_PATH := _path_to__myNatives
LOCAL_MODULE := MathFuncLib ## can be different from the previous module name definition in Android.mk or can be the same
LOCAL_SRC_FILES := $(LOCAL_PATH)/obj/local/$(TARGET_ARCH_ABI)/libMathFunc.a
include $(PREBUILT_STATIC_LIBRARY)
#
# ------------------------- .. ----------------------------
#
#
# --------------- C / C++ Project settings ----------------
#
include $(CLEAR_VARS)
LOCAL_PATH := _path_to___jni
# Application/Library Name
LOCAL_MODULE := Arithmetic
# Project Source files
LOCAL_SRC_FILES := TestMath.cpp
# Compiler Flags
LOCAL_CFLAGS := -mfpu=neon
LOCAL_LDLIBS := -llog -lz
# Static Libraries
LOCAL_STATIC_LIBRARIES := MathFuncLib # must be exactly the same as in THIS .mk file
# Shared Libraries
#LOCAL_SHARED_LIBRARIES := MathFuncLib # must be exactly the same as in THIS .mk file
#
# ------------------------- .. ----------------------------
#
include $(BUILD_SHARED_LIBRARY)
Just want to share my fixed.
1) in my MyMathFunc.h file, I shouldn't use "extern C" because C does not support class. If wanting to use "extern C" then I have to remove class declaration.
2) need to change Android.mk and Application.mk files.
Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MathFuncLib
LOCAL_SRC_FILES := ../myLibs/armeabi/libMathFuncLib.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := MathFuncLib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../myNatives/
LOCAL_MODULE := Arithmetic
LOCAL_SRC_FILES := TestMath.cpp
LOCAL_LDLIBS := -llog -lz
#Tell it to build an APK
include $(BUILD_SHARED_LIBRARY)
Application.mk file:
APP_STL := gnustl_shared
I'm developing an image processing application using Opencv and android Ndk.
First I wrote my code in visual studio and there was no problem.
I have header roi.hpp and roi.cpp :
roi.hpp:
#ifndef ROI
#define ROI
#include <..\..\imgproc.hpp>
#include <..\..\opencv.hpp>
using namespace cv;
class My_ROI{
public:
My_ROI();
My_ROI(const My_ROI &my_roi);
My_ROI(Point upper_corner, Point lower_corner,Mat src);
Point upper_corner, lower_corner;
Mat roi_ptr;
Scalar color;
int border_thickness;
void draw_rectangle(Mat src);
};
#endif
roi.cpp:
#include "myImage.hpp"
#include <..\..\imgproc.hpp>
#include <..\..\opencv.hpp>
#include <..\..\highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "roi.hpp"
using namespace cv;
using namespace std;
My_ROI::My_ROI(const My_ROI &my_roi)
{
int i;
// allocate variables
My_ROI();
// copy values
operator = (my_roi);
}
My_ROI::My_ROI(){
upper_corner=Point(0,0);
lower_corner=Point(0,0);
}
My_ROI::My_ROI(Point u_corner, Point l_corner, Mat src){
upper_corner=u_corner;
lower_corner=l_corner;
color=Scalar(0,255,0);
border_thickness=2;
roi_ptr=src(Rect(u_corner.x, u_corner.y, l_corner.x- u_corner.x,l_corner.y- u_corner.y));
}
void My_ROI::draw_rectangle(Mat src){
rectangle(src,upper_corner,lower_corner,color,border_thickness);
}
and in another class I made a vector of My_ROI and use it with no problem, Like this:
vector <My_ROI> roi;
for (int j = 0; j<NSAMPLES; j++){
roi[j].draw_rectangle(m->src);
}
Then I ported my project to android I use roi.hpp and roi.cpp as external c++ files ,this is my android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_CAMERA_MODULES := on
OPENCV_INSTALL_MODULES := on
OPENCV_LIB_TYPE:=STATIC
include ../../jni/OpenCV.mk
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.cpp
LOCAL_SRC_FILES += ../../external_cpp/makegray.cpp
LOCAL_SRC_FILES += ../../external_cpp/roi.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../external_cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
application.mk:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
And finally in hello-jni.cpp file I want to use vector of roi:
#include <jni.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <opencv2/opencv.hpp>
#include "../../external_cpp/roi.hpp"
vector <My_ROI> roi;
void fillROIArray(MyImage *m,Mat& mRgb,Mat& mGray)
{
m->src=mRgb;
flip(m->src,m->src,1);//reverse the order of rows or cols in a matrix
// My_ROI *f1 = new My_ROI;
// roi.push_back(*f1);
roi.push_back(My_ROI(Point(m->src.cols/3, m->src.rows/6),Point(m->src.cols/3+square_len,m->src.rows/6+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/4, m->src.rows/2),Point(m->src.cols/4+square_len,m->src.rows/2+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/3, m->src.rows/1.5),Point(m->src.cols/3+square_len,m->src.rows/1.5+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/2, m->src.rows/2),Point(m->src.cols/2+square_len,m->src.rows/2+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/2.5, m->src.rows/2.5),Point(m->src.cols/2.5+square_len,m->src.rows/2.5+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/2, m->src.rows/1.5),Point(m- >src.cols/2+square_len,m->src.rows/1.5+square_len),m->src));
roi.push_back(My_ROI(Point(m->src.cols/2.5, m->src.rows/1.8),Point(m->src.cols/2.5+square_len,m->src.rows/1.8+square_len),m->src));
mGray=m->src;
}
void myMethod(Image &m)
{
for (int j = 0; j<NSAMPLES; j++){
roi[j].draw_rectangle(m->src);
}
}
but it makes error :
method draw_rectangle(...) couldn't be resolved!
I can access my roi object all members but when I make vector of this class I don't have access to its members!
I searched a lot about making vectors of custom class and It's several days I'm working to solve this problem but I couldn't.
any help really appreciate.
regards.
Finally I found solution ... maybe it's usefull for others .
I can access to vector's members like this :
for (int j = 0; j<NSAMPLES; j++){
((My_ROI)roi[j]).draw_rectangle(m->src);
}
I can access any vector's objects from any custom classes now ! :)
I found some similar questions, but their answers didn't help me. I went through this tutorial http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/ and get some problems with it.
My Android.mk file :
LOCAL_PATH := $(call my-dir)
MY_PATH := $(LOCAL_PATH)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
LOCAL_PATH := $(MY_PATH)
LOCAL_LDLIBS := -llog -ldl
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c
include $(BUILD_SHARED_LIBRARY)
And my c-class ndkfoo.c :
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <string.h>
#include <jni.h>
jstring Java_com_example_ocrrecognise_ndkfoo_MainActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
and MainActivity:
public class MainActivity extends Activity {
static {
System.loadLibrary("ndkfoo");
}
private native String invokeNativeFunction();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button button = (Button) findViewById(R.id.button_id);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
try{
String hello = invokeNativeFunction();
Log.i("string func", hello);
}catch (UnsatisfiedLinkError e)
{
e.printStackTrace();
}
//new AlertDialog.Builder(MainActivity.this).setMessage(hello).show();
}
});
}
But I've got
No implementation found for native Lcom/example/ocrrecognise/MainActivity;.invokeNativeFunction ()Ljava/lang/String;
java.lang.UnsatisfiedLinkError: invokeNativeFunction
at com.example.ocrrecognise.MainActivity.invokeNativeFunction(Native Method)
at com.example.ocrrecognise.MainActivity.access$0(MainActivity.java:14)
at com.example.ocrrecognise.MainActivity$1.onClick(MainActivity.java:24)
at android.view.View.performClick(View.java:2485)
at android.view.View$PerformClick.run(View.java:9080)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3687)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
My in the ndkfoo.c I put right package name. Help with it please.
In what package your Activity is in?
Please mind that is should be under com.example.ocrrecognise.ndkfoo.
How did you compile your c code?
Did you put the compile .so file under /libs/armeabi in your project?
From the error
No implementation found for native Lcom/example/ocrrecognise/MainActivity;.invokeNativeFunction
it appears that your main activity is in the package com.example.ocrrecognise. If you place it in package com_example_ocrrecognise_ndkfoo, it should work, since that is the prefix that you are using in declaring the function in your native code.
I'm working with android and trying to use some native code in my app.
Here is a skeleton of the application code:
package A.B;
/*
import statements
*/
public class C extends Activity{
public void onCreate(...){
....
foo();
....
}
public int foo(){
.....
data(a, b);
.....
}
public int data(a, b){
GetValues(a, b);
}
static{
System.loadLibrary("baz");
}
public native int GetValues(int[] a, int b);
}
the native method signature goes like this:
JNIEXPORT jint JNICALL
Java_A_B_C_GetValues(JNIEnv *env, jobject obj, jintArray arr, jint b){
....
....
}
while running the logcat shows up:
W/dalvikvm(799): No implementation found for native LA/B/C;.GetValues ([IJ)I
the ndk documentation doesnt strictly mention creating a header file, so i dont have one
the android.mk file's contents:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := baz
LOCAL_SRC_FILES := baz.cpp
include $(BUILD_SHARED_LIBRARY)
Thanks in advance.
Since your native file is a .cpp file, I am guessing that you will need to use extern "C". Why and Why
I have tried writing a jni call for the simple c code. when i try to install this on the phone running 2.3.3 it doesnt install, sometimes even if it installs then it is being force closed.Please help me with this. the code details are as follows:
The java code of which i generate the header file.
package com.hosa;
public class edgejava
{
static{
System.loadLibrary("edgejava");
}
public native int main();
}
the generated header file is as below
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hosa_edgejava */
#ifndef _Included_com_hosa_edgejava
#define _Included_com_hosa_edgejava
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hosa_edgejava
* Method: main
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_hosa_edgejava_main
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
the implementation of native function is as below
#include "com_hosa_edgejava.h"
#include <jni.h>
#include <cv.h>
#include <highgui.h>
using namespace cv;
JNIEXPORT jint JNICALL Java_com_pes_edgejava_main(JNIEnv *, jobject){
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;
namedWindow("edges",CV_WINDOW_AUTOSIZE);
for(;;)
{
Mat frame;
cap >> frame; // get a new frame from camera
cvtColor(frame, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
imshow("edges", edges);
if(waitKey(30) >= 0) break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
the android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include /home/srijith/android-opencv/OpenCV-2.3.1/share/OpenCV/OpenCV.mk
LOCAL_MODULE := edgejava
LOCAL_SRC_FILES := edgecpp.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
the application.mk
APP_MODULES := edgejava
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
the activity file is as follows
package com.hosa;
import android.app.Activity;
import android.os.Bundle;
public class Andedge2Activity extends Activity {
edgejava nativelib;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
nativelib= new edgejava();
int i=nativelib.main();
System.out.println("value returned to andedgeactivity "+i);
}
}
All necessary changes to the manifest has been done like mention of use of camera and permissions has been set.
Edit:
I have changed the com_pes_edgejava to com_hosa_edgejava_main but still not working...
Any other solutions ??????
Problem is in you Packname change your application package com.hosa to com_pes_edgejava.
In your JNI file you will see function(main) declaration like JNIEXPORT jint JNICALL Java_com_pes_edgejava_main()
Java_com_pes_edgejava_main
That's your issue.
hotveryspicy points out the obvious issue (ie that you have com_pes when you should have com_hosa). As for the fact it doesn't work still, I would suspect this comes down to the "using namespace cv". As a result you are declaring your JNI function inside the cv namespace which is not correct. This is one of the reasons that the using keyword is something to be wary of.
whats wrong with just putting cv:: on front of the calls to functions and definitions of structs/classes that are in that namespace? Its far better at self documenting that way anyway.