关闭

[置顶] 最全的增量更新入门 包含linux端和Android

2459人阅读 评论(2) 收藏 举报
分类:

简介

增量更新大量用于 Android各大应用市场.本文想做网络上从服务器到app客户端完整讲解.app用eclipse和android studio 最新版cmark开发ndk
如下图:
这里写图片描述

以前一直好奇怎么做的直到知道了bsdiff库.
地址附上:
bsdiff源码地址和简介

  • 大家可以从简介看到bsdiff是基于bzip2源码(bsdiff和bspatch一个用于生成差异文件补丁,另一个用于差异文件和旧文件合成新文件)
    这里写图片描述
  • 下载地址说明
    这里写图片描述

应用市场原理说明

假设你用的是”XXX市场”点击更新的时候,把当前版本号和服务器最新版app版本号对比用bsdiff生成差异包,然后将差异包返回下载,下载后将本地应用app的apk文件和差异包用bspatch合成新的apk在安装.

这里写图片描述

在服务器上用java后台生成差异文件

  • 操作系统:ubuntu
  • 集成开发环境(ide):eclipse
  • 源码:bzip2 ,bsdiff

bsdiff源码点击官网中”here”下载 :
懒人链接
bzip2源码下载:
bzip2官网链接
bzip2下载链接

下载后bsdiff源码文件如下:
这里写图片描述

  • 我们看到有两个 文件一个bsdiff.c 和bspatch.c 其他文件,大家先无视(makefie可以简单理解文件工程管理的,这里可用可不用).
  • 我们服务器要生成差异文件,那么只需要bsdiff.c 即可.

  • 我们先简单阅读下bsdiff源码(我们直接看启动方法main):
    这里写图片描述
    从上图可知 传入的参数args需要等于4 不然报错.各个参数已经在上图解释

  • 由于main方法很特殊(启动方法,和java的main意义一样所以我们改一个方法名) 所以在这里我们改一个名字为 bsdiff_main
    这里写图片描述

  • 编写对应java的jni方法并生成头文件.(如果大家对jni不熟悉的,就按照本博客操作即可,尽量做到让大家都明白)

1 创建普通的java工程(当然这里不创建web工程,大家到时候自己移植到你的serverlet即可)

这里写图片描述

2 编写jni方法

package com.fmy;

public class JAVABsdiff {


    public static void main(String[] args) {



    }
    //jni方法 用于调用bsdiff
    public static native void myBsdiff(String []args);
}

3 生成对应”xxx.h”文件

1. 打开命令窗口 
2. 打开目录到java工程目录到src下
3. 输入javah 包名.类名 生成对应 "xxx.h"头文件

这里写图片描述
此时会在你java到src目录生成xx.h文件(请按F5刷新)
这里写图片描述
我们顺便打开这个文件看看
这里写图片描述
可以看到里面有一个c语言方法

        JNIEXPORT void JNICALL Java_com_fmy_JAVABsdiff_myBsdiff
          (JNIEnv *, jclass, jobjectArray);
        我们待会创建一个c文件实现它并将它与bsdiff_main方法关联

4 创建bsdiff.h。创建一个test.c文件 导入bsdiff.h和xxx.h 并实现

  • 导入bsdiff.h并声明bsdiff_main()方法作用是用于告诉 test.c有这个方式到实现 并且可以调用
  • xxx.h是我们前面调用javah 生成到头文件
#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);
}

5 编译生成方式1 gcc命令

  • 把上面所有到文件放入到一个文件中
    1. bsdiff.h
    2. bsdiff.c
    3. test.c
    4. xxx.h
    5. bzip2文件下所有源码

这里写图片描述

打开命令窗口 打开此目录输入

$ gcc *.c -fPIC -shared -o libtest.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);
}

5 编译生成方式2 eclipse

