ANDROID JNILIBS
Understanding jnilibs in Android Development
In Android development, native code is typically written in languages like C or C++, and it’s integrated into Android apps using JNI (Java Native Interface). One important concept in this context is jnilibs, which refers to the native libraries used in the app to interface with JNI.
In this article, we'll explore what jnilibs are, how to use them in Android, and best practices to follow when working with native libraries in Android development.
What Are jnilibs?
In the Android ecosystem, jnilibs is a shorthand for Java Native Interface Libraries. These are the compiled shared libraries (e.g., .so files) that contain native code written in languages like C or C++. The native libraries are required when using JNI to enable Java code to interact with native code, such as calling functions written in C/C++ or accessing platform-specific features.
Typically, JNI libraries are stored in the jniLibs folder within your Android project. This folder is where you place the compiled shared libraries so that Android can access them during runtime.
How to Use jnilibs in an Android Project
Let’s walk through the process of integrating native libraries (jnilibs) into an Android project.
Step 1: Setting Up the jniLibs Folder
When you're using native code in Android, the first thing you need to do is add the compiled .so files to the correct location in your project directory.
-
Create a folder named
jniLibsunderapp/src/main/in your Android project. -
Inside the
jniLibsfolder, create subfolders for each platform architecture that you want to support. These subfolders should match the platform names, such as:armeabi-v7a(32-bit ARM architecture)arm64-v8a(64-bit ARM architecture)x86(Intel architecture)x86_64(64-bit Intel architecture)
For example:
app/src/main/jniLibs/armeabi-v7a/ app/src/main/jniLibs/arm64-v8a/ app/src/main/jniLibs/x86/ -
Place the appropriate shared libraries (
.sofiles) in the corresponding architecture subfolders. For example:app/src/main/jniLibs/armeabi-v7a/libnative-lib.soapp/src/main/jniLibs/arm64-v8a/libnative-lib.so
Step 2: Using jnilibs in Java Code
Once your .so files are placed in the jniLibs directory, you need to load these libraries in your Java code using the System.loadLibrary() function.
In your Java class (e.g., MainActivity.java), load the native library by calling System.loadLibrary("library_name"). The argument passed to this method should be the name of the shared library without the .so extension.
Here’s an example:
package com.example.myapp;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
// Declare the native method
public native String stringFromJNI();
// Load the native library (without the .so extension)
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Call the native method
String result = stringFromJNI();
System.out.println(result); // Output: "Hello from C++"
}
}
In the code above:
System.loadLibrary("native-lib")loads thelibnative-lib.soshared library. Android will automatically look for the appropriate.sofile based on the platform (e.g.,armeabi-v7a,arm64-v8a).
Step 3: Build and Run
- Build the project by clicking on Build > Make Project.
- Run the app on an Android emulator or physical device. When the app runs, it will load the native library and execute the corresponding native method.
Example of Using jnilibs with Multiple Architectures
Suppose you're developing an app that needs to support multiple architectures (e.g., ARM and x86). You would place your native-lib.so files into the corresponding subdirectories of the jniLibs folder:
app/src/main/jniLibs/armeabi-v7a/libnative-lib.so
app/src/main/jniLibs/arm64-v8a/libnative-lib.so
app/src/main/jniLibs/x86/libnative-lib.so
Android will automatically choose the correct .so file based on the device’s architecture during runtime. For instance, if the app is running on an ARM-based device, it will load libnative-lib.so from the armeabi-v7a folder.
Best Practices for Using jnilibs
While working with native libraries (jnilibs), here are some best practices to follow:
-
Use CMake or ndk-build:
- For compiling and building your C/C++ code, use CMake or ndk-build.
- Android Studio supports both build systems and will automatically generate the necessary
CMakeLists.txtorAndroid.mkfiles.
-
Handle Different Architectures:
- Make sure to include separate
.sofiles for each architecture your app supports (e.g.,armeabi-v7a,arm64-v8a,x86). - Use the
jniLibsfolder’s architecture-specific subfolders to organize your libraries properly.
- Make sure to include separate
-
Keep Library Sizes Manageable:
- Native libraries can increase your APK size, so ensure that you're only including the architectures you need.
- Consider using multidex or dynamic delivery if the size of your app becomes too large.
-
Test on Multiple Devices:
- Test your app on different device architectures to make sure the correct
sofiles are being loaded and the native code is functioning properly.
- Test your app on different device architectures to make sure the correct
-
Use ProGuard:
- If you're using ProGuard or R8 for minification, make sure to configure them correctly to preserve your native method signatures.
-
Fallback for Missing Libraries:
- Handle cases where a required native library might not be available on the device. You can use try-catch blocks to gracefully handle failures when loading libraries.
JNI and jnilibs Directory Structure Example
Here’s what your directory structure might look like when using jnilibs in an Android project:
app/
└─ src/
└─ main/
├─ java/
│ └─ com/
│ └─ example/
│ └─ myapp/
│ └─ MainActivity.java
├─ cpp/
│ └─ native-lib.cpp
└─ jniLibs/
├─ armeabi-v7a/
│ └─ libnative-lib.so
├─ arm64-v8a/
│ └─ libnative-lib.so
└─ x86/
└─ libnative-lib.so
In this structure:
native-lib.cppcontains the C/C++ source code.jniLibscontains the compiled.sofiles for different CPU architectures (armeabi-v7a,arm64-v8a,x86).
Conclusion
The jnilibs directory in Android is a crucial part of integrating native C/C++ code with your app using JNI. By placing the compiled shared libraries (.so files) in the appropriate subdirectories, Android can automatically load the correct native code based on the architecture of the device. This approach allows your Android app to leverage the power of native code while maintaining compatibility across different device architectures.
When working with native libraries in Android, make sure to handle architecture-specific libraries, test on multiple devices, and optimize the app’s size to ensure a smooth user experience.

0 Comments