I need some help to use the method "callMethod()" inside ".so" (shared library) in android studio.
My android studio version is 2.1.3.
I created jniLibs folder in "src/main/".
Then I created three folders inside jniLibs folder: (armeabi, armeabi-v7a, x86).
Then I put the .so library inside every mentioned folder.
After that, I updated the build.gradle as follows:
compile fileTree(dir: 'libs', include: ['*.jar','.so'])
In the MainActivity java class I wrote this:
static {
System.loadLibrary("SharedLibAndroid");
}
After that I don't know what should I do.
How do I call the method callMethod() from the .so library?
I searched a lot but I did't see full example how to do that.
I've added to my project new class and native method like below:
#SuppressWarnings("JniMissingFunction")
public class Test1Cpp {
static {
System.loadLibrary("Cpp");
}
public native String callMethod();
}
Then I can call the method inside .so shared library.
I faced another problem, which is my .so library didn't work with all platform mobiles.
The error is:
java.lang.UnsatisfiedLinkError: dlopen failed:
"/data/app/com.mysecondtestapp-1/lib/arm/libCpp.so" has
unexpected e_machine: 3
So, how to convert my .so library to work on all platform mobiles?
I assume that the library does load, otherwise you would get an exception, and I guess you would have mentioned it. So you need to declare the native method you would like to use from the library, and then call it. You can see a simple example here: Sample: hello-jni
The sample source code may be found here: Hello JNI.
Related
I am trying to create a Flutter application that will be utilizing MethodChannel to call some Java code using dart that will be calling a shared library written in C++.
I was able to compile a Java program that was linked to a C++ library using JNI and run it, However once I tried to import the files into Flutter, I run into errors that the path to the file.so Shared Library could not be found.
I am looking for help regarding how to configure Flutter and its Android files in order to be able to achieve this behaviour.
I will add the CMakeLists.txt I used in order to compile and link the .jar and .so.
CMakeLists.txt
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(shared_library_java_cpp VERSION 1.0.0 LANGUAGES CXX)
set(JAVA_AWT_LIBRARY NotNeeded)
set(JAVA_JVM_LIBRARY NotNeeded)
set(JAVA_INCLUDE_PATH2 NotNeeded)
set(JAVA_AWT_INCLUDE_PATH NotNeeded)
find_package(JNI REQUIRED)
find_package(Java REQUIRED)
include_directories(${JNI_INCLUDE_DIRS})
include(UseJava)
set(CMAKE_CXX_STANDARD 11)
set(CMALE_CXX_STANDARD_REQUIRED ON)
set(JAR_NAME JavaCPP)
set(JAVA_SOURCE_DIRECTORY "/Users/user/Desktop/Temp/com/example/javacpplib")
set(JAVA_SOURCE_FILES ${JAVA_SOURCE_DIRECTORY}/JavaCPP.java)
add_jar(${JAR_NAME} ${JAVA_SOURCE_FILES})
add_library(shared_library_java_cpp SHARED java_cpp.cpp java_cpp.def)
add_executable(java_cpp_exec java_cpp.cpp)
set_target_properties(shared_library_java_cpp PROPERTIES
PUBLIC_HEADER lib_java_cpp.h
VERSION ${PROJECT_VERSION}
SOVERSION 1
OUTPUT_NAME "java_cpp"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "MacOS_ID"
)
In addition to run the code in intelliJ I used this method to load the shared library:
static {
System.load("/Users/user/IdeaProjects/JavaCPP/src/lib_java_cpp.so");
}
I am not sure of what library I should load when running in flutter.
I have found a solution to this problem.
After creating a .jar file and a .so file, I added that .so to the folder android -> app -> src -> main -> jniLibs -> arm64-v8a
I then added this line:
android {
...
sourceSets {
...
main.jniLibs.srcDirs += 'src/main/jniLibs'
}
...
}
to the app/build.gradle file
and I added:
set(JNI_LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/app/src/main/jniLibs/${ANDROID_ABI})
add_library(lib_java_cpp
SHARED
IMPORTED)
set_target_properties(lib_java_cpp
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/lib_java_cpp.so)
...
to the android/CMakeLists.txt file.
finally I called System.loadLibrary("_java_cpp") in MainActivity to load the desired library and to be able to call the Java functions from the jar that use the C++ library. (the lib is added automatically after call to find the correct shared object)
I've checked here and it seems to be no answer for my particular question. I got to know that I one can use C .so library and refer the methods in it by somewhat overriding the library native methods like below:
#SuppressWarnings("JniMissingFunction")
public class MyNativeMethods {
static {
System.loadLibrary("libraryWithSoExtension");
}
public native boolean init();
}
My probelem is that I'd like to call the constructor in this lib. The lib contains only couple of classes, where each of them contains 1 or 2 methods. I see from here:
How to call methods on .so library in Android studio
that I do not need any h, c or jni (do I really?).
Questions:
Could you confirm that I do not need any JNI files to access native methods from .so file?
Can one actually access a constructor as described above and how does the importing work if it's possible
MAVEN/GRADLE - Is it correct that a will not work for .so file? And it's equivalent in gradle also?
Thank you in advance.
If you have a prebuilt .so file that implements some native methods, you don't need its sources to build your project in Android Studio.
The catch is that the names of native methods and classes that contain these methods are hardcoded, e.g. Java_com_example_test_MainActivity_stringFromJNI exported function in a shared library libmy.so is fit to
package com.example.test;
public class MainActivity extends Activity {
static {
System.loadLibrary("my");
}
public native String stringFromJNI();
}
and not some other Java class or method (there are tools to make such reverse engineering harder).
You can use the javah command to generate C declarations for your native methods, but it cannot reverse engineer the Java class that fits given library. But it will let you declare a native constructor, if you really want one.
Gradle plugin for Android Studio will pack the so files from src/main/jniLibs into your APK, unless you set a different jniLibs.srcDir directory in your build.gradle.
I am not sure whether this is what you are looking for, but take a look here:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo025
you will find there super simple code with C++ being called via JNI wrapper from Java.
Say an Android app uses a jar library and everything is working fine when the library is specified as a dependency:
dependencies {
...
...
compile 'org.example:example:1.1.1'
...
}
BUT : one of the classes in the org.example code needs to be tweaked.
One approach is to obtain the source code and put all of that in the java folder, and remove the module. When the tweak is made, that, and the entire library will be compiled.
Another approach is to make the tweak, compile, and replace the .class file within the .jar file.
Both of those methods have their drawbacks.
My question is: Is there an easier way to tweak code in a library?
When I tried just creating the package, placing the class that needed changing into the java folder, I got an error:
Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Lorg/example/ClassNeedingChange;
I just wondered if there was a trick to getting code in the Java folder to override whats in a library jar file.
Additional Info:
Although not stated specifically above, the class that needs tweaking is buried in the library and is referenced by the library's code; I don't call it directly. For the simple case where the class that needed tweaking is one that my code (and only my code) called directly, then it would be a simple matter of extending the class using the Java construct. But for this simple case, I would not need to post this question.
Extend the class that needs tweaked in your code, and override the appropriate method.
Class A extends TweakMe {
#Override
public void someTweakedMethod() {
//Do stuff
}
}
I am trying to transfer an android project from Eclipse to android studio. The project uses a special database called jsqlite. In this library there is a class called jsqlite.Database which has some native functions. When I mouse over those native function I get the message:
Cannot resolve corresponding JNI function Java_jsqlite_Database__1open
Reports native method declarations in Java where no
corresponding JNI function is found in the project
This message is for this native function:
private native void _open(String filename, int mode)
throws jsqlite.Exception;
There are 3 .so files inside the project in those paths:
app\libs\armeabi\libjsqlite.so
app\libs\armeabi-v7a\libjsqlite.so
app\libs\x86\libjsqlite.so
So my guess is that there are on the wrong path. I tried to move them to other positions with no success. Any ideas what to try next?
UPDATE
This is my projects structure:
>app
->manifest
->java
->com.myapp.data
->jsqlite
->jniLibs
->res
You are putting the libraries in the wrong folder.
This should be the correct path:
..\YourProject\app\src\main\jniLibs\armeabi\libjsqlite.so
..\YourProject\app\src\main\jniLibs\armeabi-v7a\libjsqlite.so
..\YourProject\app\src\main\jniLibs\x86\libjsqlite.so
I have the following Java native function
private static native void fillEnergyArrays(double currentTemp, double concNA, double concMG);
The function is implemented in C. The code has been tested and I have created a working dynamic library, libhyfiModel.jnilib, which I can use to call the method from a Java file, Temp.java. There are no problems in this case when I run the program with the one file. The method call works and returns the expected value.
The problem:
I am taking Temp.java and libhyfiModel.jnilib and trying to import them into a large IntelliJ IDEA project which uses Maven as a build manager. I have put my libhyfiModel.jnilib file in my correct directory so it loaded when the program executes. I double checked that it's loaded using this code in Temp.java:
static {
try {
System.loadLibrary("hyfiModel");
}
catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load\n" + e);
}
}
No exception is thrown here, so libhyfiModel.jnilib is found and loaded correctly, but when the native method is executed I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: ca.virology.baseByBase.DiffEditor.fillEnergyArrays(DDD)V
at ca.virology.baseByBase.DiffEditor.fillEnergyArrays(Native Method)
at ca.virology.baseByBase.DiffEditor.main(DiffEditor.java:266)
I have looked at the documentation here https://www.jetbrains.com/idea/help/configuring-module-dependencies-and-libraries.html and followed the instructions with no success.
So the dynamic library is being loaded and I have added the directory containing libhyfiModel.jnilib as a dependency but the method can not execute... What am I missing?
EDIT:
I created a new IntelliJ project with just Temp.java and I am able to call the native function with no errors, so I'm thinking there must be a problem with my project configurations. Any IntelliJ experts out there?
Figured it out. It wasn't a configuration error since the library was being loaded properly. The problem was with Temp.java package membership used in the IntelliJ project.
I had a Temp.h file that was generated using the command javah -jni Temp that contains the C function definitions for my native functions.
I didn't realize that the native function definitions in Temp.h are different when the Java file Temp.java has a specified package.
I found my answer at Another JNI, C++, DLL, UnsatisfiedLinkError <Native Method>
It is shown that the header files' function names change with package membership.