It's the first time I try to create a library c++ for Android/iOS.
I'm using Visual Studio 2015 - Xamarin.
First I created a project : Visual C++ -> Cross Platform -> Shared Library. In the hared library, I created 2 files.
SayHello.h :
#pragma once
#include <string.h>
class SayHello {
public:
SayHello();
~SayHello();
static char* Hello();
};
SayHello.cpp :
#include "SayHello.h"
extern "C"
{
SayHello::SayHello(){}
SayHello::~SayHello(){}
char * SayHello::Hello()
{
return "Hello !";
}
}
Then I generated a file libSayHello.so and created a project Android with xamarin to try to call the function hello.
There is my MainActivity.cs :
[DllImport("libSayHello.so")]
static extern String Hello();
protected override void OnCreate(Bundle bundle)
{
// I paste only my added code :
String hello = Hello();
Toast.MakeText(this.ApplicationContext, hello, ToastLength.Long);
}
I did all steps in this tutorial, but I have an exception :
System.DllNotFoundException: libSayHello.so
I searched for this, but I must be so noob cause I did not find anything. How should I use my libSayHello.so ?
EDIT:
There is my libSayHello.so seen with 7zip:
And my project :
I think this will be the best sample for you.
This all works according to the following scheme:
Android supports 7 CPU architectures.
But Xamarin supports 5 of them. So in the settings of your Xamarin.Android project check which architectures you will support:
[Xamarin.Droid.project]->[Properties]->[Android Options]->[Advanced]->[Supported architectures]
Check which archs are necessary for your project. According to this your shared library should be compiled for these archs. And you should put your shared libraries in Xamarin.Droid.project's folder lib:
To see them in Solution Explorer you should mention them in your Xamarin.Android project's .CSPROJ.
Add there next item groups:
<ItemGroup>
<AndroidNativeLibrary Include="lib\{ARCH}\libCLib.so">
<Abi>{ARCH}</Abi>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AndroidNativeLibrary>
</ItemGroup>
{ARCH} could be next: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64.
Now you can put DllImport in your code:
[DllImport("libCLib", EntryPoint = "clib_add")]
public static extern int Add(int left, int right);
I think you have to tell about entry point, because i had runtime errors without this statement System.EntryPointNotFoundException.
And don't forget to add next in your code:
using System.Runtime.InteropServices;
Confirm the library is put in "/lib/{arch}/" folder.
Try [DllImport("SayHello")]. the engine may add "lib" and ".so" automatically.
Related
I have a simple C++ function compiled into a dylib file that I'm trying to run on an Android phone. The function is super simple, it just adds to numbers and returns the result. However, I keep getting this error:
Another exception was thrown: Invalid argument(s): Failed to load dynamic library 'libadd.dylib': dlopen failed: library "libadd.dylib" not found .
I'm really not sure what I'm doing wrong. I've done the following steps:
My Dart implementation:
import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
typedef C_ADD = ffi.Int Function(
ffi.Int a, ffi.Int b); // FFI signature of C function
typedef ADD = int Function(int a, int b);
void linkAndCallFunction() {
var libraryPath = path.join(Directory.current.path, "libadd.dylib");
final dylib = ffi.DynamicLibrary.open(libraryPath);
final ADD add = dylib.lookup<ffi.NativeFunction<C_ADD>>("add").asFunction();
final result = add(40, 2);
print(result);
}
I've added these to the build.gradle files:
build.gradle:
buildscript{
ext{
ndkVersion = "25.1.8937393"
}
...
and app/build.gradle:
android {
ndkVersion rootProject.ext.ndkVersion
externalNativeBuild {
cmake {
path "../../lib/CMakeLists.txt"
}
}
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10.2)
project(add LANGUAGES CXX C)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
add_library(add SHARED ./add.cpp)
and my file structure of the project looks like this:
lib/
- add.cpp
- add.o
- CMakeLists.txt
- libadd.dylib
- main.dart
it also may be worth mentioning that in order to compile add.cpp into a dylib I ran the following commands:
g++ -c add.cpp
ar rvs libadd.dylib add.o
and if you're wondering, add.cpp looks like this:
#define EXPORT extern "C" __attribute__((visibility("default")))
__attribute__((used))
EXPORT
int add(int a, int b){
return a + b;
}
Where is this error coming from? am I compiling to a dylib incorrectly?
The answer to this problem was relatively simple, it just stemmed from my lack of knowledge on how Android actually compiles to a static library. Hopefully it helps someone else who is trying to understand how to setup external C++ code in a flutter program.
The static library is generated automatically and is set up in CMakeLists.txt.
Firstly, I moved all the C++ files into the android folder. Then, I set up CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.10.2)
add_library( add // library name, will create libadd.so
SHARED
add.cpp
)
The problem before was that I was trying to manually compile the file myself, when I should have been letting CMakeLists do it instead. According to the android documentation:
"The convention CMake uses to name the file of your library is as follows:
liblibrary-name.so
For example, if you specify "native-lib" as the name of your shared library in the build script, CMake creates a file named libnative-lib.so. "
https://developer.android.com/studio/projects/configure-cmake
So when I run the program, the static library is created automatically and placed in the correct place. Then, the Dart FFI can find it with the DynamicLibrary.open() function. In this case, CMakeLists will generate a file called libadd.so, and I can callDynamicLibrary.open('libadd.so') and the program works.
I need to create a .so Android shared library for a project, and I need to use functions from a C++ static library (.lib). The .so library is meant to be used just as a bridge, so I can use functions from my static library in Android apps and games. I've created a C++ cross-platform Android project in Visual Studio 2017 (also testing it in VS2019), included the header file for the static library and the library itself, and everything is theoretically configured and linked.
The current library I'm using is a simple static library for tests that has just a single function:
namespace StaticLibrary
{
extern "C" void Func()
{
// something
}
}
The file for the Android looks something like this:
#include "StaticLibraryHeader.h"
extern "C"
{
// ...
void StaticLibFunc()
{
StaticLibrary::Func();
}
}
When I try to compile the project, the compiler says:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Build\x64\Debug\libStaticLibTest_x64_Debug.lib: bad extended name index at 778
and:
undefined reference to 'Func'
I can get rid of this second error by using the --whole-archive option of the linker but then this new error shows up, along with the first one:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: fatal error: F:\Android_IOS_libs\MobileLibraries2019\Build\x64\Debug\libStaticLibTest_x64_Debug.lib: attempt to map 60 bytes at offset 6324 exceeds size of file; the file may be corrupt
I've also used Google Lib2A ( https://code.google.com/archive/p/lib2a/ ) to create a .a file, but then the following error happens:
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 192 is not an ELF object
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 870 is not an ELF object
C:\\Microsoft\AndroidNDK64\android-ndk-r16b\toolchains\x86_64-4.9\prebuilt\windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: F:\Android_IOS_libs\MobileLibraries2019\Krilloud_Android\lib\x64\libStaticLibTestDLL_x64_Debug.a: member at 1656 is not an ELF object
I'm not an Android/Java developer, so I'm lost here. How do I properly link and use my static library in a .so project? Can it be done using Visual Studio or do I really need to install Android Studio for this? I will also need to create the same thing for iOS, so I was hoping to have both projects in a Visual Studio solution.
I have problem when I try to use C++ library in Android studio project.
I am using statically built Qt 5.14.2 for Android.
I have Qt library project which has only 1 class with this 2 functions:
testclass.h
#include <QDebug>
#include <jni.h>
extern "C"
{
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log();
void logNormal();
}
testclass.cpp
JNIEXPORT void JNICALL Java_com_example_MyTestAndroidApp_LibraryClass_log()
{
qDebug() << "---> log from Qt library";
}
void logNormal()
{
qDebug() << "---> log from Qt library";
}
An in the .pro file I am using shared or staticlib to switch from shared(.so) and static(.a) library.
TEMPLATE = lib
CONFIG += shared
#CONFIG += staticlib
CONFIG += c++11
After successfully building the lib (shared and static) I got this files(for ABI x86 but others ABIS have similar sizes too):
libTestLibrary.so ---> 3,359 KB
libTestLibrary.a ---> 7 KB
For the shared (.so) library I was able to successfully call the function from android app.
In Android Studio I am creating new Native C++ project. I have Java JNI LibraryClas which is used to load the library and call the log() function from the library. I placed the library in jniLibs folder.
But for the static(.a) library there are a lot of problems. I tried to call the logNormal() function from the C++ part of the android app(from native-lib.cpp). I am not using JNI like in the shared library case. Here is what I tried:
Create new Native C++ project
Created libs(for the static library) and include(for testclass.h) folders inside app\src\main\cpp
Inside CMakeList.txt I have added this:
add_library(TestLibrary STATIC IMPORTED)
set_target_properties(TestLibrary PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libTestLibrary.a)
target_link_libraries( native-lib TestLibrary ${log-lib} )
And I called logNormal(); from native-lib.cpp.
First I got Error about missing Qt5Core library. After adding it the same way like my library I got errors for others missing libraries and files.
I have this questions:
Why static library is so much smaller then the shared library? (7KB vs 3,359KB) I found this which is opposite from my case:
Can I somehow build my static lib with all libraries and files that it need, so I don't get errors for missing libraries?
Can I use JNI to call C++ functions from static lib? Or when calling C++ functions from static lib it must be done from the C++ part of the android project?
Sorry for the long post and more then 1 question. Any hint or help is welcome. Thank you so much in advance.
I have to write a dynamic shared library for android (.so) and use it in Unity. I tried using the .so file that is exported from Android Studio when coding with JNI but Unity can't read the library.
using UnityEngine;
using System.Runtime.InteropServices;
public class ShareApp : MonoBehaviour {
int cntr=0;
#if UNITY_ANDROID
[DllImport("SharedObject2")]
private static extern int getFrameNumber();
#endif
...
}
the error message Unity returns is:
DllNotFoundException: SharedObject2
while the name of the library in unity's Assets/Plugins is libSharedObject2.so.
I tried building the library with Visual Studio 2015, using the cross platform Dynamic shared library (Android) option for a new project. Results are the same. The .so file is built but unity fails to read it.
The .cpp file I use to built the .so file contains just this:
extern "C"
{
int getFrameNumber()
{
return 5;
}
}
Can anyone please point me to a direction?
I made a Unity3d project working with C/C++ Dll.
So first I made the dll in Visual studio.
// mydll.cpp
#define EXPORT_API __declspec(dllexport)
extern "C" {
int EXPORT_API add(int a, int b)
{
return a+b;
}
}
And I added this dll into my Unity3D project and called
// C# script in Unity3D
public class TestDll : MonoBehaviour {
[DllImport("mydll")]
private static extern int add (int a, int b);
void Start() {
int a = add (100, 200);
}
}
This code works well and I got the correct result in Unity3D editor.
So I built this project to android platform and got an apk.
I installed and run this apk on my android device but the app doesn't work.
The app didn't run the Dll function.
Whats the matter? I tried to find out the solution in Google and here, but didn't get anything, yet.
Please help me.
Thanks.
Your dll must be in Plugins folder for Windows, it can work for Editor too. for Android you must replace in Plugins/Android folder. Build and write me ok
LearnCocos2D's comment is accurate.
To get Unity to DllImport() a shared library on Android, you must use an NDK compiler and specify a compile config for your target Android platform. Moreover, Unity requires you to specify the architecture of the Android platform in the build settings, eg.. "arm v7" vs "arm64".
As an aside, in Unity 2019.4 - selecting "Load on Startup" in the inspector page of my .so elicits a "DLLNotFoundException".
Overview of this: https://docs.unity3d.com/2019.4/Documentation/Manual/AndroidNativePlugins.html
NDK's CMake guide for getting you started on compiling correctly: https://developer.android.com/ndk/guides/cmake