增量更新大量用于 Android 各大应用市场. 本文想做网络上从服务器到 app 客户端完整讲解. app 用 eclipse 和 android studio 最新版 cmark 开发 ndk 如下图:
以前一直好奇怎么做的直到知道了 bsdiff 库. 地址附上: bsdiff 源码地址和简介
假设你用的是 "XXX 市场" 点击更新的时候, 把当前版本号和服务器最新版 app 版本号对比用 bsdiff 生成差异包, 然后将差异包返回下载, 下载后将本地应用 app 的 apk 文件和差异包用 bspatch 合成新的 apk 在安装.
bsdiff 源码点击官网中 "here" 下载 : 懒人链接 bzip2 源码下载: bzip2 官网链接 bzip2 下载链接
下载后 bsdiff 源码文件如下:
- packagecom.fmy;public class JAVABsdiff{
- public static void main(String[] args) {
- }//jni方法 用于调用bsdiff
- public static native void myBsdiff(String []args);
- }
- 1. 打开命令窗口
- 2. 打开目录到java工程目录到src下
- 3. 输入javah 包名.类名 生成对应 "xxx.h"头文件
此时会在你 java 到 src 目录生成 xx.h 文件(请按 F5 刷新) 我们顺便打开这个文件看看 可以看到里面有一个 c 语言方法
- JNIEXPORTvoidJNICALL Java_com_fmy_JAVABsdiff_myBsdiff
- (JNIEnv *, jclass, jobjectArray);
- 我们待会创建一个c文件实现它并将它与bsdiff_main方法关联
- #include "com_fmy_JAVABsdiff.h"#include < stdio.h > #include "bsdiff.h"JNIEXPORT void JNICALL Java_com_fmy_JAVABsdiff_myBsdiff(JNIEnv * env, jclass jclas, jobjectArray attas) {
- //GetObjectArrayElement得到到是jstring类型 而我们调用bsdiff_main()传入的
- //是char× 数组 所以需要转化。这里需要jni知识 所以就不太多了,你只需把下面到内容
- //复制到你到项目中即可
- //旧文件地址
- jstring a0 = ( * env) - >GetObjectArrayElement(env, attas, 0);
- //转化为char ×
- char * j = (char * )( * env) - >GetStringUTFChars(env, a0, NULL);
- //
- jstring a1 = ( * env) - >GetObjectArrayElement(env, attas, 1);
- char * j1 = (char * )( * env) - >GetStringUTFChars(env, a1, NULL);
- jstring a2 = ( * env) - >GetObjectArrayElement(env, attas, 2);
- char * j2 = (char * )( * env) - >GetStringUTFChars(env, a2, NULL);
- char * agrs[] = {
- "patch",
- j,
- j1,
- j2
- };
- bsdiff_main(4, agrs);
- }
打开命令窗口 打开此目录输入
- $ gcc*.c-fPIC -shared -olibtest.so
然后报错 为什么报错?因为 前面用 javah 生成头文件中导入了 jni.h 这里大家可以回头看看。第二我们使用 env 这个变量 也是 jni 里面所有我们需要导入。
问题来了 jni.h 在哪? 位于 java 安装目录 include 下
ok 我们把这个文件复制到刚才编译目录下,继续编译
又报错发现缺少 jni_md.h 文件 报错原因: 因为 jni.h 内部引用了 jni_md.h
jni_md.h 在哪? 在 java 安装目录到 include 到 linux 下
我们在最后编译下
发现还是报错 xxx.c 中定义 main 重复定义了 大家这里可以看着报错到文件 去到文件直接把 main 方法删除了或注释 这里我就带大家注释其中到 bzip2recover.c 的 main 删除或则注释上面高亮部分 其他文件大家自己删除把
再次编译一次 快疯了。。。。。 编译通过了!
此时在目录下会生成 test.so
在 java 调用 so
- package com.fmy;
- public class JAVABsdiff {
- static {
- System.load("/media/fmy/新加卷/增量/完整/test.so");
- }
- public static void main(String[] args) {
- String oldfile = "/media/fmy/新加卷/增量/old.tar";
- String newfile = "/media/fmy/新加卷/增量/new.tar";
- String patch = "/media/fmy/新加卷/增量/patch.patch";
- myBsdiff(new String[] {
- oldfile,
- newfile,
- patch
- });
- System.out.println("asd");
- }
- //生成静态到patch文件
- public static native void myBsdiff(String[] args);
- }
elipse 需要安装 cdt 插件
eclipse cdt 编译参考文献 1 eclipse cdt 编译参考文献 2
- public class MainActivity extends Activity{
- @Override
- protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }public static native void path(String []arrays);
- }
- #include "com_fmy_JAVA_bs.h"#include < stdio.h > JNIEXPORT void JNICALL Java_com_fmy_JAVA_1bs_myBsDiff(JNIEnv * env, jclass jclas, jobjectArray attas) {
- jstring a0 = ( * env) - >GetObjectArrayElement(env, attas, 0);
- char * j = ( * env) - >GetStringUTFChars(env, a0, NULL);
- jstring a1 = ( * env) - >GetObjectArrayElement(env, attas, 1);
- char * j1 = ( * env) - >GetStringUTFChars(env, a1, NULL);
- jstring a2 = ( * env) - >GetObjectArrayElement(env, attas, 2);
- char * j2 = ( * env) - >GetStringUTFChars(env, a2, NULL);
- char * agrs[] = {
- "patch",
- j,
- j1,
- j2
- };
- bsdiff_main(4, agrs);
- }
- LOCAL_PATH :=$(call my-dir)#目的便利jni目录下所有的.c文件
- MY_CPP_LIST :=$(wildcard$(LOCAL_PATH)/*.c)#目的便利jni/bzip2目录下所有的.c文件
- MY_CPP_LIST+=$(wildcard$(LOCAL_PATH)/bzip2/*.c)include $(CLEAR_VARS)LOCAL_MODULE := bspatchLOCAL_SRC_FILES :=$(MY_CPP_LIST:$(LOCAL_PATH)/%=%)#导入Android 日志 库可以在jni中使用Log.e方法等
- LOCAL_LDLIBS:= -lloginclude $(BUILD_SHARED_LIBRARY)
- public class MainActivity extends Activity {
- static {
- System.loadLibrary("bspatch");
- }@Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //这里用zip包模拟 增量更新不止用于 apk哦亲
- File oldFile = new File(Environment.getExternalStorageDirectory(), "old.zip");
- File newFile = new File(Environment.getExternalStorageDirectory(), "new.zip");
- File patchFile = new File(Environment.getExternalStorageDirectory(), "path.patch");
- path(new String[] {
- oldFile.getAbsolutePath(),
- newFile.getAbsolutePath(),
- patchFile.getAbsolutePath()
- });
- // path();
- Log.e("test", "asd");
- // Log.e("fmy", "============"+path);
- }
- // public static native void path();
- public static native void path(String[] arrays);
- }
用 CMake 构建 ndk 开发, 这里不详细说了 CMake 教程
用 as 创建一个工程的时候勾选'include c++ support'
此时 工程目录下有个 main/cpp 文件夹 项目工程下会有个 CMakeList.txt 文件
tip: 在新版的 studio 直接鼠标方法 jni 方法上直接按下 Alt + 回车键直接生产对应实现方法哦. 这里我们在 cpp/native-lib.c 实现
- public class MainActivity extends AppCompatActivity{
- // Used to load the 'native-lib' library on application startup.
- static{
- System.loadLibrary("native-lib");
- }@Override
- protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }/**
- * A native method that is implemented by the 'native-lib' native library,
- * which is packaged with this application.
- */
- public static native void path(String []arrays);
- }
- #include <jni.h>
- #include "stdio.h"
- #include "android/log.h"
- #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,__VA_ARGS__)
- #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,__VA_ARGS__)
- #include "bzip2-1.0.6/bspatch.h"JNIEXPORTvoidJNICALL
- Java_com_myself_weather_testjni2_MainActivity_path(JNIEnv *env, jclass tjype, jobjectArray arrays) {
- jstringa0=(*env)->GetObjectArrayElement(env,arrays,0);
- char *j=(*env)->GetStringUTFChars(env,a0,NULL);
- jstringa1=(*env)->GetObjectArrayElement(env,arrays,1);
- char *j1=(*env)->GetStringUTFChars(env,a1,NULL);
- jstringa2=(*env)->GetObjectArrayElement(env,arrays,2);
- char *j2=(*env)->GetStringUTFChars(env,a2,NULL);
- char * agrs[] = {"patch",j,j1,j2};
- mybspatch_main(4,agrs);
- LOGE("FMY%s",j);
- LOGE("FMY%s",j1);
- LOGE("FMY%s",j2);
- }
- packagecom.myself.weather.testjni2;importandroid.os.Bundle;importandroid.os.Environment;importandroid.support.v7.app.AppCompatActivity;importandroid.view.View;importandroid.widget.TextView;importjava.io.File;public class MainActivity extends AppCompatActivity{
- // Used to load the 'native-lib' library on application startup.
- static{
- System.loadLibrary("native-lib");
- }@Override
- protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);// Example of a call to a native methodTextView tv = (TextView) findViewById(R.id.sample_text);
- tv.setOnClickListener(newView.OnClickListener() {@Override
- public void onClick(View v) {
- File oldFile =newFile(Environment.getExternalStorageDirectory(),"old.zip");
- File newFile =newFile(Environment.getExternalStorageDirectory(),"new.zip");
- File patchFile =newFile(Environment.getExternalStorageDirectory(),"path.patch");
- path(newString [] {oldFile.getAbsolutePath(),newFile.getAbsolutePath(),patchFile.getAbsolutePath()});
- }
- });
- }/**
- * A native method that is implemented by the 'native-lib' native library,
- * which is packaged with this application.
- */
- public static native void path(String []arrays);
- }
来源: http://blog.csdn.net/qfanmingyiq/article/details/70215295