Directory:



Android Incremental Update (1) – Difference Files (Windows-Part 1)

Android Incremental Update (ii) – Differential Files (Windows-Part2) – DLL dynamic libraries and JAR packages

Android Incremental Update (3) – Difference Files (Linux) – Generate JAR and.so libraries

Android Incremental Update (4) – The client merges the subpackage to generate a new APK installation package

The previous implementation in the server side (Windows and LLinux) to generate subcontracting, and generated the corresponding JAR package and dynamic library, easy to use directly. Now that the incremental update is about halfway done, we still need to merge the subsets on the client side to generate a new APK installation package.

Merge subcontracting is mainly used: bspatch.c(Linux) and bzip2 source. So overall it’s not that hard.



Create Android Project (BsPatchYwl5320)

1.1. Create a C++ Android project and click next until finished.





1.2. Add NDK paths





1.3. Compile and run successfully means that the C++ Android project has been built successfully





Configure bspatch and bzip2 source code and compile

2.1. Delete system-generated native methods and C ++ files, and add bspatch.c and bzip2 source code





2.2. Modify the cmakelists. TXT configuration to compile c code and set the name of the.so library (BsPatchYwl5320).

2.2.1 Add bspatch.c and bzip2. C path has 2 methods.

The first is to add all.c paths to add_library, such as:

[plain]
view plain
copy
print
?

  1. add_library( # Sets the name of the library.  
  2.              BsPatchYwl5320  
  3.   
  4.              # Sets the library as a shared library.  
  5.              SHARED  
  6.   
  7.              # Provides a relative path to your source file(s).  
  8.              src/main/cpp/bspatch.c  
  9.              src/main/cpp/bzip2/blocksort.c  
  10.              src/main/cpp/bzip2/bzip2.c  
  11. . # add all.c files
  12.              )  

