How compile c++ project via Android NDK - android

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.

Related

Android Studio JNI with C++ UnsatisfiedLinkError

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.

Unsatisfiedlinkerror: Unable to load custom NDK JNI library in Nfc system app

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!

Android NDK and JNI native method not found

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

Project containing jni file

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.

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