第一步, 在eclipose里新建一个android工程,再新建一个 SerialPort.java文件
package android.serialport;
public class SerialPort {
//本类方法,这里略过,主要是调用jni方法以给其他类提供方法。
......
// JNI 方法
private native static FileDescriptor open(String path, int baudrate) throws IOException;
private native void native_close();
private native int native_read_array(byte[] buffer, int length) throws IOException;
private native int native_read_direct(ByteBuffer buffer, int length) throws IOException;
private native int native_read_array_timeval(byte[] buffer, int length, int tv_sec, int tv_usec) throws IOException;
private native int native_read_direct_timeval(ByteBuffer buffer, int length, int tv_sec, int tv_usec) throws IOException;
private native void native_write_array(byte[] buffer, int length) throws IOException;
private native void native_write_direct(ByteBuffer buffer, int length) throws IOException;
static {
System.loadLibrary("serial_port");
}
}
第二步,生成共享库头文件。进入eclipose刚才所新建工程的/bin/classes/目录下。可以看到其目录下的android/serialport/SerialPort.class文件,这个文件就是eclipose自动编译生成的classes文件。
执行: javah android.serialport.SerialPort (注意把目录符“/”换成“.”,而且没有.classes)
就会在当前目录下生成android_serialport_SerialPort.h 头文件,查看android_serialport_SerialPort.h有时会多余些错误处,如Java_android_serialport_SerialPort_native_1open函数名,明显多了一个“1”,此处不懂为什么多了个“1”。但千万不要去掉它.
第三步,将刚才生成的H文件拷贝到jni源文件目录。因为我们这里是用ubuntu下ndk编译的。所以将android_serialport_SerialPort.h改名成SerialPort.h后,实现SerialPort.c文件,SerialPort.c就是要实现刚才SerialPort.h里面的所有方法。
SerialPort.h : 用javah 命令产生的
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_SerialPort */
#ifndef _Included_android_serialport_SerialPort
#define _Included_android_serialport_SerialPort
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_serialport_SerialPort
* Method: native_open
* Signature: (Ljava/lang/String;I)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_native_1open
(JNIEnv *, jclass, jstring, jint);
/*
* Class: android_serialport_SerialPort
* Method: native_close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_native_1close
(JNIEnv *, jobject);
/*
* Class: android_serialport_SerialPort
* Method: native_read_array
* Signature: ([BI)I
*/
JNIEXPORT jint JNICALL Java_android_serialport_SerialPort_native_1read_1array
(JNIEnv *, jobject, jbyteArray, jint);
/*
* Class: android_serialport_SerialPort
* Method: native_read_direct
* Signature: (Ljava/nio/ByteBuffer;I)I
*/
JNIEXPORT jint JNICALL Java_android_serialport_SerialPort_native_1read_1direct
(JNIEnv *, jobject, jobject, jint);
.........
#ifdef __cplusplus
}
#endif
#endif
SerialPort.c : 实现SerialPort.h中声明的函数
#include "termios.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "SerialPort.h"
#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
//static jfieldID field_context; // cannot define this , use this will anr. why??????
/*
* Class: android_serialport_SerialPort
* Method: native_open
* Signature: (Ljava/lang/String;I)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_native_1open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate)
{
int fd;
speed_t speed;
jobject mFileDescriptor;
/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
/* TODO: throw an exception */
LOGE("Invalid baudrate");
jniThrowException(env, "java/io/IOException bad baudrate!!!!!", NULL);
return NULL;
}
}
/* Opening device */
{
jboolean iscopy;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
LOGD("Opening serial port %s", path_utf);
fd = open(path_utf, O_RDWR);
LOGD("open() fd = %d", fd);
// (*env)->SetIntField(env,thiz, field_context, fd); // cannot define this , use this will anr. why??????
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -1)
{
/* Throw an exception */
LOGE("Cannot open port");
jniThrowException(env, "java/io/IOException", NULL);
/* TODO: throw an exception */
return NULL;
}
}
/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg))
{
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
jniThrowException(env, "java/io/IOException", NULL);
return NULL;
}
cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg))
{
LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
jniThrowException(env, "java/io/IOException", NULL);
return NULL;
}
}
/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
}
return mFileDescriptor;
}
/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_native_1close
(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);
}
..........
第四步,编写Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-3
LOCAL_MODULE := serial_port
LOCAL_SRC_FILES := SerialPort/SerialPort.c JNIHelp.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
第五步,编译,执行ndk-build命令,将会产生serial_port.so文件
第六步,将serial_port.so文件拷贝到eclipse项目 project/libs/armeabi/下,至此OK。