elipse 需要安装cdt插件

  1. 新建C project。

    1. 选择project type —>>Shared Libary
    2. toocahins 选择Linux GCC
    3. finish
      这里写图片描述
  2. 导入第一中编译方式 最后一步的所有文件到工程中
    这里写图片描述

  3. 修改编译参数
    1. 右键项目 在弹出到菜单栏中选择Propertice
    2. c/c++ Build –>>Setings 在右侧窗的command输入gcc -fPIC
      这里写图片描述
    3. build一下在debug下就可以看到对应的so类库

eclipse cdt编译参考文献1
eclipse cdt编译参考文献2

Android eclipse实现patch

  1. eclipse 新建一个Android 工程
  2. 右键选择Android Tools—>>Add Native Support 点击确定
    这里写图片描述

  3. 此时会在目录生成 生成一个lib目录 并且自动生成一个.cpp和Android.mk文件

  4. 创建jni方法

    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);
    
    }
    
  5. 生jni方法头文件放入jni中

    这里写图片描述

  6. 把去掉bzip2源码中所有的main方法的文件拷贝到jni目录下,

  7. 创建一个test.c文件放入jni目录

  8. 把 bspatch.c放入jni目录.并修改对应的main
    这里写图片描述

    这里写图片描述

    修改bspatch.c导入的bzip.h路径
    这里写图片描述

    我们顺带看jni 目录
    这里写图片描述

  9. 编写test.c实现

    
    #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);
    }
    
  10. 修改Android.mk文件如下

    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    := bspatch
    LOCAL_SRC_FILES := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%)
    
    #导入Android 日志 库可以在jni中使用Log.e方法等
    
    LOCAL_LDLIBS:= -llog
    
    include $(BUILD_SHARED_LIBRARY)
    
  11. 获取本地apk文件路径和服务器下载好的patch(差异文件)合成
    (这里偷懒模拟下就下)
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);
}

Android studio2.2实现patch

用CMake 构建ndk开发,这里不详细说了
CMake教程

用as创建一个工程的时候勾选 ‘include c++ support’
这里写图片描述

此时 工程目录下有个main/cpp文件夹
项目工程下会有个CMakeList.txt文件

  1. 导入bzip2(去掉文件中带有main方法的文件代码) 放入cpp文件夹中
  2. 创建一个jni方法

    
    
    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);
    
    }
    

    tip:在新版的studio直接鼠标方法jni方法上直接按下Alt+回车键直接生产对应实现方法哦.

    这里我们在cpp/native-lib.c实现

    
    #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"
    
    
    
    JNIEXPORT void JNICALL
    Java_com_myself_weather_testjni2_MainActivity_path(JNIEnv *env, jclass tjype, jobjectArray arrays) {
    
        jstring a0 = (*env)->GetObjectArrayElement(env,arrays,0);
        char *j=(*env)->GetStringUTFChars(env,a0,NULL);
        jstring a1 = (*env)->GetObjectArrayElement(env,arrays,1);
        char *j1=(*env)->GetStringUTFChars(env,a1,NULL);
        jstring a2 = (*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);
    
    }
  3. 导入bspatch.c导入cpp目录下(记得修改main方法名字和eclipse一样)

    • 此时cpp目录
      这里写图片描述
  4. 修改CmarkList.txt文件
    这里写图片描述

  5. 最后合成

