Jni Tutorial for Android

Jni Tutorial for android

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.

How do I make a JNI hello world program in Android Studio?

Use Android Studio 4.0 click to File -> New -> New Project scroll to bottom and select Native C++

Sample Image

How to create JNI android project in Eclipse

http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/

This is a great tutorial to start with NDK.

Ok Here is the code Activity--

package com.example.ndk;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;

public class MainActivity extends Activity {

static {
System.loadLibrary("NDK");
}

// declare the native code function - must match ndkfoo.c
private native String invokeNativeFunction();

@Override
public 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();
}

}

NDK.cpp

#include <string.h>
#include <jni.h>

jstring Java_com_example_ndk_MainActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {

return (*env)->NewStringUTF(env, "Hello from native code!");

}

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

# Here we give our module name and source file(s)
LOCAL_MODULE := NDK
LOCAL_SRC_FILES := NDK.c

include $(BUILD_SHARED_LIBRARY)

Put Android.mk and NDK.cpp in jni folder
Now build the library using cygwin (if you are developing on window), same as mention in the example. and run it.

How to get app package name or applicationId using JNI android

Yes, it's possible. Android is based on Linux, we can obtain a lot of information in user space provided by kernel.

In your example, the information stored here /proc/${process_id}/cmdline

We can read this file, and get the application id.

See a simple example

#include <jni.h>
#include <unistd.h>
#include <android/log.h>
#include <stdio.h>

#define TAG "YOURAPPTAG"

extern "C"
JNIEXPORT void JNICALL
Java_com_x_y_MyNative_showApplicationId(JNIEnv *env, jclass type) {

pid_t pid = getpid();
__android_log_print(ANDROID_LOG_DEBUG, TAG, "process id %d\n", pid);
char path[64] = { 0 };
sprintf(path, "/proc/%d/cmdline", pid);
FILE *cmdline = fopen(path, "r");
if (cmdline) {
char application_id[64] = { 0 };
fread(application_id, sizeof(application_id), 1, cmdline);
__android_log_print(ANDROID_LOG_DEBUG, TAG, "application id %s\n", application_id);
fclose(cmdline);
}
}

How to add JNI (C/C++ native code) to existing Android Studio project

Follow this steps from your existing project:

1. Modify build.gradle (Module app) to look like this (a lot changes!):

    apply plugin: 'com.android.model.application'

model {
android.signingConfigs {
create ("myConfig") {
keyAlias '--your-key-alias--'
keyPassword '--key-password--'
storeFile file('--/path/to/keystore.jks--')
storePassword '--store-password--'
}
}
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'

defaultConfig {
applicationId "--your.app.name--"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled true
proguardFiles.add(file('proguard-android-optimize.txt'))
proguardFiles.add(file('proguard-rules.pro'))
signingConfig = $("android.signingConfigs.myConfig")
}
}
ndk {
moduleName "--c-file--"
ldLibs.addAll(["android", "log"])
}

}
android.dexOptions {
javaMaxHeapSize "2048m"
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.3.1'
}

You can copy/paste the above code and modify at least the values with "--value--" to match yours.

2. Modify build.gradle (Project)

where it says something like this:

dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}

to this:

dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.9.3'
}

The number in my example 0.9.3 is the latest version of gradle-experimental to be found here. Eventually change your gradle version in gradle-wrapper.properties to the version recommended by Android Studio if you did not already.

3. Move your proguard settings file

proguard-android-optimize.txt to app/proguard-android-optimize.txt

4. Add the call from java

like this

static {
System.loadLibrary("--c-file--");
}
private native byte my_jni(Context context, byte[] mByte, int i);

changing to your needs. The example above loads the c-file (write it without the extension) - the same one declared in the gradle file, and calls the function my_jni, passing the application's Context, some byte array and some int, expecting that the functions returns a byte.

5. Create the function in JNI:

Now the name of your function is highlighted in red - allow Android Studio to create it Create function ... with clicking on the red lamp on the row. This creates the function in your c file and changes focus to it.

Done

Further reading here.

Tips:

  • Take care to free everything you malloc, ReleaseByteArrayElements for every GetByteArrayElements and so on

  • Take care how to properly return some dangerous values from C to Java, like arrays and Strings

