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返回泛型给easyui
由于之前遇到的easyui调用webapi的问题. 参见 :http://blog.csdn.net/hanjun0612/article/details/51144991 所以就考虑,封装一个泛型用 ...
- IScroll的那些事——内容不足时下拉刷新
之前项目中的列表是采用的IScroll,但是在使用IScroll有一个问题就是:当内容不足全屏的时候,是木有办法往下拉的,这样就达不到刷新的目的了.[这是本人工作中遇到的,具体例子具体分析,这里只作一 ...
- 自学工业控制网络之路1.2-典型的现场总线介绍PROFIBUS
返回 自学工业控制网络之路 自学工业控制网络之路1.2-典型的现场总线介绍PROFIBUS 目前看来,现场总线标准不会统一,多标准并存现象将会持续. 现场总线国家标准: 中国的DeviceNet和AS ...
- 自学Aruba5.1.1-基于时间的Role定义
点击返回:自学Aruba之路 自学Aruba5.1.1-基于时间的Role定义 可以配置一条rule是基于时间来做限制 具体配置时间(Time ranges)步骤如下: 1 建立一个绝对时间范围,命令 ...
- CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度
题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...
- unity开源移动库iTween使用完整Demo
public Vector3[] paths; // Use this for initialization void Start () { paths = ] { , , ), , , -) }; ...
- 【模板】Treap
Treap,又称树堆,是一种通过堆性质来维持BST平衡的数据结构.具体体现在对于树上每一个点来说,既有BST维护的值,又有一个堆维护的随机生成的值.维护平衡性的办法是根据堆维护的值的相对大小关系进行左 ...
- ACCESS与SQL Server下SQL Like 查询的不同
在ACCESS中LIKE的用法Access里like的通配符用法是这样: “?”表示任何单一字符: “*”表示零个或多个字符: “#”表示任何一个数字 所以应该是: select * from dat ...
- httpd服务的安装、配置
httpd服务是架设网站的必须服务下面我就来说下怎么安装配置 1.安装httpd服务 输入下面命令进行安装(如果没网络或者安装速度慢的请设置本地yum源进行安装,设置教程请点击这里查看) yum in ...
- 20190311 Windows安装ZooKeeper
1. 说明 记录过程中踩过的坑 1.1. 环境 本机环境:Win10 ZooKeeper版本:3.4.6 2. 安装 2.1. 下载 官网下载网址 2.2. 修改配置文件 复制conf目录下的zoo_ ...