Android Studio中Kotlin项目调用外部C++ .so文件问题咨询
Hey there, let's tackle this problem step by step—calling native functions from a pre-built .so in your Kotlin Android app is totally doable, even without the source code. Here's how I'd approach it:
- First, make sure your .so files are placed in the right directory. For Android Studio, create a
jniLibsfolder underapp/src/main/, then add subfolders for each architecture your .so supports (likearmeabi-v7a,arm64-v8a,x86,x86_64). Drop the corresponding .so files into each matching folder. - Double-check your module-level
build.gradlehas the necessary configuration to recognize these libraries. Add this inside theandroidblock if it's missing:sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } }
Since you don't have the .so source code, you'll need a small wrapper file to bridge Kotlin to the native functions. Here's how:
- Create a
cppfolder underapp/src/main/, then make a file (e.g.,native_wrapper.cpp) inside it. - Include your provided .h header at the top:
#include "your_header_file.h" - Declare JNI (Java Native Interface) functions that call into the .so's
init()andgetVersion(). JNI has strict naming rules—they must match your Kotlin class's package structure. For example, if your Kotlin class iscom.yourpackage.NativeLib, the JNI functions would look like this:
Important: Replace#include <jni.h> extern "C" JNIEXPORT void JNICALL Java_com_yourpackage_NativeLib_init(JNIEnv* env, jobject thiz, jstring param1, jint param2) { // Convert JNI types to C types (adjust based on your header's requirements) const char* c_param1 = env->GetStringUTFChars(param1, nullptr); // Call the .so's init() function init(c_param1, param2); // Release string reference to avoid memory leaks env->ReleaseStringUTFChars(param1, c_param1); } extern "C" JNIEXPORT jstring JNICALL Java_com_yourpackage_NativeLib_getVersion(JNIEnv* env, jobject thiz) { // Call getVersion() and convert return type to JNI string const char* version = getVersion(); return env->NewStringUTF(version); }com_yourpackage_NativeLibwith your actual package and class name, and adjust parameter/return type conversions to match what your .h header specifies.
You need to tell Android Studio how to link against your pre-built .so. Create a CMakeLists.txt file in your app module's root with this content:
cmake_minimum_required(VERSION 3.22.1) project("nativewrapper") # Define your pre-built .so library add_library( your_prebuilt_lib SHARED IMPORTED ) # Set path to your pre-built .so (adjust for each architecture) set_target_properties( your_prebuilt_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libyour_lib_name.so ) # Add your wrapper source file add_library( native_wrapper SHARED src/main/cpp/native_wrapper.cpp ) # Link wrapper against the pre-built .so target_link_libraries( native_wrapper your_prebuilt_lib android log )
- Replace
your_prebuilt_libandlibyour_lib_name.sowith your .so's actual name (drop thelibprefix for the target name). - Update your module-level
build.gradleto use CMake. Add this inside theandroidblock:externalNativeBuild { cmake { path file('CMakeLists.txt') version '3.22.1' } }
Make a Kotlin class that loads the wrapper library and declares the native functions:
package com.yourpackage class NativeLib { init { System.loadLibrary("native_wrapper") } external fun init(param1: String, param2: Int) external fun getVersion(): String }
- Adjust the package name and parameter types to match your JNI wrapper and .h header.
Use the class in your Activity or Fragment like this:
val nativeLib = NativeLib() // Call init with your parameters nativeLib.init("your_first_param", 123) // Get and use the version val version = nativeLib.getVersion() binding.tvVersion.text = "Library Version: $version"
- UnsatisfiedLinkError: This usually means the library isn't loaded correctly. Check:
- Did you place the .so in the right
jniLibssubfolders? - Does the library name in
System.loadLibrary()match the one in CMakeLists.txt? - Are the JNI function names an exact match for your Kotlin class's package and name?
- Did you place the .so in the right
- Type mismatches: Ensure you're converting JNI types (like
jstring,jint) correctly to the C types your .so expects. Refer to your .h header for exact specs. - Architecture mismatches: Build your app only for architectures your .so supports. Add this to your module-level
build.gradle:android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' // add only supported ABIs } } }
That should get you up and running with calling those .so functions. If you hit any specific roadblocks, feel free to share more details about the error messages or header file specs!
内容的提问来源于stack exchange,提问作者Charles




