一,注册java方法和jni方法相对应
static const JNINativeMethod gMethods[] = {
//name //signature //funcPtr
{"testObjectJNI","(Lcom/zero/sdk/jnitest/TestMsg;)I",(void *)jni_test},
};
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本
return -1;
jclass clazz = env->FindClass(JAVA_CLASS_PATH);
if (!clazz){
LOGW("cannot get class");
return -1;
}
if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])))
{
LOGW("register native method failed!");
return -1;
}
return JNI_VERSION_1_4;
}
二,通过接口传递java类
java定义接口
private native int testObjectJNI(TestMsg responseMsg)
c++定义接口
static jint jni_test(JNIEnv* pEnv, jobject , jobject arg)
{}
三,java层创建对象传递并通过native接口传递到c++层
TestMsg testMsg = new TestMsg();
testMsg.msg = "server is hungry!";
testMsg.subTestMsg = new TestMsg.SubTestMsg();
testObjectJNI(testMsg); //调用native通信接口
System.out.println("=================code:"+testMsg.code+";msg:"+ testMsg.msg+";subMsg:"+testMsg.subTestMsg.subMsg);
四,c++层获取java类以及其成员数据并修改设置
const char* buf = "code is success";
const char* subBuf = "sub code is success";
static jint jni_test(JNIEnv* pEnv, jobject , jobject arg)
{
jclass jcarg =GetClassOrDie(pEnv,arg);
jfieldID iid = GetFieldIDOrDie(pEnv,jcarg, "code", "I");
pEnv->SetIntField(arg,iid,200);
jfieldID strid = GetFieldIDOrDie(pEnv,jcarg, "msg", "Ljava/lang/String;");
SetChar2JString(pEnv,arg,strid,buf);
jfieldID subMsgId = GetFieldIDOrDie(pEnv,jcarg,"subTestMsg","Lcom/zero/sdk/jnitest/TestMsg$SubTestMsg;");
if (!subMsgId){
LOGW("===========================subMsgId is null");
}
jobject subObj = pEnv->GetObjectField(arg, subMsgId);
if (!subObj){
LOGW("===========================subObj is null");
}
jclass subClass = FindClassOrDie(pEnv,"com/zero/sdk/jnitest/TestMsg$SubTestMsg");
if (!subClass) {
LOGW("===========================findClass is null");
}
jfieldID subStrid = GetFieldIDOrDie(pEnv,subClass,"subMsg", "Ljava/lang/String;");
if (!subStrid){
LOGW("===========================subStrid is null");
}
SetChar2JString(pEnv,subObj,subStrid,subBuf);
return 0;
}
附完整实现code:
c++实现接口
#include <jni.h>
#include <string>
#include <android/log.h>
#include "core_jni_helpers.h"
#define TAG "SceneManager" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
extern "C" JNIEXPORT jstring JNICALL
Java_com_zero_sdk_jnitest_MainActivity_stringFromJNI(
JNIEnv *env,
jobject obj) {
std::string hello = "Hello from C++";
jstring jstr = env->NewStringUTF(hello.c_str());
return jstr;
}
const char* SCENE_REMOTE_PROXY_PATH = "com/zero/sdk/jnitest/MainActivity";
const char* buf = "code is success";
const char* subBuf = "sub code is success";
static jint jni_test(JNIEnv* pEnv, jobject , jobject arg)
{
jclass jcarg =GetClassOrDie(pEnv,arg);
jfieldID iid = GetFieldIDOrDie(pEnv,jcarg, "code", "I");
pEnv->SetIntField(arg,iid,200);
jfieldID strid = GetFieldIDOrDie(pEnv,jcarg, "msg", "Ljava/lang/String;");
SetChar2JString(pEnv,arg,strid,buf);
jfieldID subMsgId = GetFieldIDOrDie(pEnv,jcarg,"subTestMsg","Lcom/zero/sdk/jnitest/TestMsg$SubTestMsg;");
if (!subMsgId){
LOGW("===========================subMsgId is null");
}
jobject subObj = pEnv->GetObjectField(arg, subMsgId);
if (!subObj){
LOGW("===========================subObj is null");
}
jclass subClass = FindClassOrDie(pEnv,"com/zero/sdk/jnitest/TestMsg$SubTestMsg");
if (!subClass) {
LOGW("===========================findClass is null");
}
jfieldID subStrid = GetFieldIDOrDie(pEnv,subClass,"subMsg", "Ljava/lang/String;");
if (!subStrid){
LOGW("===========================subStrid is null");
}
SetChar2JString(pEnv,subObj,subStrid,subBuf);
return 0;
}
static const JNINativeMethod gMethods[] = {
//name //signature //funcPtr
{"testObjectJNI","(Lcom/zero/sdk/jnitest/TestMsg;)I",(void *)jni_test},
};
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本
return -1;
jclass clazz = env->FindClass(SCENE_REMOTE_PROXY_PATH);
if (!clazz){
LOGW("cannot get class SceneRemoteProxy");
return -1;
}
if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])))
{
LOGW("register native method failed!");
return -1;
}
return JNI_VERSION_1_4;
}
java调用
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
TestMsg testMsg = new TestMsg();
testMsg.msg = "server is hungry!";
testMsg.subTestMsg = new TestMsg.SubTestMsg();
// ResponseMsg resMsg = returnRespose();
testObjectJNI(testMsg);
System.out.println("=================code:"+testMsg.code+";msg:"+ testMsg.msg+";subMsg:"+testMsg.subTestMsg.subMsg);
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
private native int testObjectJNI(TestMsg responseMsg);
java数据结构
package com.zero.sdk.jnitest;
public class TestMsg {
public String msg;
public int code;
public SubTestMsg subTestMsg;
public static class SubTestMsg{
public String subMsg;
}
}
jni 方法封装类
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CORE_JNI_HELPERS
#define CORE_JNI_HELPERS
// Defines some helpful functions.
#ifdef NDEBUG
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
#else
#define REG_JNI(name) { name, #name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
const char* mName;
};
#endif
static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
jclass clazz = env->FindClass(class_name);
return clazz;
}
static inline jclass GetClassOrDie(JNIEnv* env, jobject arg) {
jclass jcarg = env->GetObjectClass(arg);
return jcarg;
}
static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
return res;
}
static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
return res;
}
static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
const char* field_signature) {
jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
return res;
}
static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
const char* method_signature) {
jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
return res;
}
static inline void SetChar2JString(JNIEnv* env,jobject obj,jfieldID id, const char* value) {
jstring strBuf = env->NewStringUTF(value);
env->SetObjectField(obj, id, strBuf);
}
template <typename T>
static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
jobject res = env->NewGlobalRef(in);
return static_cast<T>(res);
}
#endif // CORE_JNI_HELPERS