1、JNI简介

The Java Native Interface (JNI) is a programming framework that enables Java code running in a Java Virtual Machine (JVM) to call and be called by[1] native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly.

   --引用于wiki

官方文档

2、Java调用C

  2.1、java类文件中定义本地方法,其他方法调用此本地方法

    下面给出三个比较有代表性的方法:

    1、传递java对象  public static native int JNVSDKDEVOpen(ConfigObj config);

    2、返回java对象  public static native ResultObj JNVSDKDEVGetConfig(int i, int type);

    3、回调java方法  public static native int JNVSDKDEVStatusCallback();

jniFactory.java    

package com.xxxx.xxxxplayer.jni;
import com.xxxx.xxxxplayer.conf.ConfigObj;
import com.xxxx.xxxxplayer.modelView.ResultObj;
public class JniFactory { static {
System.loadLibrary("sdk-lib");
} public static native int JNVSDKDEVOpen(ConfigObj config);
public static native ResultObj JNVSDKDEVGetConfig(int i, int type);
public static native int JNVSDKDEVStatusCallback();
}

java类型和本地类型对比(主要用于定义JNI规范的方法)

Java Type  Native Type Description
boolean jboolean unsigned 8 bits
byte jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
int jint signed 32 bits
long jlong signed 64 bits
float jfloat 32 bits
double jdouble 64 bits
void void not applicable

java类型标识(主要用于在JNI规范的方法中获取java对象的相关属性)

Type Signature  Java Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

 

  2.2、编写本地方法的实现

sdk-lib.c  

