Reputation: 163
I am new in NDK development, I created project with C++ support. However i just added 1 cpp class and generated .SO file. And tried to access that so file in another project. I refer many stackoverflow links, Blogs and Google developer site. But not able to resolve it. Here is my code.
local.properties
ndk.dir=/home/android/Android/Sdk/ndk/20.1.5948944
sdk.dir=/home/android/Android/Sdk
src/main/cpp/CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
hello_world_lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
hello_world_lib.cpp
HelloWorld.cpp
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
hello_world_lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
src/main/cpp/hello_world_lib.cpp
#include <jni.h>
#include <string>
#include <bitset>
#include "HelloWorld.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_dc_testapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_dc_testapplication_MainActivity_getSumOfValues(JNIEnv *env,
jobject,jint a ,jint b,jstring sign){
// working Solution
const char *nativeString = env->GetStringUTFChars(sign, 0);
HelloWorld helloWorld;
helloWorld.setValues((int)a,(int)b);
helloWorld.setOperationType(*nativeString);
jint mData = (jint)helloWorld.getSumOf2Values();
return mData;
}
I got so files from here after build/run application. app/build/intermediates/cmake/debug/obj/{abis}/{nameoflib}.so
Now i need to access these .so files in another project. And its package name is com.dc.usendklib. Now here is my new project Code.
app/libs/{abi folder names}/.so files. src/main/jniLibs/{abi folder names}/.so
src/main/jniLibs/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello_world_lib-prebuilt
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libhello_world_lib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
src/main/jniLibs/Application.mk
APP_ABI := armeabi-v7a arm64-v8a x86
app's gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
sourceSets.main {
jniLibs.srcDir 'src/main/jniLibs' //set .so files location to libs
jni.srcDirs = [] //disable automatic ndk-build call
}
defaultConfig {
applicationId "com.dc.usendklib"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
moduleName "hello_world_lib"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// sourceSets {
// main {
// // let gradle pack the shared library into apk
// jniLibs.srcDirs = ['src/main/jniLibs','src/main/CPP']
// }
// }
// sourceSets.main {
// jniLibs.srcDir 'src/main/jniLibs'
// }
// externalNativeBuild {
// cmake {
// path "src/main/cpp/CMakeLists.txt"
// version "3.10.2"
// }
// }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
And when i run this, i am getting this error.
2020-01-03 11:44:54.946 17235-17235/com.dc.usendklib E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dc.usendklib, PID: 17235
java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.dc.usendklib.MainActivity.stringFromJNI() (tried Java_com_dc_usendklib_MainActivity_stringFromJNI and Java_com_dc_usendklib_MainActivity_stringFromJNI__)
at com.dc.usendklib.MainActivity.stringFromJNI(Native Method)
at com.dc.usendklib.MainActivity.onCreate(MainActivity.kt:14)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
MainActivity.kt
package com.dc.usendklib
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Example of a call to a native method
sample_text.text = stringFromJNI()
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("hello_world_lib")
}
}
}
Now my questions are,
The way i generate and pick .so files, is that a correct way?
JNI class methods uses Java_{package}_method, So after generate .so, is that possible to use that files in another project?
If yes, please tell me how. Any help will be appreciated. Thanks in advance.
Upvotes: 1
Views: 5632
Reputation: 434
Yes you can access your so file to other project. but your project directory must be same as your old project. in your case project directory must be like this :
com/dc/testapplication/MainActivity.class
And your MainActivity.class
must have getSumOfValues
method.
Upvotes: 2
Reputation: 4007
Java_com_dc_testapplication_MainActivity_stringFromJNI
It supposed that your "wrapper" class in MainActivity from the package com.dc.testapplication
But, as far as I can see in your post, your MainActivity is located in com.dc.usendklib. That's why you have an UnsatisfiedLinkError.
You can have a look at my case to understand how it works
Upvotes: 1