封装 jni 的 java 层 Integer、Long 对象使用时必须用 new 对象的形式,防止修改 128>x x>-128 之间缓存的对象,一定要谨记
配置
在 eclipse 环境下开发 jni
1. 导入 ndk Window->Preferences->Android->NDK,点击 Browse 引入 ndk 的目录
2. 创 建 java 类 , 声 明 一 个 private native String CBBT_getVersionString();
JNIEXPORT jstring JNICALL Java_com_raiing_ABBTSurface_getVersionString(JNIEnv *env,
jobject obj)
3. 使用 javah 生成 jni 头文件.
3-a. run - external tools - external tools configuration - program - new lanch configuration 3-b. name:javah
location:jdk 安装目录中的 javah.exe 所在目录javah.exe FilesJavajdk1.7.0_02injavah.exe
working directory: ${workspace_loc}
arguments: -v -classpath "${project_loc}/bin/classes" ${java_type_name}
common - Display in favorites menu - 选中 External tools
中显示 javah。
3-c. apply , close
3-d. 点中 src- com.raiing - CTMProcess.java 文件
3-e. run - external tools - javah 将生成 jni 的头文件在 jni 目录下。按 F5 刷新 project explorer 的 jni 目录。
4. 添加 Android.mk 和 Application.mk 文件到 jni 目录。 android.mk 内容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_MODULE := child 自己起的库名字
LOCAL_SRC_FILES := com_raiing_childmodule_ChildModule.cpp utilities.c include $(BUILD_SHARED_LIBRARY)
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_LDFLAGS := $(LOCAL_PATH)ccodearmeabi-v7alibCBBT.a
LOCAL_LDFLAGS += $(LOCAL_PATH)ccodearmeabi-v7alibutilities.a 两者有
顺序
比如:C:Program "${project_loc}/jni"
-d
以便在 run - external tools
#LOCAL_STATIC_LIBRARIES := utilities
endif
需要修改上述内容的 LOCAL_MODULE:= 为希望的库名称。生成的库名将在这个名称前增加
lib 前缀。
需要修改 LOCAL_SRC_FILES:= 将 jni 目录下的所有 cpp c 添加到后面,空格分隔。
Application.mk 内容:
APP_ABI := all 生成所有平台的目录文件,我们一般只需要三个
APP_ABI := armeabi armeabi-v7a arm64-v8a
APP_CFLAGS += -Wno-error=format-security -D_ENV_ANDROID_=1
5. 添加 ndk 编译命令到项目。
5-a. run - external tools - external tools configuration - program - new lanch configuration
main- name: ndk_build
main-location: ndk 安 装 目 录 dk-build.cmd 比如:S:work_dirandroid-ndk-r9d dk-build.cmd
main- working directory: ${workspace_loc}/${project_name}/jni common - Display in favorites menu - 选中 External tools
5-b. 选中 CTMProcess 项目名,project - properties - builders - import - ndk_build 5-d. 在 builders 中选中 ndk_build ,点击 UP,将 ndk_build 调整到最高。
基本数据类型
Java Type Native Type Description
boolean jboolean
byte jbyte
char jchar
double jdouble
float jfloat
int jint
long jlong
short jshort
void void
8 bits, unsigned
8 bits, signed
16 bits, unsigned
64 bits
32 bits
32 bits, signed
64 bits, signed
16 bits, signed
N/A
Java Type |
Signature |
boolean Z
byte B
char C double D
float F
int I
long J
void V
object
Lfully-qualified-class;
type[]
[type
method signature ( arg-types) ret-type
Method |
Signature |
void f1() |
()V |
int f2(int, long) |
(IJ)I |
boolean f3(int[]) |
([I)B |
double f4(String, int) |
(Ljava/lang/String;I)D |
void f5(int, String [], char) |
(I[Ljava/lang/String;C)V |
数据交互
基本类型不需要转换,navtive 层直接可以使用,赋值到 c 里面需要强转,如 int uciT->cycleDays = (uint16) cycle_days;
uint16 表示有符号,正数 int16 无符号正负都可以
String 转换
const char *= CBBT_getVersionString();
char*转String
jstring jstrBuf = env->NewStringUTF();
String 转 char*
char *filePath = (char *)(env->GetStringUTFChars(path, NULL));
不用时需要释放
ReleaseStringUTFChars(buf, jstrBuf);
对象
有 jobject 对象
jclass cls = env->GetObjectClass(javaUCI);
创建某个类对象
jclass cls_acr = env->FindClass("com/raiing/cbbtjni/entity_jni/ACR_T"); jmethodID construct_acr = env->GetMethodID(cls_acr, "<init>", "()V"); jobject obj_acr = env->NewObject(cls_acr, construct_acr, "");
给对象某个字段赋值,首先获取字段 id,再给字段赋值 jfieldID originFieldID = env->GetFieldID(cls_acr, "origin", "I"); env->SetIntField(obj_acr, originFieldID, (jint) acrT->origin); jfieldID extraDataFieldID = env->GetFieldID(cls, "extraData", "[B");
对象集合 ArrayList<Entity>,给集合添加对象
jclass cls_ArrayList = env->GetObjectClass(jobject);
jmethodID arrayList_add = env->GetMethodID(cls_ArrayList, "add", "(Ljava/lang/Object;)Z");
env->CallBooleanMethod(jobject, arrayList_add, obj_cbbt); env->DeleteLocalRef(obj_cbbt);
获取集合里面的对象
jmethodID arraylist_get = env->GetMethodID(cls_arraylist, "get", "(I)Ljava/lang/Object;"); jobject obj_uci = env->CallObjectMethod(jobject, arraylist_get, i); env->DeleteLocalRef(obj_uci);
循环操作里面一定要删除引用,否则会有 512 的限制,如:jbytearray jstring jclass jobject
数组类型数据赋值给 c 层
jbyteArray extraData = (jbyteArray) env->GetObjectField(obj,
extraDataFieldID);
int size = env->GetArrayLength(extraData);
jbyte *ed = (jbyte *) cbbt.extraData; env->GetByteArrayRegion(, 0, size, ed); env->DeleteLocalRef(extraData);
c 层数组赋值给 java
jbyteArray jbarray = env->NewByteArray(len);
jbyte *jb = env->GetByteArrayElements(jbarray, 0);
memcpy(jb, cbbt->extraData, len);
env->SetByteArrayRegion(jbarray, 0, len, jb);
输入输出
c
int8 ABBT_getExpectedDataRange(uint32 currentTime, int32 timeZone, uint32 *startTime,
uint32 *endTime);
java
private native int getExpectedDataRange(long currentTime, long timeZone, Long startTime,
Long endTime);
cpp
JNIEXPORT jint JNICALL Java_com_raiing_ABBTSurface_getExpectedDataRange(
JNIEnv *env, jobject obj, jlong curTime, jlong timeZone,
jobject startTime, jobject endTime)
jclass cls = env->GetObjectClass(retObject);
jmethodID codeMethodID = env->GetMethodID(cls, "<init>", "(J)V");
env->CallVoidMethod(startTime, codeMethodID, retLong);
java 层错误的写法
Integer startTime = 0;
Integer endTime = 0;
两者指向的同一个内存地址,再 c 层输出修改的时候,本来输出两个值,就变为了一个
查看 ndk 崩溃 log
需要的 So 文件在 objlocalarm64-v8alibCBBT.so
S:Android_SDK dk-bundle oolchains Eclipse jni 提示
异常问题
建的工程没有 c/c++ build 支持,工程右键 android tools
Log 占位符
C 语言中输入输出函数占位符介绍 : 占位符 数据类型
%d
int
%ld
long int
%c char
%f float
&lf double
%x 十六进制
%O 八进制
%s 字符串
--> Add native Support
Project Properties -> C/C++ General -> Path and Symbols
选择 include 标签,
Add -> $Android_NDK_HOME/platforms/android-14/arch-arm/usr/include 任意版本
选中 All languages.
最后 Apply -> OK
Log 测试不能输出 long uint64,需要分解为 uint32 LOGV("java2SYMPTOM->UEI_SYMPTOM_T 结构体 111: symptomTypeH jj
h:%u,l:%u", (uint32)(symptomTypeH>>32),(uint32)(symptomTypeH));
学习网址
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html http://home.pacifier.com/~mmead/jni/cs510ajp/index.html#JNI Data Types
http://blog.csdn.net/woshinia/article/details/25132353
http://blog.csdn.net/u012690435/article/details/38612461 参数传递 http://mysuperbaby.iteye.com/blog/1603817 DeleteLocalRef 问题
http://www.oschina.net/question/2241352_213433 addr2line 定位 jni 问题行号