How to use a pre-compiled .so file in another android app? - android-ndk

I wonder why there is no proper answer to this question, I searched for couple of hours but no good answer.
So, we work on a team in which my friend wrote a C library and compiled it as a .so file (it's called ttplib.so)(assume I don't have access to it's C code). Now I have to use that .so file in my android application. But I don't know how to load the library and how to use its methods. I have good documentation of it.
That would be great if you can tell me how to create the Android.mk file too.
Do I have to use dlopen?

Put ttplib.so in the new project's libs/armeabi or libs/armeabi-v7a folder depending what it was compiled with.
Somewhere in your new app (before interacting with the library) add this line of code
System.loadLibrary( "ttplib" );
Now that it's loaded in memory, you'll need to interact with it using JNI. You'll have to go back to the C code to export some JNI functions:
JNIEXPORT jint JNICALL Java_com_example_package_MyClass_methodName( JNIEnv* env, jobject jthis, jfloat value )
{
return 5;
}
Then you'll need to add ClassName.java in your new project:
package com.example.package;
public class MyClass
{
private native int methodName( float value );
private void someJavaMethod()
{
int i = methodName( 65.33f );
}
}
That's it, in a nutshell.

Related

Calling C external library (.so) from android java

I am writing an example android app to demonstrate the use of our (university research) C/C++ library.
I know that, using jni, we can call C functions from java.
However, I have not found a step by step set of instructions for how to do this within Android Studio Artic Fox.
I have seen the need to write jni compatible C wrapper functions, but have not found how to do this (correctly formed function signatures) or where to put them.
In addition, what do I need to change in the project setup to correctly build the project (using gradle) ?
Note that I have to use directly the pre-built .so file and the public header file which defines the set of public C functions for the library.
There are plenty of examples which give partial outdated information, but still nothing comprehensive - or have I missed something ?
I put together a quick guide below, but I want to clarify how it all fits together first.
In an Android application, you can bind native methods to specially-named functions that are loaded from a native library.
These specially-named functions receive pointers to a JNIEnv struct to interact with the embedding Java application.
The native library is typically built using CMake. Any external dependencies (such as your prebuilt library) need to be made visible to CMake in its CMakeLists.txt. The weapon of choice here are IMPORTED libraries, which are exactly what you think they are.
the steps
First, create an Android project with Kotlin as language.
Right click the app at the top of the tree and select "Add C++ to module" to generate the necessary build stuff.
Change your MainActivity.kt file to be:
class MainActivity : AppCompatActivity() {
external fun doit();
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val nativeThread = Thread {
doit()
}
nativeThread.start()
}
}
You will get a build error stating "cannot resolve corresponding JNI function". If you select the quick fix for that, Android Studio will generate a .cpp file with the appropriate JNI wrapper code inside it.
The generated function will look like:
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_doit(JNIEnv *env, jobject thiz) {
// TODO: implement doit()
}
and above that will be instructions on how to load the native library from Kotlin. Copy that code to your MainActivity.kt.
Edit that .cpp file to do whatever you need to do with your native library (eg #include some files and call some functions).
Finally, edit app/src/main/cpp/CMakeLists.txt to point to your headers and precompiled library.

How to edit a kotlin file containing compiled code

I have an aar package, I unzipped it, unzipped the classes.jar file as well, and now have a bunch of .kt and .class files a few of which I would like to edit. But all I see is class and method declaration with their body containing /* compiled code */. Where do I find the Kotlin code so I can edit it like we used to in Java class files?
Now this is my first time handling kotlin and frankly i don't even know the language. I am using android studio to open the files, and i know how to generate a read-only decompiled java version to understand the inner workings. That's how i figured out which file i need to edit.
I have also found some answers on stack that mention how converting kotlin to java and back to kotlin after editing is not a good idea, since the java file is not a perfect decompilation.
Here is the file I want to edit as it appears in AS:
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package ru.aviasales.screen.results.view
public final class ResultItemView public constructor(context: android.content.Context, attributeSet: android.util.AttributeSet) : ru.aviasales.ui.views.CardView {
private final val segmentViews: kotlin.collections.MutableList<ru.aviasales.screen.results.view.ResultSegmentItemView> /* compiled code */
public final fun onFavouritesButtonClicked(onClick: () -> kotlin.Unit): kotlin.Unit { /* compiled code */ }
protected open fun onFinishInflate(): kotlin.Unit { /* compiled code */ }
public final fun setData(viewModel: ru.aviasales.screen.results.viewmodel.ResultItem.TicketViewModel): kotlin.Unit { /* compiled code */ }
private final fun setUpAvailableSeatsCount(seatsCount: kotlin.Int, type: ru.aviasales.screen.results.viewmodel.ResultViewType): kotlin.Unit { /* compiled code */ }
private final fun setUpFavouritesButton(favoritesEnabled: kotlin.Boolean, addedToFavourites: kotlin.Boolean): kotlin.Unit { /* compiled code */ }
private final fun setUpPrice(price: kotlin.Long, passengersCount: kotlin.Int): kotlin.Unit { /* compiled code */ }
private final fun setUpSegments(segments: kotlin.collections.List<ru.aviasales.screen.results.viewmodel.SegmentViewModel>): kotlin.Unit { /* compiled code */ }
}
Is it even possible to edit these type of files ? if yes then Do i need a different editor or is there a different method to open such files ?
The simple answer after trying everything I could, is that you can't.
Luckily I was able to circumvent the issue, by creating a new activity. The aar package had its own MainActivity activity which was also kotlin class file. I decompiled the .class file, copy pasted the java code into my new activity and use then call the new activity from application file (since the MainActivity was being called automatically at start). I also faced the problem of some variables not initialising properly because of lateinit. I solved that by simply copying the variables through application from MainActivity using registerActivityLifecycleCallback and then calling my activity.

accessing Android native method from different project

I am working on an Android application that will call a .so file created by a different Android NDK application.
I have created the following folder structure in my project and copied over the .so files as seen below:
|--app:
|--|--src:
|--|--|--main
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--libmylib.so
|--|--|--|--|--x86
|--|--|--|--|--|--libmylib.so
I call this library through my application via the following code:
static {
System.loadLibrary("mylib");
}
I then call the method from this shared object via the following code:
String str = stringFromJNI();
This does not work as the program looks for mangled function name as follows:
com.example.androidlibcall.MainActivity.stringFromJNI() where my .so function will be using a different package name and hence a different function name is generated.
I am not really sure what I need to do to call the functions from the external library, I assume I can create my own library and utilize dlopen() to load the external library and make calls to it, but was wondering if there are the other methods to achieve this or not.
My ultimate goal is to be able to create applications that can call pre-existing libraries that are on the mobile device, but since I am new to NDK/Android I am not sure what is the best method for this and have not found good examples to work with.
A lot of the pre-existing similar questions seem to be dealing with older versions of Android Studio that don't seem applicable anymore.
I am using the latest version of Android Studio (3.1.2) with Gradle 4.4 on Windows 7 machine.
Please advise.
Thanks!
Generally speaking, it's not a good idea to have native methods in application's MainActivity, but this should not worry us now that we are forging a workaround.
Assume that your new project has com.example.other.MainActivity.java, and you want to call the native method com.example.androidlibcall.MainActivity.stringFromJNI() from com.example.other.MainActivity.onCreate(). To do this, create a new Java class in your other app:
package com.example.androidlibcall;
public class MainActivity {
public static native String stringFromJNI();
}
and in your existing MainActivity class,
package com.example.other;
import static com.example.androidlibcall.MainActivity.stringFromJNI;
class MainActivity {
static {
System.loadLibrary("mylib");
}
}
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
String qq = stringFromJNI();
…
}
}
You see that com/example/androidlibcall/MainActivity.java contains no logic, no data, no code. It is only a wrapper that lets us easily use libmylib.so without rebuilding it.