add_library( # Sets the name of the library. BsPatchYwl5320 # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/bspatch.c src/main/cpp/bzip2/blocksort.c src/main/cpp/bzip2/bzip2.c . # add all.c files)Copy the code

This method is suitable for a small number of source files, when the number is large, it is difficult to write and error prone.



The second method is simple, set the directory containing the source file to a global variable, and specify that the.c inside is read, as in:

[plain]
view plain
copy
print
?

  1. file(GLOB bzip_c src/main/cpp/bzip2/*.c)  
  2.   
  3. add_library( # Sets the name of the library.  
  4.              BsPatchYwl5320  
  5.   
  6.              # Sets the library as a shared library.  
  7.              SHARED  
  8.   
  9.              # Provides a relative path to your source file(s).  
  10.              ${bzip_c}  
  11.              src/main/cpp/bspatch.c  
  12.              )  

file(GLOB bzip_c src/main/cpp/bzip2/*.c)

add_library( # Sets the name of the library.
             BsPatchYwl5320

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             ${bzip_c}
             src/main/cpp/bspatch.c
             )Copy the code





2.2.2 Introduce dynamic library BsPatchYwl5320

[plain]
view plain
copy
print
?

  1. target_link_libraries( # Specifies the target library.  
  2.                        BsPatchYwl5320  
  3.   
  4.                        # Links the target library to the log library  
  5.                        # included in the NDK.  
  6.                        ${log-lib} )  

target_link_libraries( # Specifies the target library.
                       BsPatchYwl5320

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )Copy the code



#include

in bspatch.c to #include “bzip2/bzlib.h”

2.2.4 Since there can only be one main method in.c and there is already a main method in bspatch.c, we need to find if there is a main method in all files in bzip2. If there is a main method, we need to change the main method to something else, in this case “filename _main”.

2.2.5. Compile it after modification. If you can compile it successfully, the source code has been added and configured, for example:





Add native methods

3.1. Write the bspathyWL5320Util. Java class

[java]
view plain
copy
print
?

  1. package com.ywl5320.bspatchywl5320;  
  2.   
  3. / * * 
  4.  * Created by ywl5320 on 2017/10/25. 
  5. * /  
  6.   
  7. public class BsPatchYwl5320Util {  
  8.   
  9.     private static BsPatchYwl5320Util instance = new BsPatchYwl5320Util();  
  10.   
  11.     private BsPatchYwl5320Util(){}  
  12.   
  13.     public static BsPatchYwl5320Util getInstance()  
  14.     {  
  15.         return instance;  
  16.     }  
  17.   
  18.     static  
  19.     {  
  20.         System.loadLibrary(“BsPatchYwl5320”);  
  21.     }  
  22.   
  23.     public native int bsPatch(String oldfile, String newfile, String patchfile);  
  24.   
  25. }  

package com.ywl5320.bspatchywl5320;

/**
 * Created by ywl5320 on 2017/10/25.
 */

public class BsPatchYwl5320Util {

    private static BsPatchYwl5320Util instance = new BsPatchYwl5320Util();

    private BsPatchYwl5320Util(){}

    public static BsPatchYwl5320Util getInstance()
    {
        return instance;
    }

    static
    {
        System.loadLibrary("BsPatchYwl5320");
    }

    public native int bsPatch(String oldfile, String newfile, String patchfile);

}
Copy the code

3.2 compile the project to generate a. Class file, and then use the javah command to generate a. H file

[plain]
view plain
copy
print
?

  1. javah com.ywl5320.bspatchywl5320.BsPatchYwl5320Util  

javah com.ywl5320.bspatchywl5320.BsPatchYwl5320UtilCopy the code





3.3. Move com_ywl5320_bspatchywl5320_BsPatchYwl5320Util. H to CPP file and implement native method in bspatch.c, then add Android log printing function and modify the original Err method. The final bspatch.c code is as follows:

[cpp]
view plain
copy
print
?

  1. / * – 
  2.  * Copyright 2003-2005 Colin Percival 
  3.  * All rights reserved 
  4.  * 
  5.  * Redistribution and use in source and binary forms, with or without 
  6.  * modification, are permitted providing that the following conditions  
  7.  * are met: 
  8.  * 1. Redistributions of source code must retain the above copyright 
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  * 2. Redistributions in binary form must reproduce the above copyright 
  11.  *    notice, this list of conditions and the following disclaimer in the 
  12.  *    documentation and/or other materials provided with the distribution. 
  13.  * 
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR “AS IS” AND ANY EXPRESS OR 
  15.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  16.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  17.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 
  18.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  19.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  20.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  21.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
  22.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
  23.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  24.  * POSSIBILITY OF SUCH DAMAGE. 
  25. * /  
  26.   
  27. #if 0  
  28. __FBSDID(“$FreeBSD: SRC/usr. Bin/bsdiff bspatch/bspatch. C, v 1.1 2005/08/06 01:59:06 cperciva Exp $”);  
  29. #endif  
  30.   
  31. #include “com_ywl5320_bspatchywl5320_BsPatchYwl5320Util.h”  
  32. #include “bzip2/bzlib.h”  
  33. #include <stdlib.h>  
  34. #include <stdio.h>  
  35. #include <string.h>  
  36. //#include <err.h>  
  37. #include <unistd.h>  
  38. #include <fcntl.h>  
  39.   
  40. // Prints logs  
  41. #include <android/log.h>  
  42. #define LOGI(FORMAT,…) __android_log_print(ANDROID_LOG_INFO,”ywl5320″,FORMAT,##__VA_ARGS__);  
  43.   
  44. static off_t offtin(u_char *buf)  
  45. {  
  46.     off_t y;  
  47.   
  48.     y=buf[7]&0x7F;  
  49. y=y*256; y+=buf[6];
  50. y=y*256; y+=buf[5];
  51. y=y*256; y+=buf[4];
  52. y=y*256; y+=buf[3];
  53. y=y*256; y+=buf[2];
  54. y=y*256; y+=buf[1];
  55. y=y*256; y+=buf[0];
  56.   
  57.     if(buf[7]&0x80) y=-y;  
  58.   
  59.     return y;  
  60. }  
  61.   
  62. int patch_main(int argc,char * argv[])  
  63. {  
  64.     FILE * f, * cpf, * dpf, * epf;  
  65.     BZFILE * cpfbz2, * dpfbz2, * epfbz2;  
  66.     int cbz2err, dbz2err, ebz2err;  
  67.     int fd;  
  68.     ssize_t oldsize,newsize;  
  69.     ssize_t bzctrllen,bzdatalen;  
  70.     u_char header[32],buf[8];  
  71.     u_char *old, *new;  
  72.     off_t oldpos,newpos;  
  73.     off_t ctrl[3];  
  74.     off_t lenread;  
  75.     off_t i;  
  76.   
  77.     if(argc! = 4)
  78.     {  
  79.         LOGI(“usage: %s oldfile newfile patchfile\n”,argv[0])  
  80.         return 1;  
  81.     }  
  82. //        errx(1,);  
  83.   
  84.     /* Open patch file */  
  85.     if ((f = fopen(argv[3], “r”)) == NULL)  
  86.     {  
  87.         LOGI(“can’t find patch file: %s”, argv[3]);  
  88.         return 1;  
  89.     }  
  90.   
  91.   
  92.     / * 
  93.     File format: 
  94.         0   8   “BSDIFF40” 
  95.         8   8   X 
  96.         16  8   Y 
  97.         24  8   sizeof(newfile) 
  98.         32  X   bzip2(control block) 
  99.         32+X    Y   bzip2(diff block) 
  100.         32+X+Y  ??? bzip2(extra block) 
  101.     with control block a set of triples (x,y,z) meaning “add x bytes 
  102.     from oldfile to x bytes from the diff block; copy y bytes from the 
  103.     extra block; seek forwards in oldfile by z bytes”. 
  104. * /  
  105.   
  106.     /* Read header */  
  107.     if (fread(header, 1, 32, f) < 32) {  
  108.         if (feof(f))  
  109.         {  
  110.             LOGI(“Corrupt patch”);  
  111.             return 1;  
  112.         }  
  113.         LOGI(“can’t read patchfile header: %s”, argv[3]);  
  114.         return 1;  
  115.     }  
  116.   
  117.     /* Check for appropriate magic */  
  118.     if (memcmp(header, “BSDIFF40”, 8) != 0) {  
  119.         LOGI(“Corrupt patch\n”);  
  120.         return 1;  
  121.     }  
  122.   
  123.     /* Read lengths from header */  
  124.     bzctrllen=offtin(header+8);  
  125.     bzdatalen=offtin(header+16);  
  126.     newsize=offtin(header+24);  
  127.     if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) {  
  128.         LOGI(“Corrupt patch\n”);  
  129.         return 1;  
  130.     }  
  131.   
  132.     /* Close patch file and re-open it via libbzip2 at the right places */  
  133.     if (fclose(f)) {  
  134.         LOGI(“%s”, argv[3]);  
  135.         return 1;  
  136.     }  
  137.     if ((cpf = fopen(argv[3], “r”)) == NULL) {  
  138.         LOGI(“%s”, argv[3]);  
  139.         return 1;  
  140.     }  
  141.     if (fseeko(cpf, 32, SEEK_SET)) {  
  142.         LOGI(“%s”, argv[3]);  
  143.         return 1;  
  144.     }  
  145.     if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) {  
  146.        LOGI(“BZ2_bzReadOpen, bz2err = %d”, cbz2err);  
  147.         return 1;  
  148.     }  
  149.     if ((dpf = fopen(argv[3], “r”)) == NULL) {  
  150.         LOGI(“%s”, argv[3]);  
  151.         return 1;  
  152.     }  
  153.     if (fseeko(dpf, 32 + bzctrllen, SEEK_SET)) {  
  154.         LOGI(“%s”, argv[3]);  
  155.         return 1;  
  156.     }  
  157.     if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) {  
  158.         LOGI(“BZ2_bzReadOpen dbz2err = %d”, dbz2err);  
  159.         return 1;  
  160.     }  
  161.     if ((epf = fopen(argv[3], “r”)) == NULL) {  
  162.         LOGI(“%s”, argv[3]);  
  163.         return 1;  
  164.     }  
  165.     if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) {  
  166.         LOGI(“%s”, argv[3]);  
  167.         return 1;  
  168.     }  
  169.     if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) {  
  170.         LOGI(“BZ2_bzReadOpen, bz2err = %d”, ebz2err);  
  171.         return 1;  
  172.     }  
  173.   
  174.     if(((fd=open(argv[1],O_RDONLY,0))<0) ||  
  175.         ((oldsize=lseek(fd,0,SEEK_END))==-1) ||  
  176.         ((old=malloc(oldsize+1))==NULL) ||  
  177. (lseek(fd,0,SEEK_SET)! = 0) | |
  178. (read(fd,old,oldsize)! =oldsize) ||
  179.         (close(fd)==-1))  
  180.     {  
  181.         LOGI(“can’t find oldfile: %s”, argv[1]);  
  182.         return 1;  
  183.     }  
  184.     if((new=malloc(newsize+1))==NULL) {  
  185.         LOGI(“newsize is NULL”);  
  186.         return 1;  
  187.     }  
  188.   
  189. oldpos=0; newpos=0;
  190.     while(newpos<newsize) {  
  191.         /* Read control data */  
  192.         for(i=0; i<=2; i++) {
  193.             lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);  
  194.             if((lenread < 8) || ((cbz2err ! = BZ_OK) &&
  195. (cbz2err ! = BZ_STREAM_END))) {
  196.                 LOGI(“Corrupt patch\n”);  
  197.                 return 1;  
  198.             }  
  199.             ctrl[i]=offtin(buf);  
  200.         };  
  201.   
  202.         /* Sanity-check */  
  203.         if(newpos+ctrl[0]>newsize) {  
  204.             LOGI(“Corrupt patch\n”);  
  205.             return 1;  
  206.         }  
  207.   
  208.         /* Read diff string */  
  209.         lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);  
  210.         if ((lenread < ctrl[0]) ||  
  211. ((dbz2err ! = BZ_OK) && (dbz2err ! = BZ_STREAM_END))) {
  212.             LOGI(“Corrupt patch\n”);  
  213.             return 1;  
  214.         }  
  215.   
  216.         /* Add old data to diff string */  
  217.         for(i=0; i
  218.             if((oldpos+i>=0) && (oldpos+i<oldsize))  
  219.                 new[newpos+i]+=old[oldpos+i];  
  220.   
  221.         /* Adjust pointers */  
  222.         newpos+=ctrl[0];  
  223.         oldpos+=ctrl[0];  
  224.   
  225.         /* Sanity-check */  
  226.         if(newpos+ctrl[1]>newsize) {  
  227.             LOGI(“Corrupt patch\n”);  
  228.             return 1;  
  229.         }  
  230.   
  231.         /* Read extra string */  
  232.         lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);  
  233.         if ((lenread < ctrl[1]) ||  
  234. ((ebz2err ! = BZ_OK) && (ebz2err ! = BZ_STREAM_END))) {
  235.             LOGI(“Corrupt patch\n”);  
  236.             return 1;  
  237.         }  
  238.   
  239.         /* Adjust pointers */  
  240.         newpos+=ctrl[1];  
  241.         oldpos+=ctrl[2];  
  242.     };  
  243.   
  244.     /* Clean up the bzip2 reads */  
  245.     BZ2_bzReadClose(&cbz2err, cpfbz2);  
  246.     BZ2_bzReadClose(&dbz2err, dpfbz2);  
  247.     BZ2_bzReadClose(&ebz2err, epfbz2);  
  248.     if (fclose(cpf) || fclose(dpf) || fclose(epf)) {  
  249.         LOGI(“%s”, argv[3]);  
  250.         return 1;  
  251.     }  
  252.   
  253.     /* Write the new file */  
  254.     if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||  
  255.         (write(fd,new,newsize)! =newsize) || (close(fd)==-1)) {
  256.         LOGI(“can’t open newfile: %s”, argv[2]);  
  257.         return 1;  
  258.     }  
  259.   
  260.     free(new);  
  261.     free(old);  
  262.   
  263.     return 0;  
  264. }  
  265.   
  266. JNIEXPORT jint JNICALL Java_com_ywl5320_bspatchywl5320_BsPatchYwl5320Util_bsPatch(JNIEnv *env, jobject instance, jstring oldfile_,  
  267.                                                    jstring newfile_, jstring patchfile_) {  
  268.   
  269.     int restlt = -1;  
  270.     int argc = 4;  
  271.     char *argv[4];  
  272.   
  273.     const char *oldfile = (*env)->GetStringUTFChars(env, oldfile_, 0);  
  274.     const char *newfile = (*env)->GetStringUTFChars(env, newfile_, 0);  
  275.     const char *patchfile = (*env)->GetStringUTFChars(env, patchfile_, 0);  
  276.   
  277.     argv[0] = “bspatch_ywl5320”;  
  278.     argv[1] = oldfile;  
  279.     argv[2] = newfile;  
  280.     argv[3] = patchfile;  
  281.     // TODO  
  282.     restlt = patch_main(argc, argv);  
  283.   
  284.     (*env)->ReleaseStringUTFChars(env, oldfile_, oldfile);  
  285.     (*env)->ReleaseStringUTFChars(env, newfile_, newfile);  
  286.     (*env)->ReleaseStringUTFChars(env, patchfile_, patchfile);  
  287.   
  288.     return restlt;  
  289. }  

