Android基于NDK 实现 bsdiff功能实现
准备
下载所需要c文件,直接解压即可
bsdiff
bzip(bsdiff依赖库)
项目prepare目录已经下载好所需的文件
项目创建
Studio新建c++项目
1.解压bzip到 src/main/cpp/bzip目录 (可以删除后缀不是.c或.h文件,保留文件参考项目)
2.解压bsdiff 到 src/main/cpp/目录
3.配置
#关联bzip目录
file(GLOB bzip bzip/*.c)
#添加需要参与编译的c/c++库
add_library( # Sets the name of the library.
patch # 默认native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${bzip}
# 默认
)
#将bzip目录 include, 不需要写包路径
include_directories(bzip)
4.创建工具类
public class PatchUtil {
static {
("patch"); // 默认native-lib
}
public static native int bsPatch(String old, String patch, String output);
public static native int bsDiff(String old, String newfile, String patch);
}
在方法上使用快捷键ALT+ENTER 自动生成 jni 方法
5.实现bsdiff 和 bspatch 功能
// 声明外部c的方法, bsdiff,和bspatch都有main方法,记得改成不同的方法名
extern "C" {
extern int main(int argc, const char *argv[]);
extern int diff_main(int argc, const char *argv[]);
}
extern "C" JNIEXPORT jint JNICALL
Java_me_leon_patch_PatchUtil_bsDiff(JNIEnv *env, jclass thiz, jstring old, jstring newfile_,jstring patch_) {
// 将jstring 转char * ,因为bspatch的参数需要
const char *oldApk = env->GetStringUTFChars(old, 0);
const char *newFile = env->GetStringUTFChars(newfile_, 0);
const char *output = env->GetStringUTFChars(patch_, 0);
// 调用bsDiff c的方法
const char *argv[] = {"", oldApk, newFile, output};
int r = diff_main(4, argv);
// jstring 释放
// C/C++ 没有java 的gc功能,需要手动释放资源
env->ReleaseStringUTFChars(old, oldApk);
env->ReleaseStringUTFChars(newfile_, newFile);
env->ReleaseStringUTFChars(patch_, output);
return r;
}
extern "C" JNIEXPORT jint JNICALL
Java_me_leon_patch_PatchUtil_bsPatch(JNIEnv *env, jclass thiz, jstring old,
jstring patch_,
jstring output_) {
// 将jstring 转char *
const char *oldApk = jstringToChar(env, old);
const char *patch = jstringToChar(env, patch_);
const char *output = jstringToChar(env, output_);
// 调用bsPatch c的方法
const char *argv[] = {"", oldApk, output, patch};
int r = main(4, argv);
// 资源 释放
env->ReleaseStringUTFChars(old, oldApk);
env->ReleaseStringUTFChars(patch_, patch);
env->ReleaseStringUTFChars(output_, output);
return r;
}
6.编译运行代码
可能会出现CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
原因: 高版本ndk,默认abiFilters 是 armeabi-v7a
解决: 在module defaultConfig闭包添加
ndk{
abiFilters "arm64-v8a","armeabi-v7a","x86","x86_64"
}
7.编译成功后, 编写测试程序,测试PatchUtil的两个方法
页面跟功能请自行实现,加两个Button,实现PatchUtil的功能
如果使用app或demo,请先准备测试文件,
adb push /sdcard/
adb push /sdcard/
8.清单文件配置文件读取权限(高版本需要动态授权)
<uses-permission android:name=".WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name=".READ_EXTERNAL_STORAGE" />
<uses-permission android:name=".REQUEST_INSTALL_PACKAGES"/>
9.测试
返回结果为0表示成功,可用adb 命令查看文件情况
adb shell
cd /sdcard
ll
封装lib给他人使用
- 调用gradle命令生成so库
graldew build
- 新建Android lib项目,包名同c++项目
- 拷贝
- 拷贝 \build\intermediates\merged_native_libs\release\out\lib下所有文件夹 到src/main/jniLibs
- 使用(参考demo 的使用)
- 通过implementation project 方式引入
- 也可以上传到jcenter 或 maven 私服后 ,直接implementaion
附上个人封装测试好的库:
implementation 'me.leon406:patch:1.0.1'
#若无法使用,请在project repositories闭包中加上
#maven {url "/leon4062/maven"}
项目地址: /Leon406/Patch
参考:
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
Android增量更新(bsdiff使用)