Android Studio JNI with C++ UnsatisfiedLinkError - android

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.

Related

NDK for beginner : where/how to add source files?

I'm trying to use the NDK, and I've been working with official samples to get started. I've managed to get the "Hello JNI" sample working :
https://github.com/googlesamples/android-ndk/tree/master/hello-jni
(I work with Android Studio)
But I don't know how to add source files to the project. So, for example, the JNI function provided is (I removed macros that aren't useful for this) :
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
Let's say I want to get the string from a C function "getString()", defined as below:
const char* getString()
{
return "Hello from getString()";
}
//Then, JNI function becomes
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, getString());
}
If I create a getString.h where I declare the function, and put the implementation in my current and only one source file, everything works like a charm. So, headers do work.
However, If I create a GetString.c file where I put the implementation, my code stops compiling. I do understand it's because GetString.o doesn't get linked (or even compiled ? I don't know), but I have no idea about how to tell Android Studio to compile both hello-jni.c (sample's source fil) and GetString.c
Should I get my hands dirty and modify gradle files ?
I also heard about a file called Android.mk which acts like a makefile, but I haven't found it in the project. If it's mandatory, should I create it, and what to put in it ? If it's not, how does the IDE knows he must build hello-jni.c ? (AKA "how did the project get configured before I modified it")
If you need any information about java-side things or gradle scripts, just have a look on the github link :)
Well, a bit of testing was enough to confirm what I thought. I just had to create Android.mk :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := hello-jni.c, GetString.cpp
LOCAL_MODULE := hello-jni
include $(BUILD_SHARED_LIBRARY)

How compile c++ project via Android NDK

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.

Linking .a compiled library and own shared library Android NDK r8b

