您的位置:首页 > 移动开发 > Android开发

Android:通过JNI调用c++代码

2016-11-16 14:30 405 查看
一些说明



//查找JNIAPI类,得到类的class,包名每级用/分隔

jclass clazz = env->FindClass("com/g/im/JNIAPI");

//通过类查找静态方法,得到方法的引用,callBackLogin为方法名称,"Ljava/lang/String;"表示函数参数为String类型,要用括号括起来,V表示函数返回值为void

jmethodID methodId = env -> GetStaticMethodID(clazz, "callBackLogin", "(Ljava/lang/String;)V")

//调用此方法,第三个参数为

env->CallStaticVoidMethod(clazz, id, jstring类型的字符串)

在JNI中与Java类型对应的类型如下,一个方法有多个参数时直接组合使用:

类类型:L包名/类名;  需要以分号结尾,如:Ljava/lang/String;

类类型[]:[L包名/类名;  需要以分号结尾,如:[Ljava/lang/String;

boolean:Z        如:env -> GetStaticMethodID(clazz, "callBackLogin", "(Z)V")

boolean[]:[Z 

byte:B

byte[]:[B

char:C

char[]:[C

short:S

short[]:[S

int:I

int[]:[I

long:J

long[]:[J

float:F

float[]:[F

double:D

double[]:[D

void:V



Java调用类:

/**
* Java与C/C++互调
* (JNI调用动态库接口)
*/
public class JNIAPI {

static {
System.loadLibrary("GIM");
}

/**
* 登录
*/
public native void login(String username, String ticket, String deviceId);

/**
* C++层异步回调
*/
public void callbackLogin(String   jsonData) {
//解析返回的数据
}
}


与Java对应的.h头文件:

#include <jni.h>
#ifndef _Included_com_g_im_biz_JNIAPI
#define _Included_com_g_im_biz_JNIAPI
#ifdef __cplusplus
extern "C" {
#endif

/**
* 登录
*/
JNIEXPORT void JNICALL Java_com_g_im_biz_JNIAPI_login(JNIEnv *, jobject, jstring, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif


.h的实现cpp文件,此类用于java与c++交互数据用:

#include <string.h>
#include <jni.h>
#include <locale.h>
#include <stdlib.h>
#include <list>
#include <vector>
#include "com_g_im_biz_JNIAPI.h"
#include "com_g_im_biz_JNIAPI_impl.h"
#include "GTPIM/common/CommUtility.h"
#include<stdio.h>
#include <android/log.h>
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ProjectName", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "ProjectName", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ProjectName", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ProjectName", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ProjectName", __VA_ARGS__)

JavaVM* mJvm;
jobject mJNIAPI_obj;
jobject mStr_obj;
void processSignal(int signo);

/**jstring转换char**/
char* jstringToChar(JNIEnv* env, jstring jstr) {
  if (jstr == NULL){
    return NULL;
  }
  char* rtn = new char;
  jclass clsstring = env->FindClass("java/lang/String");
  jstring strencode = env->NewStringUTF("utf-8");
  jmethodID mid = env->GetMethodID(clsstring, "getBytes","(Ljava/lang/String;)[B");
  jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
  jsize alen = env->GetArrayLength(barr);
  jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
  if (alen > 0){
    rtn = (char*) malloc(alen + 1);
    memcpy(rtn, ba, alen);
    rtn[alen] = 0;
  }else {
    rtn = "";
  }

  /**资源清理**/
  env->ReleaseByteArrayElements(barr, ba, 0);
  if(clsstring != NULL){
    env->DeleteLocalRef(clsstring);
    clsstring = NULL;
  }
  if(strencode != NULL){
    env->DeleteLocalRef(strencode);
    strencode = NULL;
  }
  mid = NULL;
  return rtn;
}

/**char转换jstring**/
jstring charToJstring(JNIEnv* env, const char* pat){
  jclass str_class = env->GetObjectClass(mStr_obj);
  jmethodID ctorID = env->GetMethodID(str_class, "<init>", "([BLjava/lang/String;)V");
  jbyteArray bytes = env->NewByteArray(strlen(pat));
  env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
  jstring encoding = env->NewStringUTF("utf-8");

  jstring str = (jstring)env->NewObject(str_class, ctorID, bytes, encoding);
  jbyte* ba = env->GetByteArrayElements(bytes, JNI_FALSE);

  /**资源清理**/
  env->ReleaseByteArrayElements(bytes, ba, 0);
  if(str_class != NULL){
    env->DeleteLocalRef(str_class);
    str_class = NULL;
  }
  if(encoding != NULL){
    env->DeleteLocalRef(encoding);
    encoding = NULL;
  }
  ctorID = NULL;
  return str;
}

/**得到对象**/
jobject getInstance(JNIEnv* env, jclass JNIAPI_class){
  jmethodID JNIAPI_method = env->GetMethodID(JNIAPI_class, "<init>", "()V");
  jobject JNIAPI_obj = env->NewObject(JNIAPI_class, JNIAPI_method);
  return JNIAPI_obj;
}

/**
* 回调java中的方法
* @param methodName 方法名
* @param jsonData json数据
*/
void callbackJava(const char*  methodName, const char*  jsonData){
  JNIEnv* env;
  int status = mJvm->AttachCurrentThread(&env, NULL);
  if(status >= 0){
    jclass JNIAPI_class = env->GetObjectClass(mJNIAPI_obj);
    jmethodID JNIAPI_method = env->GetMethodID(JNIAPI_class, methodName,"(Ljava/lang/String;)V");
    if(JNIAPI_method != 0){
    jstring str = charToJstring(env, xmlData);
      env->CallVoidMethod(mJNIAPI_obj, JNIAPI_method, str);

      /**资源清理**/
      if(JNIAPI_class != NULL){
        env->DeleteLocalRef(JNIAPI_class);
        JNIAPI_class = NULL;
      }
      if(str != NULL){
        env->DeleteLocalRef(str);
        str = NULL;
      }
    JNIAPI_method = NULL;
    }
    if(strcmp(methodName, "printSignLog") != 0 && strcmp(methodName,"addMsgCache") != 0 && strcmp(methodName,"removeMsgCache") != 0){
      mJvm->DetachCurrentThread();
    }
  }
}

/**
* 登录
*/
JNIEXPORT void JNICALL Java_com_glodon_im_service_JNIAPI_login(JNIEnv* env, jobject thiz, jstring name, jstring ticket, jstring deviceId) {
  char* rtticket = jstringToChar(env, ticket);
  char* rtdeviceId = jstringToChar(env, deviceId);
  comm.login(rtname, rtticket, rtdeviceId);
  if(rtname != NULL){
    free(rtname);
    rtname = NULL;
  }
  if(rtticket != NULL){
    free(rtticket);
    rtticket = NULL;
  }
  if(rtdeviceId != NULL){
    free(rtdeviceId);
    rtdeviceId = NULL;
  }
}

void callbackLogin(const char* jsonData){
  callbackJava("callbackLogin", jsonData);
}


与上面对应的.h头文件:

#include <string.h>
#include <jni.h>
#include <locale.h>
#include <stdlib.h>
#include <signal.h>
#include <list>
#include <vector>
#include <android/log.h>

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ProjectName", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "ProjectName", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ProjectName", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ProjectName", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ProjectName", __VA_ARGS__)

void callbackLogin(const char*  jsonData);


Android.mk文件:

#指定Android.mk的路径
LOCAL_PATH := $(call my-dir)

#用于重置除LOCAL_PATH变量外的,所有LOCAL_XXX系列变量
include $(CLEAR_VARS)

#使用标准库,系统默认使用system(最小的C++运行库,部分功能将无法支持)
APP_STL  :=  stlport_static

include $(BUILD_MULTI_PREBUILT)

#在所有源文件中增加一个宏定义#define MARKUP_STDCONV
LOCAL_CFLAGS := \
-DMARKUP_STDCONV

#生成的so文件名
LOCAL_MODULE    := GIM

$(warning  $(SYSROOT))

#添加系统库
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

#需要参与编译的cpp源文件
LOCAL_SRC_FILES := \
com_g_im_biz_JNIAPI_impl.cpp \

#编译静态库
#include $(BUILD_STATIC_LIBRARY)

#编译动态库
include $(BUILD_SHARED_LIBRARY)


Application.mk文件:

#                                C++异常   C++ RTTI   C++标准库
#System默认的                     不支持    不支持     不支持
#gabi++_shared、gabi++_static     不支持     支持      不支持
#stlport_shared、stlport_static   不支持     支持       支持
#gnustl_shared、gnustl_static      支持      支持       支持
APP_STL := gnustl_static

#表示生成哪些CPU架构的so,有这些值:all、armeabi、armeabi-v7a、x86、mips
#APP_ABI := armeabi armeabi-v7a

#STLPORT_FORCE_REBUILD := true

#可以使用APP_GNUSTL_CPP_FEATURES,指使用C++异常(exceptions)或C++ RTTI特性(rtti)
APP_CPPFLAGS += -fexceptions

#NDK版本号
APP_PLATFORM := android-9
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: