You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android项目用JNI+pybind11桥接Python遇编译错误求助

解决Android中pybind11桥接Python的"io.h"文件未找到错误

问题背景

在Android项目中通过C++(pybind11)作为桥接层调用Python模块,编译时出现错误:

config.py:- "io.h" file not found

错误原因

io.h是Windows平台专属头文件,Android基于Linux内核,使用NDK编译时无法识别该文件。核心问题是直接使用了Windows版本的Python头文件/库,没有针对Android平台交叉编译Python。

解决方案

1. 交叉编译Python到Android平台

必须为目标Android架构(arm64-v8a、armeabi-v7a等)交叉编译Python静态库:

  • 使用Android NDK提供的交叉编译工具链,配置CC、CXX指向NDK的clang编译工具。
  • 编译时指定静态库模式,关闭依赖Windows平台的特性(如--disable-readline、--disable-ssl等),避免额外依赖问题。
  • 将编译后的头文件和库文件放到externals/python-android目录下,替换原Windows版本的Python资源。

2. 修正CMakeLists.txt配置

确保CMake正确识别交叉编译后的Python和pybind11,示例配置如下:

cmake_minimum_required(VERSION 3.22.1)

project("methodchannel")

# 交叉编译后的Python路径
set(PYTHON_ANDROID_PATH ${CMAKE_CURRENT_SOURCE_DIR}/externals/python-android)
include_directories(${PYTHON_ANDROID_PATH}/include/python3.11)
link_directories(${PYTHON_ANDROID_PATH}/lib/${ANDROID_ABI})

# 引入pybind11
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/externals/pybind11)

add_library(
        methodchannel
        SHARED
        methodchannel.cpp
)

find_library(
        log-lib
        log
)

target_link_libraries(
        methodchannel
        ${log-lib}
        pybind11::embed
        python3.11  # 链接交叉编译的Python静态库
        dl
        pthread
        m
)

# 将Python模块复制到assets,运行时再复制到可访问路径
set(MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/modules)
file(GLOB MODULE_FILES ${MODULES_DIR}/*.py)
foreach(FILE ${MODULE_FILES})
    configure_file(${FILE} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/assets/modules COPYONLY)
endforeach()

3. 调整代码细节

  • 统一路径分隔符:把代码中的externals\python\include/Python.h改成Linux风格的externals/python-android/include/python3.11/Python.h。
  • 添加模块搜索路径:Android的assets目录是只读的,需要把modules复制到应用私有目录后,再添加到Python的sys.path中,示例代码调整如下:
#include "jni.h"
#include "iostream"
#include "externals/python-android/include/python3.11/Python.h"
#include "externals/pybind11/include/pybind11/embed.h"

namespace py = pybind11;

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_methodchannel_MainActivity_00024Companion_getNum(JNIEnv *env, jobject thiz, jint num)
{
    py::scoped_interpreter guard{};

    // 获取应用私有文件目录路径
    jclass contextClass = env->GetObjectClass(thiz);
    jmethodID getFilesDirMethod = env->GetMethodID(contextClass, "getFilesDir", "()Ljava/io/File;");
    jobject filesDirObj = env->CallObjectMethod(thiz, getFilesDirMethod);
    jclass fileClass = env->FindClass("java/io/File");
    jmethodID getAbsolutePathMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
    jstring pathStr = (jstring)env->CallObjectMethod(filesDirObj, getAbsolutePathMethod);
    const char* filesPath = env->GetStringUTFChars(pathStr, nullptr);
    std::string modulesPath = std::string(filesPath) + "/modules";
    env->ReleaseStringUTFChars(pathStr, filesPath);

    // 添加模块搜索路径
    py::module_ sys = py::module_::import("sys");
    sys.attr("path").cast<py::list>().append(modulesPath);

    // 调用Python模块
    auto module = py::module_::import("module");
    auto func = module.attr("myfunc");
    int result = func(num).cast<int>();

    return 12 + result;
}

4. 运行时准备

在App启动阶段,将assets中的modules目录复制到getFilesDir()返回的应用私有路径下,确保Python能够读取到模块文件。

内容的提问来源于stack exchange,提问作者Ahsan Tony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 01:20:19