call unmanaged C++ code from C# using pinvoke

I have a unmanaged C++ dll for which I do not have access to code but have all methods declarations for.
Lets for simplicity say that .h looks like this:
#include <iostream>
#ifndef NUMERIC_LIBRARY
#define NUMERIC_LIBRARY
class Numeric
{
public:
Numeric();
int Add(int a, int b);
~Numeric();
};
#endif
and method implementation in .cpp file
int Numeric::Add(int a, int b)
{
return (a + b);
}
I simply want to call the add function from C++ in my C# code:
namespace UnmanagedTester
{
class Program
{
[DllImport(#"C:\CPP and CSharp Project\UnmanagedNumeric\Debug\numeric.dll", EntryPoint = "Add")]
public static extern int Add(int a, int b);
static void Main(string[] args)
{
int sum = Add(2, 3);
Console.WriteLine(sum);
}
}
}
After trying to execute I have the following error:
Unable to find an entry point named 'Add' in DLL 'C:\CPP and CSharp Project\UnmanagedNumeric\Debug\numeric.dll'.
I CAN NOT change C++ code. Have no idea what is going wrong.
Appreciate your help.
Using PInvoke you can only call global functions exported from Dll. To use exported C++ classes, you need to write C++/CLI wrapper. This is C++/CLI Class Library project, which exposes pure .NET interface, internally it is linked to unmanaged C++ Dll, instantiates a class from this Dll and calls its methods.
Edit: you can start from this: http://www.codeproject.com/KB/mcpp/quickcppcli.aspx#A8
If you need to create a wrapper, take a look at swig.org. It will generate one for most high level language like C#.
I just came across this program a few minutes ago while working the same problem that you are.
To use a class from native C++ from C# you need a C++/CLi wrapper in between, as mentioned by by previous answers. To actually do that, it is not very straight forward. Here is I link that tell you how to do it at a high level: C++/CLI wrapper for native C++ to use as reference in C#.
If you are quite new to this (like me), you might stumble on 1) -- the linking part. To solve that, you can see how I did here (see my question portion): Link error linking from managed to unmanaged C++ despite linking to .lib file with exported symbols

VC++: Using DLLs as "subprograms"

So I just began to try my hand at emulation after years of putting it off and not knowing where to start and I have managed to successfully write my first emulator! Now I am organizing my code in so that I can reuse the code to emulate other systems. I've been toying with the idea of having a shared frontend "platform handler" of sorts that I will compile as my executable whereas I will compile my emulated system code into dlls that the platform handler will use to identify what is available and instantiate from. This would allow me to separate my code into different projects and to leave the option open of using a bulkier front-end with more features or a streamlined "game only" and to share the same dlls between them rather than make two different solutions.
I know how to compile dlls vs executables but I don't know how to link the executable to the custom dll in such a way that I can instantiate a class from it. I'm not even sure what I'm trying to do is technically possible. Do the dll classes need to be static? I've never coded anything like this before or even done much with custom dlls so any help or ideas would be appreciated. I'm using Visual C++ 2010 by the way. Thanks in advance for any advice anyone may have.
You don't really have to do much different. Just export your classes from the dll like you do for functions. In your app, include the header and link to the generated lib like you usually do. See this page: http://msdn.microsoft.com/en-us/library/81h27t8c%28v=vs.80%29.aspx
Example.h
#ifdef DLL_EXPORT
#define EXPORT_API __declspec(dllexport)
#else
#define EXPORT_API __declspec(dllimport)
#endif
class EXPORT_API Example
{
public:
Example();
~Example();
int SomeMethod();
};
int EXPORT_API ExampleFuncion();
Example.cpp
#include "Example.h"
Example::Example()
{
// construct stuff
}
Example::~Example()
{
// destruct stuff
}
int Example::SomeMethod()
{
// do stuff
return 0;
}
int EXPORT_API ExampleFunction()
{
return 0;
}
In your dll project, define DLL_EXPORT and build. You will get a .lib and .dll output. In your main project where you will be using the dll you do not have to do anything except include the header and link against the .lib. Do not define the DLL_EXPORT symbol in your main project and be sure the .dll is somewhere your application can find it.
If you really want to get clever, this problem is screaming for the factory design pattern. If you design your interface well enough, you can have your dlls register their implementation with your application when they are loaded. You can extend forever without even rebuilding your main executable.

Resources