How to create a Java Library (API) with native code via JNI

Well, your Library will contain both the .jar file with the java wrapper code as well as the native files (.so if you're on linux based, or .dll if you're on windows).

Here's where the fun begins :

Because native is compiled in processor assembly language you will have to compile the .so for all your supported target (eg for all android with native support since like forever):
armv5, armv7, armv7s , arm64

Now, you will have to provide an archive with all the above.

This is the case where you want a stand alone library, without providing the code to the developer.

If you can provide the code,then you don't need to worry about different architectures.

Android JNI - Call function on Android UI thread from C++

As @Elviss has mentioned - to post your code to main thread you should use Looper. Actually this may be done without extra coping with JNI and creating of custom java.lang.Runnable and posting it via complicated JNI stuff.

Android NDK offers extremely lightweight and efficient way to post your native code to the arbitrary looper. The key point is that you should provide arbitrary file descriptor to the looper and specify what file events you are interested in (input, output, so on). Under the hood looper will poll that file descriptor and once event becomes available - it runs your callback on proper thread.

There is the minimal example (no error checks and teardowns):

#include <android/looper.h>
#include <unistd.h>

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "sergik", __VA_ARGS__)

static ALooper* mainThreadLooper;
static int messagePipe[2];

static int looperCallback(int fd, int events, void* data);

void someJniFuncThatYouShouldCallOnceOnMainThread() {
mainThreadLooper = ALooper_forThread(); // get looper for this thread
ALooper_acquire(mainThreadLooper); // add reference to keep object alive
pipe(messagePipe); //create send-receive pipe
// listen for pipe read end, if there is something to read
// - notify via provided callback on main thread
ALooper_addFd(mainThreadLooper, messagePipe[0],
0, ALOOPER_EVENT_INPUT, looperCallback, nullptr);
LOGI("fd is registered");

// send few messages from arbitrary thread
std::thread worker([]() {
for(char msg = 100; msg < 110; msg++) {
LOGI("send message #%d", msg);
write(messagePipe[1], &msg, 1);
sleep(1);
}
});
worker.detach();
}

// this will be called on main thread
static int looperCallback(int fd, int events, void* data) {
char msg;
read(fd, &msg, 1); // read message from pipe
LOGI("got message #%d", msg);
return 1; // continue listening for events
}

This code produces next output:

06-28 23:28:27.076 30930-30930/? I/sergik: fd is registered
06-28 23:28:27.076 30930-30945/? I/sergik: send message #100
06-28 23:28:27.089 30930-30930/? I/sergik: got message #100
06-28 23:28:28.077 30930-30945/? I/sergik: send message #101
06-28 23:28:28.077 30930-30930/? I/sergik: got message #101
06-28 23:28:29.077 30930-30945/? I/sergik: send message #102
06-28 23:28:29.078 30930-30930/? I/sergik: got message #102
06-28 23:28:30.078 30930-30945/? I/sergik: send message #103
06-28 23:28:30.078 30930-30930/? I/sergik: got message #103
06-28 23:28:31.079 30930-30945/? I/sergik: send message #104
06-28 23:28:31.079 30930-30930/? I/sergik: got message #104
06-28 23:28:32.079 30930-30945/? I/sergik: send message #105
06-28 23:28:32.080 30930-30930/? I/sergik: got message #105
06-28 23:28:33.080 30930-30945/? I/sergik: send message #106
06-28 23:28:33.080 30930-30930/? I/sergik: got message #106
06-28 23:28:34.081 30930-30945/? I/sergik: send message #107
06-28 23:28:34.081 30930-30930/? I/sergik: got message #107
06-28 23:28:35.081 30930-30945/? I/sergik: send message #108
06-28 23:28:35.082 30930-30930/? I/sergik: got message #108
06-28 23:28:36.082 30930-30945/? I/sergik: send message #109
06-28 23:28:36.083 30930-30930/? I/sergik: got message #109

As you see from pid-tid pairs - messages are received on main thread. And of course you may send something more complicated than one-byte messages.

Where can I get the complete list of JNI function for NDK with Android Studio?

Please refer this following link :

http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html



Related Topics



Leave a reply



Submit