/*-
 * Copyright 2003-2005 Colin Percival
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing that the following conditions 
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#if 0
__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");
#endif

#include "com_ywl5320_bspatchywl5320_BsPatchYwl5320Util.h"
#include "bzip2/bzlib.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include <err.h>
#include <unistd.h>
#include <fcntl.h>

//打印日志
#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"ywl5320",FORMAT,##__VA_ARGS__);

static off_t offtin(u_char *buf)
{
	off_t y;

	y=buf[7]&0x7F;
	y=y*256;y+=buf[6];
	y=y*256;y+=buf[5];
	y=y*256;y+=buf[4];
	y=y*256;y+=buf[3];
	y=y*256;y+=buf[2];
	y=y*256;y+=buf[1];
	y=y*256;y+=buf[0];

	if(buf[7]&0x80) y=-y;

	return y;
}

int patch_main(int argc,char * argv[])
{
	FILE * f, * cpf, * dpf, * epf;
	BZFILE * cpfbz2, * dpfbz2, * epfbz2;
	int cbz2err, dbz2err, ebz2err;
	int fd;
	ssize_t oldsize,newsize;
	ssize_t bzctrllen,bzdatalen;
	u_char header[32],buf[8];
	u_char *old, *new;
	off_t oldpos,newpos;
	off_t ctrl[3];
	off_t lenread;
	off_t i;

	if(argc!=4)
    {
        LOGI("usage: %s oldfile newfile patchfile\n",argv[0])
        return 1;
    }
//        errx(1,);

	/* Open patch file */
	if ((f = fopen(argv[3], "r")) == NULL)
    {
        LOGI("can't find patch file: %s", argv[3]);
        return 1;
    }


	/*
	File format:
		0	8	"BSDIFF40"
		8	8	X
		16	8	Y
		24	8	sizeof(newfile)
		32	X	bzip2(control block)
		32+X	Y	bzip2(diff block)
		32+X+Y	???	bzip2(extra block)
	with control block a set of triples (x,y,z) meaning "add x bytes
	from oldfile to x bytes from the diff block; copy y bytes from the
	extra block; seek forwards in oldfile by z bytes".
	*/

	/* Read header */
	if (fread(header, 1, 32, f) < 32) {
		if (feof(f))
        {
            LOGI("Corrupt patch");
            return 1;
        }
        LOGI("can't read patchfile header: %s", argv[3]);
        return 1;
	}

	/* Check for appropriate magic */
	if (memcmp(header, "BSDIFF40", 8) != 0) {
        LOGI("Corrupt patch\n");
        return 1;
    }

	/* Read lengths from header */
	bzctrllen=offtin(header+8);
	bzdatalen=offtin(header+16);
	newsize=offtin(header+24);
	if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) {
        LOGI("Corrupt patch\n");
        return 1;
    }

	/* Close patch file and re-open it via libbzip2 at the right places */
	if (fclose(f)) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if ((cpf = fopen(argv[3], "r")) == NULL) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if (fseeko(cpf, 32, SEEK_SET)) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) {
       LOGI("BZ2_bzReadOpen, bz2err = %d", cbz2err);
        return 1;
    }
	if ((dpf = fopen(argv[3], "r")) == NULL) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if (fseeko(dpf, 32 + bzctrllen, SEEK_SET)) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) {
        LOGI("BZ2_bzReadOpen dbz2err = %d", dbz2err);
        return 1;
    }
	if ((epf = fopen(argv[3], "r")) == NULL) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) {
        LOGI("%s", argv[3]);
        return 1;
    }
	if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) {
        LOGI("BZ2_bzReadOpen, bz2err = %d", ebz2err);
        return 1;
    }

	if(((fd=open(argv[1],O_RDONLY,0))<0) ||
		((oldsize=lseek(fd,0,SEEK_END))==-1) ||
		((old=malloc(oldsize+1))==NULL) ||
		(lseek(fd,0,SEEK_SET)!=0) ||
		(read(fd,old,oldsize)!=oldsize) ||
		(close(fd)==-1))
    {
        LOGI("can't find oldfile: %s", argv[1]);
        return 1;
    }
	if((new=malloc(newsize+1))==NULL) {
        LOGI("newsize is NULL");
        return 1;
    }

	oldpos=0;newpos=0;
	while(newpos<newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
			    (cbz2err != BZ_STREAM_END))) {
                LOGI("Corrupt patch\n");
                return 1;
            }
			ctrl[i]=offtin(buf);
		};

		/* Sanity-check */
		if(newpos+ctrl[0]>newsize) {
            LOGI("Corrupt patch\n");
            return 1;
        }

		/* Read diff string */
		lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
		if ((lenread < ctrl[0]) ||
		    ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) {
            LOGI("Corrupt patch\n");
            return 1;
        }

		/* Add old data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<oldsize))
				new[newpos+i]+=old[oldpos+i];

		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];

		/* Sanity-check */
		if(newpos+ctrl[1]>newsize) {
            LOGI("Corrupt patch\n");
            return 1;
        }

		/* Read extra string */
		lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]);
		if ((lenread < ctrl[1]) ||
		    ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) {
            LOGI("Corrupt patch\n");
            return 1;
        }

		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};

	/* Clean up the bzip2 reads */
	BZ2_bzReadClose(&cbz2err, cpfbz2);
	BZ2_bzReadClose(&dbz2err, dpfbz2);
	BZ2_bzReadClose(&ebz2err, epfbz2);
	if (fclose(cpf) || fclose(dpf) || fclose(epf)) {
        LOGI("%s", argv[3]);
        return 1;
    }

	/* Write the new file */
	if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
		(write(fd,new,newsize)!=newsize) || (close(fd)==-1)) {
        LOGI("can't open newfile: %s", argv[2]);
        return 1;
    }

	free(new);
	free(old);

	return 0;
}