#include <jni.h>
#include "jnvsdk_net_interface.h"
#include <stdlib.h>
#define TAG "SDK_LIB>>" // 这个是自定义的LOG的标识 JNVSDK_HANDLE handle;//全局handle初始化之后其他函数都引用此变量
JavaVM *gs_jvm=NULL;//全局JavaVM,用于C主动调用java方法,用于UI刷新
jclass g_jniActClass=NULL;//保存主Activity的类,用于UI刷新 int JNVSDKCallback(JNVSDK_HANDLE jnvsdk_handle, int iChn, int cmdType, int cmdType2, char *ptr, int dataLen); jint Java_com_xxxx_xxxxplayer_jni_JniFactory_JNVSDKDEVOpen
( JNIEnv* env, jobject jobj , jobject config)
{ //第一种获取java对象参数的方法
//jclass clazz=(*env)->FindClass(env,"com/xxxx/xxxxplayer/conf/ConfigObj"); //第二种获取java对象参数的方法
jclass clazz=(*env)->GetObjectClass(env,config);
if(clazz==NULL){
return 0;
} //获取java对象的字段
jfieldID device_ip=(*env)->GetFieldID(env,clazz,"device_ip","Ljava/lang/String;");
jfieldID device_port=(*env)->GetFieldID(env,clazz,"device_port","I");
jfieldID uname=(*env)->GetFieldID(env,clazz,"uname","Ljava/lang/String;");
jfieldID password=(*env)->GetFieldID(env,clazz,"password","Ljava/lang/String;"); //第一种获取字段值的方法(直接获取)
jstring test = (jstring)(*env)->GetObjectField(env,config,uname);
const char *test_uname_ = (*env)->GetStringUTFChars(env,test ,NULL); //第二种获取字段值的方法(通过java对象提供的getxx()获取)
jmethodID mid = (*env)->GetMethodID(env,clazz, "getUname", "()Ljava/lang/String;");
jstring strObj = (jstring)(*env)->CallObjectMethod(env,config, mid);
const char *uname_ = (*env)->GetStringUTFChars(env,strObj ,NULL);   ... //将java对象封装到结构体
strcpy(u_info.username,uname_); //调用目标方法
return JNVSDK_DEV_Open(&handle,u_info,n_info); } jobject Java_com_xxxx_xxxxplayer_jni_JniFactory_JNVSDKDEVGetConfig
( JNIEnv* env, jobject jobj ,jint iChn ,jint cfgType)
{
//得到返回对象的类和初始化方法
jclass clazz = (*env)->FindClass(env,"com/xxxx/xxxxplayer/modelView/ResultObj");
jmethodID method_init = (*env)->GetMethodID(env,clazz,"<init>","()V"); //获取java对象的字段
jfieldID resultNum = (*env)->GetFieldID(env,clazz, "resultNum", "I");
jfieldID resultStr = (*env)->GetFieldID(env,clazz, "resultStr", "Ljava/lang/String;"); //创建java对象
jobject return_Obj = (*env)->NewObject(env,clazz, method_init); int result=0;
char result_str[128]="";
division_display_cfg_t st;
switch(cfgType){
case 51:
result= JNVSDK_DEV_GetConfig(handle, iChn, cfgType, (char *)&st, sizeof(st));
//向对象设值
(*env)->SetIntField(env,return_Obj,resultNum,result);
int length = sizeof(st.display_mode)/sizeof(st.display_mode[0]);
for(int i=0;i<length;i++){
char tmp[10];
sprintf(tmp, "%d",st.display_mode[i]);
strcat(tmp,";");
strcat(result_str,tmp);
}
//向对象设值
(*env)->SetObjectField(env,return_Obj,resultStr,(*env)->NewStringUTF(env,result_str));
break;
}
//返回对象
return return_Obj;
}

  2.3、调用非JNI规范的C方法

    这在上一步已经实现,单独列出是强调java调用非JNI规范的库该做些什么。

    项目需要调用两类库文件:

    1、libvlcjni.so(JNI规范),这是VLClan提供的,并且还提供了java类,这种情形下我们只需要关注java层面的接口就好了。

    2、libjnvsdk.a(非JNI规范),这类比较麻烦,需要自己编写JNI规范的c文件,再调用libjnvsdk.a的头文件libjnvsdk.h里的方法,所以这种情形下我们需要库文件(*.so/*.a)以及对应的头文件。

    我在下面给的示例都是非JNI规范的。至于怎么将这类库编译生成JNI规范的动/静态库,我在这篇博文已交代。

3、C调用Java

  3.1、项目背景

    项目是安卓平台的APP,用于直播,监控。程序主代码还是java,库文件提供额外功能。大多JNI项目是单向的,双向较少。

    本项目出现C调用java是由于服务器(c开发)要向客户端(web,android,ios,qt)发送同步UI的数据,app获取数据后更新UI。

sdk-lib.c

jint  Java_com_xxxx_xxxxplayer_jni_JniFactory_JNVSDKDEVStatusCallback
( JNIEnv* env, jobject jobject )
{ jclass jniActClass = (*env)->FindClass(env, "com/xxxx/xxxxplayer/activity/VideoActivity");
(*env)->GetJavaVM(env,&gs_jvm); //保存到全局变量中
g_jniActClass = (*env)->NewGlobalRef(env,jniActClass);//保存到全局变量中
jint result= JNVSDK_DEV_RegisterRefreshCfgAndStatusCallback(JNVSDKCallback);//注册回调函数,c端数据更新会调用JNVSDKCallback
return result;
} int (JNVSDK_HANDLE jnvsdk_handle, int iChn, int cmdType, int cmdType2, char *ptr, int dataLen)
{
  division_display_status_t *divi_display = (division_display_status_t *)ptr;
JNIEnv *jnienv;
  //将全局的jvm加到当前线程
(*gs_jvm)->AttachCurrentThread(gs_jvm,&jnienv, NULL);
  //得到VideoActivity中的jniCallback4java方法,然后调用
jmethodID jniCallback4java = (*jnienv)->GetStaticMethodID(jnienv, g_jniActClass, "jniCallback4java", "(Ljava/lang/String;)V");
(*jnienv)->CallStaticVoidMethod(jnienv, g_jniActClass, jniCallback4java,(*jnienv)->NewStringUTF(jnienv, "OOOOOOOOOOOO")); }

VideoActivity.java

public class VideoActivity extends Activity {

  @Override
public void onCreate(Bundle savedInstanceState) { mHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle tBundle=msg.getData();
String jni_msg=tBundle.getString("JNI_MSG");
Log.e(TAG,jni_msg);
       //更新UI
      ...
} }; } //***callback*********JNVSDKCallback调用此函数,负责发送更新UI信息
public static void jniCallback4java(String msg){
Message tMsg=new Message();
Bundle tBundle=new Bundle();
tBundle.putString("JNI_MSG", msg);
tMsg.setData(tBundle);
mHandler.sendMessage(tMsg);
} }

4、异常处理和内存管理

  待续...

JNI打通java和c的更多相关文章

  1. HAL中通过JNI调用java方法【转】

    转载请注明本文出处:http://www.cnblogs.com/xl19862005 作者:Xandy 由于工作的需要,最近一直在研究HAL.JNI.Java方法之间互调的问题,并做了如下一些记录和 ...

  2. Android NDK开发之Jni调用Java对象

    https://my.oschina.net/zhiweiofli/blog/114064 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instan ...

  3. android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )

    JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...

  4. Android JNI之JAVA与C++对象建立对称关联(JNI优化设计,确保JNI调用的稳定性)

    转载请声明:原文转自:http://www.cnblogs.com/xiezie/p/5930503.html Android JNI之JAVA与C++对象建立对称关联 1.JAVA对象持有C++对象 ...

  5. cocos2d-x由Jni实现Java与C++打电话给对方

    cocos2d-x由Jni实现Java与C++打电话给对方. cocos2d-x与开发商提供一个类JniHelper,提供java与c++之间的互jni解. 笔者所开发的"史上最坑爹的游戏& ...

  6. Android Studio NDK开发-JNI调用Java方法

    相对于NDK来说SDK里面有更多API可以调用,有时候我们在做NDK开发的时候,需要在JNI直接Java中的方法和变量,比如callback,系统信息等.... 如何在JNI中调用Java方法呢?就需 ...

  7. Android 通过 JNI 访问 Java 字段和方法调用

    在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型.字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系. 有了之前那些基础,就可以实现 Jav ...

  8. 【详解】JNI(Java Native Interface)(一)

    前言: 一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧.它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互 ...

  9. Android JNI访问Java成员

    在 JNI 调用中,不仅仅 Java 可以调用本地方法,本地方法也可以调用 Java 中的方法和成员变量. Java 中的类封装了属性和方法,想要访问 Java 中的属性和方法,首先要获得 Java ...

随机推荐

  1. MT【62】柯西求三角值域

    求$sinx(\sqrt{cos^2x+24}-cosx)$的范围. 解答:[-5,5] $$\because (sinx \sqrt{cos^2x+24}-cosxsinx)^2$$ $$\le ( ...

  2. 【Luogu4512】多项式除法(FFT)

    题面 洛谷 题解 模板题... 我直接蒯我写的东西... 这个除法是带余除法,所以并不能直接求逆解决. 要求的就是给定两个多项式\(A(x),B(x)\),其项数为\(n,m\) 求解一个\(n-m\ ...

  3. Linux中如何运行.AppImage文件

    今天在GitHub上发现了一个upterm( https://github.com/railsware/upterm )的开源项目,和其他的并不太一样,对于Linux发行版本只提供了AppImage的 ...

  4. UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There Was One / POJ 3517 And Then There Was One / Aizu 1275 And Then There Was One (动态规划,思维题)

    UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There W ...

  5. CF 1000

    水爆了...... 当然不是题目水,而是我水. 第一题,看完题目我稍微惊了一下,有点难度(并不). 开个map,先加后减,统计正数即可. 第二题,看完我冷汗就流下来了,有点难啊,这是B难度? 趴床上推 ...

  6. StringTokenizer 的性能看来真的不用担心

    一直以来,分析HTTP的Header使用的都是StringTokenizer,但是看过jdk中关于StringTokenizer的介绍: StringTokenizer 是出于兼容性的原因而被保留的遗 ...

  7. react中多语言切换的实现方式

    目前正在进行的项目就是一个多语言切换的项目,有些前情知识我们可以 从https://react.i18next.com/getting-started进行了解. 说到使用方法,当然首先是要$ npm ...

  8. babel与ES6环境的搭建

    我们知道浏览器环境下直接运行ES6是存在一些兼容性问题的.那么把ES6变成ES5不就行了吗? 那如何将ES6转换成ES5呢?我们来搭建它的转换环境吧~ 第一步:初始化项目,建立写注意事项的README ...

  9. 2018.9青岛网络预选赛(K)

    传送门:Problem K https://www.cnblogs.com/violet-acmer/p/9664805.html 题意: 给你n个数,找出满足条件的最多的数的个数. 题解: 满足条件 ...

  10. RESTful框架简述

    什么是RESTful架构: (1)每一个URI代表一种资源: (2)客户端和服务器之间,传递这种资源的某种表现层: (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态 ...