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)
Related
I am trying to fork AndroidPdfViewer to replace its underlying library from PdfiumAndroid to android-pdfium.
My problem is, when I load AndroidPdfViewer and PdfiumAndroid in Android Studio, I can't get the project to work, even before changing anything.
The problem is PdfiumAndroid has JNI code that define many previously declared functions, but the linker can't link the definitions in C++ to the declarations in Java. The error message has two errors:
E/barteksc.sample: No implementation found for long com.shockwave.pdfium.PdfiumCore.nativeOpenDocument(int, java.lang.String) (tried Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument and Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument__ILjava_lang_String_2)
E/PDFView: load pdf error
java.lang.UnsatisfiedLinkError: No implementation found for long com.shockwave.pdfium.PdfiumCore.nativeOpenDocument(int, java.lang.String) (tried Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument and Java_com_shockwave_pdfium_PdfiumCore_nativeOpenDocument__ILjava_lang_String_2)
at com.shockwave.pdfium.PdfiumCore.nativeOpenDocument(Native Method)
at com.shockwave.pdfium.PdfiumCore.newDocument(PdfiumCore.java:135)
Here is the gradle file. It looks like there is something missing, although these are the original files before any modifications.
I tried to add this to proguard-rules.pro
-keep class com.shockwave.** { *; }
it removed the first error, but the second is still there.
Solved it.
If anyone is having the same issue, I did the following to solve it:
Installed android-ndk tools
Edited Application.mk file to remove mips and mips64 since they are not supported anymore, and updated android version to 19 since it's the minimum right now.
run ndk-build in the jni folder / directory.
That created what I was said about in my question
It looks like there is something missing
That created a libs folder that has the necessary definitions for the linker.
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 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.
I'm trying to build pjmedia for Android.
From pjsip library (http://www.pjsip.org/).
I've followed official tutorial (https://trac.pjsip.org/repos/wiki/Getting-Started/Android#OtherAndroidprojects)
1.Created config_site.h with next configuration:
define PJ_CONFIG_ANDROID 1
include <pj/ config_site_sample.h>
2.Specified path to NDK
export ANDROID_NDK_ROOT=/path_to_android_ndk_dir
3.Run android configurations and do make
./configure-android
make dep && make clean && make
I've got builded pjmedia libraries in /pjmedia/lib directory
libpjmedia-arm-unknown-linux-androideabi.a
libpjmedia-audiodev-arm-unknown-linux-androideabi.a
libpjmedia-codec-arm-unknown-linux-androideabi.a
libpjmedia-videodev-arm-unknown-linux-androideabi.a
libpjsdp-arm-unknown-linux-androideabi.a
And questions:
How should I use only pjmedia in Android app?
Where is JNI for pjmedia?
Should I create JNI .cpp wrapper by myself (with SWIG) and build it with pjmedia libraries into single library?
How to generate JNI with SWIG only for pjmedia?
I'm just little bit confused. They give me pjsua example with JNI and library but I don't want pjsua I need pjmedia!
I just don't know how can I use it in Android.
OS: OS X Yosemite
NDK: v9d x86
Help me somebody please! :)
Thanks!
I'm using netbeans 7.4 / jdk 1.7u51
I downloaded the jar for JNA from official site, in version 4.0.0.
I have an internally developped DLL whose interface is in plain C, which loads perfectly well with ctypes in python. This dll is compiled in release with visual 2010, whose runtime are in path.
D:\fl006\Downloads>dir D:\deploy\SpotLight\spotlight-1488\PasanBusLibrary.dll
Directory of D:\deploy\SpotLight\spotlight-1488
29.01.2014 11:13 1'690'112 PasanBusLibrary.dll
I tried to load it in java with jna:
public interface CLibrary extends Library {
(...snip...)
void pasanIpcInitializeLibrary(String xClient, String xBusName, int xTimeout);
void pasanIpcTerminateLibrary();
}
public static void main(String[] args) {
NativeLibrary.addSearchPath("PasanBusLibrary","D:\\deploy\\SpotLight\\spotlight-1488");
CLibrary Bus = (CLibrary) Native.loadLibrary("PasanBusLibrary",CLibrary.class);
(... snip ...)
This is basically an out of the book standard dll load, from a custom location.
When activating jna debug, I see the following :
run:
Looking in classpath from sun.misc.Launcher$AppClassLoader#714a8f44 for /com/sun/jna/win32-x86-64/jnidispatch.dll
Found library resource at jar:file:/D:/code/perso/TestWrapperBus/jna-4.0.0.jar!/com/sun/jna/win32-x86-64/jnidispatch.dll
Looking for library 'PasanBusLibrary'
Adding paths from jna.library.path: null
Trying D:\deploy\SpotLight\spotlight-1488\PasanBusLibrary.dll
Adding system paths: []
Trying D:\deploy\SpotLight\spotlight-1488\PasanBusLibrary.dll
Looking for lib- prefix
Trying libPasanBusLibrary.dll
Looking in classpath from sun.misc.Launcher$AppClassLoader#714a8f44 for PasanBusLibrary
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'PasanBusLibrary': Native library (win32-x86-64/PasanBusLibrary.dll) not found in resource path ([file:/D:/code/perso/TestWrapperBus/jna-4.0.0.jar, file:/D:/code/perso/TestWrapperBus/jna-platform-4.0.0.jar, file:/D:/code/perso/TestWrapperBus/build/classes/])
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:271)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
at com.sun.jna.Library$Handler.<init>(Library.java:147)
at com.sun.jna.Native.loadLibrary(Native.java:412)
at com.sun.jna.Native.loadLibrary(Native.java:391)
at testwrapperbus.TestWrapperBus.main(TestWrapperBus.java:39)
It looks it looks through the location I gave and somehow discards it. I tried different folders and I got same behaviour, there is no obvious file system right issue (dll is RW from all users)
Any clue on what I'm missing, I'm kind of stuck currently...
EDIT
if I load "msvcrt" this is working nice to cll printf
my dll has some dependencies, all of them hosted in c:\windows\system32 (standard runtime, dynamically linked)
My dll is a win32 compilation while I use a win64 JDK / JRE. Of course, when dealing with pure java, we don't care but loading native library needs to match.
I tried running from command line on a 32 bits JRE7 and it worked, so I'm pretty sure that installing JDK for win32 in my netbeans or recompiling my dll in 64 bits will solve the issue.
Thanks to this answer : Trying to use DLL from Java (JNA). Unable to load library exception for having put me on the righteous path