JNIEXPORT jint JNICALL Java_com_ywl5320_bspatchywl5320_BsPatchYwl5320Util_bsPatch(JNIEnv *env, jobject instance, jstring oldfile_,
                                                   jstring newfile_, jstring patchfile_) {

    int restlt = -1;
    int argc = 4;
    char *argv[4];

    const char *oldfile = (*env)->GetStringUTFChars(env, oldfile_, 0);
    const char *newfile = (*env)->GetStringUTFChars(env, newfile_, 0);
    const char *patchfile = (*env)->GetStringUTFChars(env, patchfile_, 0);

    argv[0] = "bspatch_ywl5320";
    argv[1] = oldfile;
    argv[2] = newfile;
    argv[3] = patchfile;
    // TODO
    restlt = patch_main(argc, argv);

    (*env)->ReleaseStringUTFChars(env, oldfile_, oldfile);
    (*env)->ReleaseStringUTFChars(env, newfile_, newfile);
    (*env)->ReleaseStringUTFChars(env, patchfile_, patchfile);

    return restlt;
}
Copy the code

4. Test the combination function of subcontracting

4.1. Prepare the app_patch1.patch package and the app_OLd1. Apk file generated by the subpackage, create the BSPatch folder in the root directory of the phone, and add the old files and the subpackage to bSPatch:



