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 ...
随机推荐
- webapi Filter
webapi的controller和action的控制. 使用场景:webapi接收到加密数据以及签名.验证签名是否有效.我们不能一个个action增加判断. 所以添加Filter是比较明智的方法. ...
- 解析 Android Things 技术原理
2012 年 6 月,由 IoT-GSI(Global Standards Initiative on Internet of Things)发布的白皮书“ITU-T Y.4000/Y.2060”[1 ...
- 架构师成长之路2.2-PXE+Kickstart安装部署
点击返回架构师成长之路 架构师成长之路2.2-PXE+Kickstart安装部署 系统测试环境: 实验环境:VMware Workstation 12 系统平台:CentOS Linux releas ...
- 【BZOJ3879】SvT(后缀自动机,虚树)
[BZOJ3879]SvT(后缀自动机,虚树) 题面 BZOJ 题解 看着这个东西,询问若干个前缀两两之间的\(lcp\)? 显然\(lcp\)就是\(SAM\)构建出来的\(parent\)数上的\ ...
- 【BZOJ1799】[AHOI2009]同类分布(动态规划)
[BZOJ1799][AHOI2009]同类分布(动态规划) 题面 BZOJ 洛谷 题解 很容易想到数位\(dp\),然而数字和整除原数似乎不好记录.没关系,直接枚举数字和就好了,这样子就可以把整除原 ...
- 洛谷 P3253 [JLOI2013]删除物品 解题报告
P3253 [JLOI2013]删除物品 题目描述 箱子再分配问题需要解决如下问题: (1)一共有\(N\)个物品,堆成\(M\)堆. (2)所有物品都是一样的,但是它们有不同的优先级. (3)你只能 ...
- [NOI2017]泳池——概率DP+线性递推
[NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...
- code::Blocks生成的dll 在 java jni 调用遇到的问题
Test.java__________________________________ public class Test{ public static native void p(); pub ...
- 关于移动端及flex
我们知道写pc页面的时候,ui设计图是多少px,我们写网页的时候,就会写多少px,这个其实就是由pc端屏幕的物理像素,和我们设计图的css逻辑像素决定的,由于屏幕的物理像素和css逻辑像素比,刚好是1 ...
- 网络流 KM dinic
study from: https://blog.csdn.net/A_Comme_Amour/article/details/79356220 1. Edmonds-Karp 无优化 最坏时间复杂度 ...