语言混编之java调用c_Java通过JNI调用C语言库
本文中以Java调用C语言Android增量更新bsdiff库为例进行说明。下图流程图为先定义java中方法,然后修改C语言库的方法以达到生成动态库以供调用的方式;当然,C语言库的方法调用同样可以先定义好,然后再写java的方法来调用。目的只有一个是保持方法调用和定义的一致性。流程图1 编写java文件package com.gccy.utils;public class BspatchUtils
本文中以Java调用C语言Android增量更新bsdiff库为例进行说明。下图流程图为先定义java中方法,然后修改C语言库的方法以达到生成动态库以供调用的方式;当然,C语言库的方法调用同样可以先定义好,然后再写java的方法来调用。目的只有一个是保持方法调用和定义的一致性。
流程图
1 编写java文件
package com.gccy.utils;
public class BspatchUtils {
/**
* 定义apk差分方法接口
* 在C中实现
*/
public static native int bspatch(String oldApk, String newApk, String patch);
}
此处创建的java类文件是包含包名的,在后续编译、生成头文件的时候需要注意。
2 编译java文件
# 创建目录
mkdir -p com/gccy/utils
# 将java文件移至目录下
mv BspatchUtils.java com/gccy/utils/
# 编译java文件
javac com/gccy/utils/BspatchUtils.java
创建包路径,并将类文件放入该目录下后执行编译操作。(当然直接编译也是可以的,但是后续头文件的生成是需要的,索性在这一步就给创建了)如果你是直接在项目目录中进行编译的则不需要此步骤。
3 生成头文件
# 默认头文件生成在当前目录
javah com.gccy.utils.BspatchUtils
文件名称:com_gccy_utils_BspatchUtils.h 文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_gccy_utils_BspatchUtils */
#ifndef _Included_com_gccy_utils_BspatchUtils
#define _Included_com_gccy_utils_BspatchUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_gccy_utils_BspatchUtils
* Method: bspatch
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_gccy_utils_BspatchUtils_bspatch
(JNIEnv *, jclass, jstring, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
4 编写c文件
本文中并非自己写C函数的实现方法,而是将接口的实现改为调用差分函数,只是简单的调用不涉及接口的实现。
将上述生成头文件的接口与bsdiff.c文件合并(即将该接口作为调用bsdiff.c内差分函数的入口)
#include "jni.h"
#include
/*
* Class: com_gccy_utils_BspatchUtils
* Method: bspatch
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_gccy_utils_BspatchUtils_bspatch
(JNIEnv *env, jclass jc, jstring old, jstring new, jstring patch) {
int argc = 4;
char * argv[argc];
argv[0] = "bspatch";
argv[1] = (char*) ((*env)->GetStringUTFChars(env, old, 0));
argv[2] = (char*) ((*env)->GetStringUTFChars(env, new, 0));
argv[3] = (char*) ((*env)->GetStringUTFChars(env, patch, 0));
//修改的main
int ret = bspatch(argc, argv);
(*env)->ReleaseStringUTFChars(env, old, argv[1]);
(*env)->ReleaseStringUTFChars(env, new, argv[2]);
(*env)->ReleaseStringUTFChars(env, patch, argv[3]);
return ret;
}
5 编译c文件生成so库
编译所依赖的头文件:jni.h、jni_md.h、bzlib.h
1.前两个h文件在jdk中就含有,可以将其拷贝到指定目录,编译的时候使用
# 查找java安装目录
which java
# 拷贝头文件
cp /data/thirdAssembly/jdk/include/jni.h ./
cp /data/thirdAssembly/jdk/include/linux/jni_md.h ./
2.最后一个h文件需要安装
# jni编译依赖libbz2提前安装
yum install bzip2-devel.x86_64
3.执行编译
gcc -shared -fPIC -lbz2 -I /data/tymiao/ -o libbsdiff.so bsdiff.c
6 调用so库
在1中的基础内写一个main函数来启动调用该方法来验证so库的正确与否。注意此处so库为linux环境中执行!
package com.gccy.utils;
public class BspatchUtils {
/**
* 定义apk差分方法接口在C中实现
*/
public static native int bspatch(String oldApk, String newApk, String patch);
static {
//加载C文件
System.load("/data/so/libbsdiff.so");
}
public static void main(String[] args) {
BspatchUtils bs = new BspatchUtils();
bs.bspatch("/data/apk/old.apk", "/data/apk/new.apk", "/data/patch/increment.patch");
}
}
上述java文件写完成之后直接编译后执行即可,验证是否有increment.patch文件生成。
更多推荐
所有评论(0)