本文假设读者使用cmake方式编写jni代码,并且已经学会基本数据类型的jni传递!
一、传递对象,这里使用自定义User对象举例:
1、首先在java层定义native函数,并且loadLibrary库
public static native User sendUser(User obj);
static {
System.loadLibrary("JNIDemo");
}
2、编写测试类代码,这里就是在Activity加了个TextView,显示jni返回的值
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.sample_text);
User user = new User();
User.BaseUser baseUser = user.new BaseUser();
baseUser.setBaseName("李世民");
user.setName("大唐");
user.setAge(619);
tv.setText(JniUtils.sendUser(user).toString());
}
}
3、cmakelists.txt文件中
cmake_minimum_required(VERSION 3.4.1)
add_library(JNIDemo SHARED JNIDemo.cpp)
find_library(log-lib log)
target_link_libraries(JNIDemo ${log-lib})
4、JNIDemo.cpp文件中实现对应的代码
#include <jni.h>
#include <string>
#include <android/log.h>
#define LOG_TAG "JniDome"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
const char *userCalssName = "com/example/jnidemo/User";
jobject sendUser(JNIEnv *env, jobject job, jobject objData) {
//根据全路径类名查找到java对象
jclass user = env->FindClass(userCalssName);
//根据java对象、成员属性名、属性签名查找 到对象的成员变量
jfieldID userName = env->GetFieldID(user, "name", "Ljava/lang/String;");
jfieldID userAge = env->GetFieldID(user, "age", "I");
jstring jniStrUserName = (jstring) env->GetObjectField(objData, userName);
const char *usetNameStr = env->GetStringUTFChars(jniStrUserName, 0);
jint jniUserAge = (jint) env->GetIntField(objData, userAge);
LOGI("%s%d", usetNameStr, jniUserAge);
//创建Object,返回java上层
jmethodID jObjectUserConstructor = env->GetMethodID(user,"<init>","()V");
jobject jObjectUser = env->NewObject(user,jObjectUserConstructor);
env->SetIntField(jObjectUser,userAge,15);
jstring jStringUserName = env->NewStringUTF(usetNameStr);
env->SetObjectField(jObjectUser,userName,jStringUserName);
//释放内存
//env->ReleaseByteArrayElements(byteArry,byteArray,0);
return jObjectUser;
}
const char *jniClassName = "com/example/jnidemo/JniUtils";
const JNINativeMethod getMethods[] = {{"sendUser",
"(Lcom/example/jnidemo/User;)Lcom/example/jnidemo/User;",
(void *) sendUser}};
jint RegisterNative(JNIEnv *env) {
//获取映射的Java类
jclass javaClass = env->FindClass(jniClassName);
if (javaClass == NULL) {
printf("cannot get class : %s\n", jniClassName);
return -1;
}
return env->RegisterNatives(javaClass, getMethods, sizeof(getMethods) / sizeof(getMethods[0]));
}
//jni函数入口,类似main函数
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGE("jni_onload_start");
//注册时在JNIEnv中实现,所以必须首先获取它
JNIEnv *env = NULL;
jint result = -1;
//从JavaVM中获取JNIEnv,一般使用1.4的版本
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return result;
}
result = RegisterNative(env);
LOGE("RegisterNatives result:%d", result);
LOGE("jni_onload_end");
return JNI_VERSION_1_4;//必须返回版本,否则加载会失败
}
demo很简单,注释基本上看明白流程,跑一遍代码应当就能学会,有问题欢迎大佬们斧正