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
相关产品推荐
相关产品推荐

