本文中以Java调用C语言Android增量更新bsdiff库为例进行说明。下图流程图为先定义java中方法,然后修改C语言库的方法以达到生成动态库以供调用的方式;当然,C语言库的方法调用同样可以先定义好,然后再写java的方法来调用。目的只有一个是保持方法调用和定义的一致性。

56d1de7ab972

流程图

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文件生成。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