iOS客户端React-Native增量更新实践

市场上现存方案:微软的 CodePush 以及React-Native中文网的Pushy,大家可根据公司实际情况酌情选择。
处于安全性的考虑,公司禁止向第三方平台上传源码相关文件,所以要自己动手实现。

增量更新主要实现流程
1.使用react-native bundle 命令打包,压缩打包文件
2.使用bsdiff生成新旧RN版本压缩文件的差异化文件patchFile
3.客户端旧RN版本压缩文件合并下载的patchFile文件,校验文件MD5值,解压合并后的文件,重新加载jsbundle,完成更新
4.增加版本控制,脚本化1、2过程

常见问题:
一、bsdiff的使用
下载地址:http://www.daemonology.net/bsdiff/
1.解压下载文件

$ cd bsdiff-4.3

2.修改makefile文件格式如下,原文件后三行缩进格式不对:

CFLAGS        +=    -O3 -lbz2

PREFIX        ?=    /usr/local
INSTALL_PROGRAM    ?=    ${INSTALL} -c -s -m 555
INSTALL_MAN    ?=    ${INSTALL} -c -m 444

all:        bsdiff bspatch
bsdiff:        bsdiff.c
bspatch:    bspatch.c

install:
    ${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
    .ifndef WITHOUT_MAN
    ${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
    .endif

3.在bspatch.c文件中加入头文件

#include

4.终端执行make命令,生成bsdiff、bspatch文件

$ make

5.将bsdiff、bspatch文件拷贝到usr/local/bin 目录下
6.使用方式:

//生成差异文件
$ bsdiff oldFilePath newFilePath patchFilePath
//合并文件
$ bspatch oldFilePath newFilePath patchFilePath

二、客户端合并文件,工程需要添加libbz2.tbd
1.bsdiff.h

#ifndef bsdiff_h
#define bsdiff_h

#define LBD_OK 0

#define LBD_ERR_OPEN 1000
#define LBD_ERR_CLOSE 1005
#define LBD_ERR_MALLOC 1010
#define LBD_ERR_SEEK 1015
#define LBD_ERR_TELL 1020
#define LBD_ERR_READ 1025
#define LBD_ERR_WRITE 1030
#define LBD_ERR_CORRUPT 1035

#define LBD_ERR_BZ 2000

#include 

int ff_patch(const char *oldf, const char *patchf, const char *newf);

#endif /* bsdiff_h */

2.bsdiff.c

#include "bsdiff.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include

#define MIN(x,y) (((x)<(y)) ? (x) : (y))

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

#pragma mark - Public

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

    if ((f = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    /* Read header */
    if (fread(header, 1, 32, f) < 32)
    {
        if (feof(f))
        {
            return LBD_ERR_CORRUPT;
        }

        return LBD_ERR_READ;
    }

    /* Check for appropriate magic */

    // had to change this to use patches created with command line bsdiff
    //    if (memcmp(header, "LBDIFFXX", 8) != 0)
    if (memcmp(header, "BSDIFF40", 8) != 0)
    {
        return LBD_ERR_CORRUPT;
    }

    /* Read lengths from header */
    bzctrllen = offtin(header + 8);
    bzdatalen = offtin(header + 16);
    newsize = offtin(header + 24);
    if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
    {
        return LBD_ERR_CORRUPT;
    }

    /* Close patch file and re-open it via libbzip2 at the right places */
    if (fclose(f))
    {
        return LBD_ERR_CLOSE;
    }

    if ((cpf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(cpf, 32, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if ((dpf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if ((epf = fopen(patchf, "r")) == NULL)
    {
        return LBD_ERR_OPEN;
    }

    if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
    {
        return LBD_ERR_SEEK;
    }

    if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
    {
        return LBD_ERR_BZ;
    }

    if (((fd = open(oldf, 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))
    {
        return LBD_ERR_OPEN;
    }

    if ((new = malloc(newsize + 1)) == NULL)
        return LBD_ERR_MALLOC;

    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)))
            {
                return LBD_ERR_CORRUPT;
            }

            ctrl[i] = offtin(buf);
        }

        /* Sanity-check */
        if (newpos + ctrl[0] > newsize)
        {
            return LBD_ERR_CORRUPT;
        }

        /* Read diff string */
        lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]);
        if ((lenread < ctrl[0]) ||
            ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
        {
            return LBD_ERR_CORRUPT;
        }

        /* 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)
        {
            return LBD_ERR_CORRUPT;
        }

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

        /* 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))
    {
        return LBD_ERR_CLOSE;
    }

    /* Write the new file */
    if (((fd = open(newf, O_CREAT|O_TRUNC|O_WRONLY, 0666)) < 0) ||
        (write(fd, new, newsize) != newsize) || (close(fd) == -1))
    {
        return LBD_ERR_OPEN;
    }

    free(new);
    free(old);

    return LBD_OK;
}

三、iOS客户端解压缩工具:SSZipArchive

四、参考项目react-native-pushy

五、版本管理脚本化 待更新

你可能感兴趣的:(iOS,react-native)