package com.myself.weather.testjni2;

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import java.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 method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                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()});
            }
        });
    }

    /**
     * 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);

}
0
0
查看评论

Linux rsync增量同步方法

linux rsync增量同步方法 可以先使用 rpm -qa |grep rsync 查看rsync是否已经安装 下面说说rsyns的配置过程 一. 配置服务器端 首先编辑 /etc/rsyncd.conf 内容如下: uid = nobody #进行备份的用户 nobod...
  • czgxhf1985
  • czgxhf1985
  • 2012-08-06 17:40
  • 2777

实现应用的增量更新\升级

转载请注明出处:http://blog.csdn.net/yyh352091626/article/details/50579859 增量升级的背景 虽然很多App的版本更新并不频繁,但是一个App基本上也有几兆到几十兆不等,在没有Wifi的条件下,更新App是非常耗流量的。说到这个就必...
  • zb872676223
  • zb872676223
  • 2016-06-28 19:08
  • 1197

java web项目war包自动升级部署方案

前言之前,我们公司部署以及升级都是由运维去管理的,联想到很多开源平台都支持自动升级,索性我也做个自动升级war的功能。 这里没有用docker镜像发包,灰度发包等,只适用于单个tomcat的部署环境,支持docker单个tomcat容器。分析先简单分析下war包自动升级流程: 1. 检查是否需要...
  • qq273681448
  • qq273681448
  • 2017-07-10 17:11
  • 3602

热更新

虽然有插件开发,但热更新少不了。 当我们需要更新插件的时候使用的是插件开发,当我们需要更新宿主程序就需要使用热更新 热更新使用框架bsdiff和bzip2 我们需要在服务端使用新版apk和旧版apk生成差分包,由于服务端在windows下,所以生成动态文件(dll) 通过寻找bsdiff的入口函...
  • m0_37402140
  • m0_37402140
  • 2017-07-25 19:22
  • 847

差分升级的攻克!(主要是so库的生成和使用啦)

差分升级 一 什么是差分升级 二 差分升级相关概念 差分工具 bsdiff 生成补丁 bspatch 合成apk 创建so库 使用so库差分升级一. 什么是差分升级 将已安装的apk和最新的apk进行二进制对比,得到差分包。用户升级的时候只需要下载差分包,在本地使用差分包和已安装的apk合成...
  • SelfLearner
  • SelfLearner
  • 2017-03-30 17:44
  • 345

增量更新

实现思路实现增量更新的步骤: 1. old.apk和new.apk生成差异包patch 2. old.apk和patch合成更新包merge.apk 3. 安装merge.apk生成差异包patch1.进入bsdiff官网,下载bsdiff-4.3.tar.gz 2.解压下载好的bsdiff...
  • likuan0214
  • likuan0214
  • 2017-11-30 18:46
  • 160

Android高级之十三讲-HotFix、热加载和增量更新

Android热加载出现的原因在于:第一5.1出现之前没有好的办法解决App方法数超过65536的问题,第二启动特别慢,因为加载的模块比较多。本质上还是虚拟机支持JIT的加载机制。  AndroidDynamicLoader 是最早分析的动态加载框架,主要使用activity当壳...
  • liuxian13183
  • liuxian13183
  • 2016-12-14 23:25
  • 1928

Android 增量更新完全解析 是增量不是热修复

感悟 今天是我身份证上的25岁生日,所以法律上来说我25岁啦~~ 一直没有写过总结,本来是准备写个总结的,但是列出来几条觉得太装逼,也不是什么干货,所以决定换个角度。 那么就聊聊,目前人生中做的最正确的决定,那就是: 写博客。 很多专业人士觉得写博客很low,更有甚者认为程序员写...
  • lmj623565791
  • lmj623565791
  • 2016-10-11 08:45
  • 46801

Android中的增量更新与热修复

留待后续更新(博客任务)
  • zhouhang421
  • zhouhang421
  • 2016-10-11 09:14
  • 568

Android开发之增量更新

一、使用场景 apk升级,节省服务器和用户的流量 二、原理自从 Android 4.1 开始, Google Play 引入了应用程序的增量更新功能,App使用该升级方式,可节省约2/3的流量。现在国内主流的应用市场也都支持应用的增量更新了,最常见的应用宝省流量更新。增量更新的原理,就是将手机上...
  • qq_33750826
  • qq_33750826
  • 2017-07-20 18:56
  • 880
    个人资料
    • 访问:491589次
    • 积分:6793
    • 等级:
    • 排名:第4126名
    • 原创:274篇
    • 转载:63篇
    • 译文:0篇
    • 评论:51条