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

Android串口APP报错:无法解析对应JNI函数问题求助

解决JNI函数无法解析(cannot resolve corresponding jni function)的问题

看起来你在开发Android串口应用时遇到了JNI函数找不到的困扰,我帮你从提供的代码里排查出几个关键问题,逐一给出修复方案:

1. 修复Close函数的JNI导出修饰符

你的C代码里的close函数缺少JNIEXPORT和JNICALL关键字——这俩是JNI函数的必填修饰符,没有它们编译器不会把函数导出到.so库的符号表中,Java层自然找不到对应的JNI实现。

修改后的Close函数代码:

JNIEXPORT void JNICALL Java_com_example_richyrony_serial485_SerialPort_close (JNIEnv *env, jobject thiz) {
    jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
    jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

    jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
    jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

    jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
    jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);

    LOGD("close(fd = %d)", descriptor);
    close(descriptor);
}

2. 确保Java层正确声明Native方法

你提供的Java代码不完整,必须在SerialPort类中用native关键字声明对应的JNI方法,参数和返回值要和C层完全匹配,还要加上库加载的静态代码块:

package com.example.richyrony.serial485;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.util.Log;

public class SerialPort {
    private static final String TAG = "SerialPort";

    // 必须保留这个字段,native的close方法会直接访问它
    private FileDescriptor mFd;
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;

    // 声明native方法,参数和返回值要和C层严格对应
    private native FileDescriptor open(String path, int baudrate);
    private native void close();

    static {
        // 加载.so库:如果你的库文件是libserial_port.so,这里只需要写"serial_port"
        System.loadLibrary("serial_port");
    }

    public SerialPort(File device, int baudrate) throws SecurityException, IOException {
        /* 检查设备读写权限 */
        if (!device.canRead() || !device.canWrite()) {
            try {
                // 尝试通过su获取权限(如果设备已root)
                Process su = Runtime.getRuntime().exec("/system/bin/su");
                String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";
                su.getOutputStream().write(cmd.getBytes());
                if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
                    throw new SecurityException();
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new SecurityException();
            }
        }
        // 补全native方法调用逻辑
        mFd = open(device.getAbsolutePath(), baudrate);
        if (mFd == null) {
            Log.e(TAG, "Native open() returned null");
            throw new IOException();
        }
        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }

    // 对外提供串口的输入输出流
    public InputStream getInputStream() {
        return mFileInputStream;
    }

    public OutputStream getOutputStream() {
        return mFileOutputStream;
    }

    // 封装关闭逻辑,方便上层调用
    public void closePort() {
        if (mFileInputStream != null) {
            try {
                mFileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mFileOutputStream != null) {
            try {
                mFileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 调用native方法关闭串口
        close();
    }
}

3. 检查JNI函数名的正确性

JNI函数名必须严格遵循Java_包名_类名_方法名的格式,你的C代码里的Java_com_example_richyrony_serial485_SerialPort_open和修改后的close函数名是正确的,只要Java类的包名、类名完全匹配就没问题。

4. 修复一处日志格式错误

你的C代码中有个小bug:

LOGD(" serial port buadrate %s", speed);

speed是整数类型(speed_t本质是int),用%s会导致内存错误或乱码,应该改成%d,顺便纠正拼写错误:

LOGD(" serial port baudrate %d", baudrate);

5. 确认.so库的放置和配置

  • 确保.so库放在src/main/jniLibs/[abi]/目录下,比如armeabi-v7a、arm64-v8a,根据你的目标设备架构选择;
  • 在Module级的build.gradle中确认NDK配置:
android {
    ...
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a' // 根据需求调整支持的架构
        }
    }
}

做完这些修改后重新编译运行,应该就能解决JNI函数无法解析的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:17:21