I'm encountering an issue with linking C libraries in my Android project using the Android NDK r8b.
I built with the toolchain for ARM the cURL library (no SSL) and it provided me a libcurl.a file and a libcurl.so.4.2.0 one.
I also created a C file to provide functions to my Java code and to use the cURL library.
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= libcurl
LOCAL_SRC_FILES := libcurl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := curljni
LOCAL_SRC_FILES := curljni.c
LOCAL_STATIC_LIBRARIES := libcurl
include $(BUILD_SHARED_LIBRARY)
and now my C file
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
jstring Java_test_curljni_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz)
{
CURL *curl;
CURLcode
......
}
When I try to build with the ndk-build command from my project folder, here's the output error :
Compile thumb : curljni <= curljni.c
jni/curljni.c: In function 'Java_test_curljni_MainActivity_stringFromJNI':
jni/curljni.c:8:3: error: unknown type name 'CURL'
jni/curljni.c:9:3: error: unknown type name 'CURLcode'
jni/curljni.c:11:8: warning: assignment makes pointer from integer without a cast [enabled by default]
jni/curljni.c:13:28: error: 'CURLOPT_URL' undeclared (first use in this function)
jni/curljni.c:13:28: note: each undeclared identifier is reported only once for each function it appears in
/cygdrive/c/android-ndk-r8b/build/core/build-binary.mk:252: recipe for target `obj/local/armeabi/objs/curljni/curljni.o' failed
make: *** [obj/local/armeabi/objs/curljni/curljni.o] Error 1
I've tried many things within the Android.mk file, nothing successful. Using a PREBUILT_SHARED_LIBRARY doesn't help because it requires a .so file only and changing the extension from .so.4.2.0 to .so just tells me that the format is not supported when building ...
One thing I'm not sure about if whether I have to include the headers in my C file, but when I do it, it ofcourse don't find them.
As a note, when I build with only the curl library declared in my Android.mk file (the shared library with the C file is ommitted) then nothing is created in the libs folder !
Thanks in advance for your help !
EDIT ::::
Actually it did work mbrenon (I've tried it millions time and now it works, no idea what's different), but now I have
c:/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../. ./arm-linux-androideabi/bin/ld.exe: cannot find ./obj/local/armeabi/libcurl.a: Permission denied
I'm using Cygwin, could that be why I encounter permission issues ?
I manage to get around it when the .so and the .a are created, returning the permission error, chmod on it and running the ndk-build again, but that seems a bit rough !
Plus now none of my curl functions can be reached ("undefined reference to (function)").
$ ../../../ndk-build
SharedLibrary : libcurljni.so
./obj/local/armeabi/objs/curljni/curljni.o: In function `Java_test_curljni_MainActivity_stringFromJNI':
C:\android-ndk-r8b\apps\curljni\project/jni/curljni.c:12: undefined reference to `curl_easy_init'
C:\android-ndk-r8b\apps\curljni\project/jni/curljni.c:14: undefined reference to `curl_easy_setopt'
C:\android-ndk-r8b\apps\curljni\project/jni/curljni.c:15: undefined reference to `curl_easy_perform'
C:\android-ndk-r8b\apps\curljni\project/jni/curljni.c:17: undefined reference to `curl_easy_cleanup'
collect2: ld returned 1 exit status
/cygdrive/c/android-ndk-r8b/build/core/build-binary.mk:378: recipe for target `obj/local/armeabi/libcurljni.so' failed
make: *** [obj/local/armeabi/libcurljni.so] Error 1
and my curljni.c is the following
jstring Java_test_curljni_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz)
{
CURL *curl;
CURLcode res;
char buffer[10];
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "yahoo.com");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(res == 0)
return (*env)->NewStringUTF(env, "0 response");
else
sprintf(buffer,"code: %i",res);
return (*env)->NewStringUTF(env, buffer);
}
else {
return (*env)->NewStringUTF(env, "no curl");
}
}
I made sure every needed function is declared in the curl.h
Yes, you do have to include the Curl headers in your C file. To allow ndk-build to find these header files at link time, you'll have to add their path using LOCAL_EXPORT_C_INCLUDES:
include $(CLEAR_VARS)
LOCAL_MODULE:= libcurl
LOCAL_SRC_FILES := libcurl.a
LOCAL_EXPORT_C_INCLUDES := /* put the path to the Curl headers here */
include $(PREBUILT_STATIC_LIBRARY)
This will automatically add the path to the headers in all the targets requiring libcurl, and it should build and link.

Android std and stl support

I am playing with android ndk. I am using Window Vista with cygwin (latest version). I compiled and launched the hello world jni sample on my phone. It is working. The code is (is a .cpp file):
#include <string.h>
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis);
};
jstring Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis)
{
return env->NewStringUTF("Hello from native code!");
}
I wanted to add some modifications, just to play with it a bit:
#include <algorithm>
and then, in the function above, i added:
int a;
a=std::min<int>(10, 5);
but the compiler says that it cannot find the file 'algorithm' and that min() is not part of std.
After a bit of searching, i have found that the android ndk has a gnu-libstdc++ directory with all the std files needed. Reading the NDK docs, i have learned that usint std::* should work without any modification to the code (if one include the proper header files). But it seems that gcc on cygwin is not able to find the needed files.
What are the steps to do in order to be able to use std and stl within a .cpp file in an android ndk app?
From NDK r5's docs/CPLUSPLUS-SUPPORT.html:
By default, the headers and libraries for the minimal C++ runtime system
library (/system/lib/libstdc++.so) are used when building C++ sources.
You can however select a different implementation by setting the variable
APP_STL to something else in your Application.mk, for example:
APP_STL := stlport_static
To select the static STLport implementation provided with this NDK.
Value APP_STL values are the following:
system -> Use the default minimal C++ runtime library.
stlport_static -> Use STLport built as a static library.
stlport_shared -> Use STLport built as a shared library.
gnustl_static -> Use GNU libstdc++ as a static library.
Which NDK are you using? Have you tried compiling one of the sample applications that utilize the STL such as test-libstdc++?

Jni Tutorial for android [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
Hi, can anyone suggest me some good resources to learn JNI for Android and some good JNI Tutorials?
Tutorial for ECLIPSE
Here is first and second small tutorials, but if you want to write a simple program that uses JNI , you may continue reading :)
Create Android application project , Once your project has been created, you’ll need to create a new folder inside the top level of the project. To do this right click on your project name → New → Folder. Name this folder jni. Than add class with name SquaredWrapper. add these code in it
package org.edwards_research.demo.jni;
public class SquaredWrapper {
// Declare native method (and make it public to expose it directly)
public static native int squared(int base);
// Provide additional functionality, that "extends" the native method
public static int to4(int base)
{
int sq = squared(base);
return squared(sq);
}
// Load library
static {
System.loadLibrary("square");
}
}
Open terminal. You must compile these code for getting header file. At first call this command.
cd src # change into the source directory
javac -d /tmp/ org/edwards_research/demo/jni/SquaredWrapper.java
Than
cd /tmp
javah -jni org.edwards_research.demo.jni.SquaredWrapper
SO you'll have header file named org.edwards_research.demo.jni.SquaredWrapper in your tmp directory.
it must be something like this
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_edwards_research_demo_jni_SquaredWrapper */
#ifndef _Included_org_edwards_research_demo_jni_SquaredWrapper
#define _Included_org_edwards_research_demo_jni_SquaredWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_edwards_research_demo_jni_SquaredWrapper
* Method: squared
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_org_edwards_1research_demo_jni_SquaredWrapper_squared
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
change these name for some short one for your comfort, for example square.h. Copy this header file in the jni folder of your app. Than create square.c file in same folder, copy this in it.
#include "square.h"
JNIEXPORT jint JNICALL Java_com_example_android_1jni_1second_1demo_SquaredWrapper_squared
(JNIEnv * je, jclass jc, jint base)
{
return (base*base);
}
Add this in your MainActivity.java
int x = SquaredWrapper.to4(2);
x = x*2;
Add Android.mk file in jni folder with this body
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := squared
LOCAL_SRC_FILES := square.c
include $(BUILD_SHARED_LIBRARY)
It must create library from header and cpp files.
So you have only to do some configurations by looking on my first link
Now you can compile it , be sure that your library has created and your lib directory consist it.
Tutorial for Android Studio
Let's consider you have simple android application opened by Android Studio
step 1: open Your application by Android Studio
step 2: Download NDK and set the path to NDK in local properties of your application(below/above of android sdk path) like this ndk.dir=C\:\\Android\\android-ndk-r10e
P.S. for windows double // , for linux one /
step3: Add JNI folder in the app (right click on the app -> new -> folder -> JNI Folder)
step 4 Set up the Gradle by this way:
Add this code in app/build.gradle for starting NDK
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/libs'
}
tasks.withType(NdkCompile) { // disable automatic ndk-build call
compileTask -> compileTask.enabled = false
}
task ndkBuild(type: Exec) { // call ndk-build(.cmd) script
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'cmd', '/c', 'ndk-build.cmd', '-C', file('src/main').absolutePath
} else {
commandLine 'ndk-build', '-C', file('src/main').absolutePath
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
step 4:
Create files Android.mk and Application.mk in JNI folder of the app with this bodies:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_SRC_FILES := main.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
include $(BUILD_SHARED_LIBRARY)
In APP_ABI you choose which compilers to use. It
step 5:
We have to manually run NDK as we disable it from build.config. For creating com_example_nativedemo_app_MainActivit.h file in src\main\jn folder we have to run this command in terminal
javah -d .\jni -classpath C:\Intel\INDE\IDEintegration\android-sdk-windows\platforms\android-21\android.jar;..\..\build\intermediates\classes\debug com.example.mydemo.nativedemo.MainActivity
for windows cmd you have to give the full path of files.
For
step 6:
Add file main.cpp in JNI folder with this body:
#include <string.h>
#include <jni.h>
#include <vchat_cpptest_Hellojnicpp.h>
extern "C" {
JNIEXPORT jstring JNICALL
Java_vchat_cpptest_Hellojnicpp_stringFromJNI
(JNIEnv *env, jobject obj)
{
#ifdef __INTEL_COMPILER_UPDATE
return env->NewStringUTF("Hello from Intel C++ over JNI!");
#else
return env->NewStringUTF("Hello from default C++ over JNI!");
#endif
}
I would suggest downloading the ndk. Unzip it and browse the sample folder ndk codes. Start with the hello-jni and go further. It explains a lot with ease.
You can also browse these links and this while going through the code and keep coming back and forth.

Categories

Resources