JNI打通java和c
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的更多相关文章
- HAL中通过JNI调用java方法【转】
转载请注明本文出处:http://www.cnblogs.com/xl19862005 作者:Xandy 由于工作的需要,最近一直在研究HAL.JNI.Java方法之间互调的问题,并做了如下一些记录和 ...
- Android NDK开发之Jni调用Java对象
https://my.oschina.net/zhiweiofli/blog/114064 通过使用合适的JNI函数,你可以创建Java对象,get.set 静态(static)和 实例(instan ...
- android 学习随笔二十七(JNI:Java Native Interface,JAVA原生接口 )
JNI(Java Native Interface,JAVA原生接口) 使用JNI可以使Java代码和其他语言写的代码(如C/C++代码)进行交互. 问:为什么要进行交互? 首先,Java语言提供的类 ...
- Android JNI之JAVA与C++对象建立对称关联(JNI优化设计,确保JNI调用的稳定性)
转载请声明:原文转自:http://www.cnblogs.com/xiezie/p/5930503.html Android JNI之JAVA与C++对象建立对称关联 1.JAVA对象持有C++对象 ...
- cocos2d-x由Jni实现Java与C++打电话给对方
cocos2d-x由Jni实现Java与C++打电话给对方. cocos2d-x与开发商提供一个类JniHelper,提供java与c++之间的互jni解. 笔者所开发的"史上最坑爹的游戏& ...
- Android Studio NDK开发-JNI调用Java方法
相对于NDK来说SDK里面有更多API可以调用,有时候我们在做NDK开发的时候,需要在JNI直接Java中的方法和变量,比如callback,系统信息等.... 如何在JNI中调用Java方法呢?就需 ...
- Android 通过 JNI 访问 Java 字段和方法调用
在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型.字符串和数组的相关操作,并描述了 Java 和 Native 在类型和签名之间的转换关系. 有了之前那些基础,就可以实现 Jav ...
- 【详解】JNI(Java Native Interface)(一)
前言: 一提到JNI,多数编程者会下意识地感受到一种无法言喻的恐惧.它给人的第一感觉就是"难",因为它不是单纯地在JVM环境内操作Java代码,而是跳出虚拟机与其他编程语言进行交互 ...
- Android JNI访问Java成员
在 JNI 调用中,不仅仅 Java 可以调用本地方法,本地方法也可以调用 Java 中的方法和成员变量. Java 中的类封装了属性和方法,想要访问 Java 中的属性和方法,首先要获得 Java ...
随机推荐
- MT【62】柯西求三角值域
求$sinx(\sqrt{cos^2x+24}-cosx)$的范围. 解答:[-5,5] $$\because (sinx \sqrt{cos^2x+24}-cosxsinx)^2$$ $$\le ( ...
- 【Luogu4512】多项式除法(FFT)
题面 洛谷 题解 模板题... 我直接蒯我写的东西... 这个除法是带余除法,所以并不能直接求逆解决. 要求的就是给定两个多项式\(A(x),B(x)\),其项数为\(n,m\) 求解一个\(n-m\ ...
- Linux中如何运行.AppImage文件
今天在GitHub上发现了一个upterm( https://github.com/railsware/upterm )的开源项目,和其他的并不太一样,对于Linux发行版本只提供了AppImage的 ...
- 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 ...
- CF 1000
水爆了...... 当然不是题目水,而是我水. 第一题,看完题目我稍微惊了一下,有点难度(并不). 开个map,先加后减,统计正数即可. 第二题,看完我冷汗就流下来了,有点难啊,这是B难度? 趴床上推 ...
- StringTokenizer 的性能看来真的不用担心
一直以来,分析HTTP的Header使用的都是StringTokenizer,但是看过jdk中关于StringTokenizer的介绍: StringTokenizer 是出于兼容性的原因而被保留的遗 ...
- react中多语言切换的实现方式
目前正在进行的项目就是一个多语言切换的项目,有些前情知识我们可以 从https://react.i18next.com/getting-started进行了解. 说到使用方法,当然首先是要$ npm ...
- babel与ES6环境的搭建
我们知道浏览器环境下直接运行ES6是存在一些兼容性问题的.那么把ES6变成ES5不就行了吗? 那如何将ES6转换成ES5呢?我们来搭建它的转换环境吧~ 第一步:初始化项目,建立写注意事项的README ...
- 2018.9青岛网络预选赛(K)
传送门:Problem K https://www.cnblogs.com/violet-acmer/p/9664805.html 题意: 给你n个数,找出满足条件的最多的数的个数. 题解: 满足条件 ...
- RESTful框架简述
什么是RESTful架构: (1)每一个URI代表一种资源: (2)客户端和服务器之间,传递这种资源的某种表现层: (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态 ...