Building android shared library and calling with Java Native Access (JNA)

in utopian-io •  7 years ago  (edited)

Overview

In previous tutorial we learned how to use Java Native Access (JNA) library to call native method this native method is availabe in android prebuild shared library (libc). In this tutorial we will create our own C++ shared library and call with JNA library.

This post covers

  • Creating Android Studio project
  • Configuring JNA AAR library
  • Creating C++ shared library
  • Calling C++ shared library in Java
  • Output

Requirements

  • Android Studio 3.0 or higher
  • Android NDK

Difficulty

  • Intermediate

Guide

1. Creating Android Studio project

Create new android project and change Application name you can also change Company domain and Package name according to requirements, select Include C++ support and click next

p1.png

Select minimum SDK version and click next

p2.png

Select Empty Activity and click next

p3.png

Change Activity Name and Layout Name according to requirements and click Next

p4.png

Select C++ Standard as Toolchain Default and click Finish to create project

p5.png

2. Configuring JNA AAR library

Download jna.aar and
create New Module and select Import JAR/AAR Package and click next

p7.png

Select jna.aar file from file system and click Finish

p8.png

jna module added to project, open build.gradle file and add jna module under dependencies

dependencies {
    compile project(':jna')
    ....
    ....
}

p9.png

3. Creating C++ shared library

In this section we will create very simple math library in C++ which will perform basic math operations such as add, subtract, multiply and divide. Open the file native-lib.cpp which is in cpp folder
at the time of writing contents of this file are

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

extern "C"
JNIEXPORT jstring JNICALL
Java_com_faob_t2_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

As we can see for a very simple method which just returns string, a very complex code has been generated with long method name and complex arguments types. Replace this complex code with a very simple code which does exactly the same thing

extern "C" {
    char* libName(){
        return (char *) "My Math Shared Library";
    }
}

As we can see code is very simple and readable and is easy to maintain. Return type of this method is pointer to char which is standard way to declare string in C++. We don't need complex JNI types and long method names this is one of the power JNA gives us. Lets add some more methods which performs basic math operations complete code is

extern "C" {
    int add(int a, int b) {
        return a + b;
    }

    int subtract(int a, int b) {
        return a - b;
    }

    int divide(int a, int b) {
        return a / b;
    }

    int multiply(int a, int b) {
        return a * b;
    }

    char* libName(){
        return (char *) "My Math Shared Library";
    }
}

Since we are using C++ we must wrap all methods in extern "C" block to avoid name mangling. First four methods returns basic math operations results and fifth method libName just returns string which is name of our library. As we can see this code is much simpler, easy to maintain and understand, equivalent JNI code for these methods will be complex and difficult to maintain this is one of many advantages JNA library gives us.

4. Calling C++ shared library in Java

Open MainActivity.java and replace old code with this new code

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.sun.jna.Native;

public class MainActivity extends AppCompatActivity {

    //loading native library
    static {
        Native.register(MainActivity.class, "native-lib");
    }

    //native methods signatures
    public native int add(int a, int b);
    public native int subtract(int a, int b);
    public native int divide(int a, int b);
    public native int multiply(int a, int b);
    public native String libName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //calling native methods
        System.out.println("add: " + add(4, 2));
        System.out.println("subtract: " + subtract(4, 2));
        System.out.println("divide: " + divide(4, 2));
        System.out.println("multiply: " + multiply(4, 2));
        System.out.println(libName());
    }
}

There are three steps

1. Loading shared library
static {
    Native.register(MainActivity.class, "native-lib");
}

First argument to Native.register() method is the class in which we defined our native methods and 2nd argument is the name of native shared library. Name of shared library is native-lib we can change this default name in CMakeLists.txt file which is available in app folder. Loading should be done in static block which will load shared library during class loading time.

2. Declaring native methods signatures
native int add(int a, int b);
native int subtract(int a, int b);
native int divide(int a, int b);
native int multiply(int a, int b);
native String libName();

Mapping C++ functions in Java is very simple first four C++ methods are almost same in Java and fifth C++ method which return pointer to char which is String in java. we have to add native keyword which tells compiler that method is implemented in native code.

3. Calling native methods
System.out.println("add: " + add(4, 2));
System.out.println("subtract: " + subtract(4, 2));
System.out.println("divide: " + divide(4, 2));
System.out.println("multiply: " + multiply(4, 2));
System.out.println(libName());

Calling native methods is same as calling other java methods.

5. Output

Output can be seen in Logcat window.

p11.png

Conclusion

With latest Android Studio versions it becomes very easy to add native code in android project and with JNA library it becomes super simple to call native code.

Code

Project is available on github. Clone repo and open project name T2.



Posted on Utopian.io - Rewarding Open Source Contributors

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @kabooom I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x