市场上现存方案:微软的 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
五、版本管理脚本化 待更新