4.2. Add merge code to Mainactivity

[java]
view plain
copy
print
?

  1. package com.ywl5320.bspatchywl5320;  
  2.   
  3. import android.os.Environment;  
  4. import android.support.v7.app.AppCompatActivity;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.widget.Toast;  
  9.   
  10.   
  11. public class MainActivity extends AppCompatActivity {  
  12.   
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.activity_main);  
  17.     }  
  18.   
  19.   
  20.     public void onPatch(View view) {  
  21.   
  22.         String oldfile = Environment.getExternalStorageDirectory().getAbsolutePath() + “/bspatch/app_old1.apk”;  
  23.         String newfile = Environment.getExternalStorageDirectory().getAbsolutePath() + “/bspatch/app_new1.apk”;  
  24.         String patchfile = Environment.getExternalStorageDirectory().getAbsolutePath() + “/bspatch/app_patch1.patch”;  
  25.   
  26.         int restlt = BsPatchYwl5320Util.getInstance().bsPatch(oldfile, newfile, patchfile);  
  27.         if(restlt == 0)  
  28.         {  
  29.             Log.d(“ywl5320”.“Merger successful”);  
  30.             Toast.makeText(this.“Merger successful”, Toast.LENGTH_LONG).show();  
  31.         }  
  32.         else  
  33.         {  
  34.             Log.d(“ywl5320”.“Merge failed”);  
  35.             Toast.makeText(this.“Merge failed”, Toast.LENGTH_LONG).show();  
  36.         }  
  37.     }  
  38. }  

