You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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:

Step 1: Set up your project structure correctly
  • First, make sure your .so files are placed in the right directory. For Android Studio, create a jniLibs folder under app/src/main/, then add subfolders for each architecture your .so supports (like armeabi-v7a, arm64-v8a, x86, x86_64). Drop the corresponding .so files into each matching folder.
  • Double-check your module-level build.gradle has the necessary configuration to recognize these libraries. Add this inside the android block if it's missing:
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/jniLibs']
        }
    }
    
Step 2: Create a C/C++ wrapper (using your .h header)

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:

  1. Create a cpp folder under app/src/main/, then make a file (e.g., native_wrapper.cpp) inside it.
  2. Include your provided .h header at the top:
    #include "your_header_file.h"
    
  3. Declare JNI (Java Native Interface) functions that call into the .so's init() and getVersion(). JNI has strict naming rules—they must match your Kotlin class's package structure. For example, if your Kotlin class is com.yourpackage.NativeLib, the JNI functions would look like this:
    #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);
    }
    
    Important: Replace com_yourpackage_NativeLib with your actual package and class name, and adjust parameter/return type conversions to match what your .h header specifies.
Step 3: Configure CMakeLists.txt

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_lib and libyour_lib_name.so with your .so's actual name (drop the lib prefix for the target name).
  • Update your module-level build.gradle to use CMake. Add this inside the android block:
    externalNativeBuild {
        cmake {
            path file('CMakeLists.txt')
            version '3.22.1'
        }
    }
    
Step 4: Create the Kotlin class to call native functions

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.
Step 5: Test the calls in your app

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"
Troubleshooting common issues
  • UnsatisfiedLinkError: This usually means the library isn't loaded correctly. Check:
    • Did you place the .so in the right jniLibs subfolders?
    • 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?
  • 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

火山引擎 最新活动