package com.ywl5320.bspatchywl5320; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onPatch(View view) { String oldfile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bspatch/app_old1.apk"; String newfile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bspatch/app_new1.apk"; String patchfile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bspatch/app_patch1.patch"; int restlt = BsPatchYwl5320Util.getInstance().bsPatch(oldfile, newfile, patchfile); If (restlt == 0) {log. d("ywl5320", "merge successful "); Toast.maketext (this, "merge succeeded ", toast.length_long).show(); } else {log.d ("ywl5320", "merge failed "); Toast.maketext (this, "merge failed ", toast.length_long).show(); }}}Copy the code

4.3 test merge

The merge succeeds, and the installation can be successful.



Five, package. Jar files and extract. So library, easy to use

5.1. Package JAR packages

[plain]
view plain
copy
print
?

  1. jar cvf BsPatchYwl5320Util.jar com\ywl5320\bspatchywl5320\BsPatchYwl5320Util.class  

jar cvf BsPatchYwl5320Util.jar com\ywl5320\bspatchywl5320\BsPatchYwl5320Util.classCopy the code







5.2. Extract the Android platform. So library



Six, summarized

At this point, incremental update server generation of subcontracting and client consolidation of subcontracting are complete. In actual development, jar files and dynamic libraries (DLL, SO) generated in difference and merge can be directly used. It is better to verify whether the MD5 of the old APK is consistent when the client requests the server to obtain the subcontract, because Android applications are generally multi-channel, or they are prone to error. Besides, the merge here is only a function test. In the specific project, it is to obtain the old APK file in the system directory data of this APK, and then merge it with the patch file downloaded from the server and reinstall it.

A concrete implementation example, I will implement in my other open source project AppServiceRestFul.



GitHub BsDiffYwl5320