差分升级主要流程就是,拿新APK和旧apk进行比较生成patch包,放在服务器上让用户下载,用户下载完成后本地apk程序再将本地的apk和patch包整合成一个最新的apk让用户进行安装。 我们需要如下2套源码来实现以上功能 bsdiff/bzlib2 这里我还要介绍一下其实android已经集成了以上两个模块,我们可以在源码的external目录里面看到bsdiff和bzip2两个文件夹对应的就是上面的2套源码。 我们在能编译的源码环境中mmm external/bsdiff看如下截图
 这里out/host/linux-x86/obj32/EXECUTABLES/bspatch_intermediates/bsdiff就是用来生成patch的,out/host/linux-x86/obj32/EXECUTABLES/bspatch_intermediates/bspatch是用来整合patch生成新apk的。
所以我们可以拿bsdiff去生成patch包,然后把bspatch相关代码整合成so库加载到我们应用内去运行再生成最新的整包这整个差分升级功能就完成了。 bsdiff命令如下,大家可以自己尝试oldfile是旧包路径+文件名,newfile是新包的,patchfile是生成的patch我们这里可以随便命名为XXX.patch
./bsdiff oldfile newfile patchfile 以上前期准备完成了,现在直奔主题贴上android上功能实现需要的代码 1、新建jni目录存放so库所需源码我只写了3个文件
bs_patch.c
bs_patch.h
Android.mk - #ifndef BS_PATCH_H
- #define BS_PATCH_H
- JNIEXPORT jint JNICALL Java_com_android_updatetest_util_PatchUtil_applyPatchToApk
- (JNIEnv *, jclass, jstring, jstring, jstring);
- #endif
复制代码bs_patch.c这个文件功能参考源码external/bsdiff/bspatch.c加了jni接口 - #include <jni.h>
- #include "bs_patch.h"
- #include <bzlib.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <err.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- 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 applypatch(int argc, const 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 *oldStr, *newStr;
- off_t oldpos, newpos;
- off_t ctrl[3];
- off_t lenread;
- off_t i;
- if (argc != 4)
- errx(1, "usage: %s oldfile newfile patchfile\n", argv[0]);
- /* Open patch file */
- if ((f = fopen(argv[3], "r")) == NULL)
- err(1, "fopen(%s)", argv[3]);
- /*
- 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))
- errx(1, "Corrupt patch\n");
- err(1, "fread(%s)", argv[3]);
- }
- /* Check for appropriate magic */
- if (memcmp(header, "BSDIFF40", 8) != 0)
- errx(1, "Corrupt patch\n");
- /* Read lengths from header */
- bzctrllen = offtin(header + 8);
- bzdatalen = offtin(header + 16);
- newsize = offtin(header + 24);
- if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
- errx(1, "Corrupt patch\n");
- /* Close patch file and re-open it via libbzip2 at the right places */
- if (fclose(f))
- err(1, "fclose(%s)", argv[3]);
- if ((cpf = fopen(argv[3], "r")) == NULL)
- err(1, "fopen(%s)", argv[3]);
- if (fseeko(cpf, 32, SEEK_SET))
- err(1, "fseeko(%s, %lld)", argv[3], (long long) 32);
- if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
- if ((dpf = fopen(argv[3], "r")) == NULL)
- err(1, "fopen(%s)", argv[3]);
- if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
- err(1, "fseeko(%s, %lld)", argv[3], (long long) (32 + bzctrllen));
- if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
- if ((epf = fopen(argv[3], "r")) == NULL)
- err(1, "fopen(%s)", argv[3]);
- if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
- err(1, "fseeko(%s, %lld)", argv[3],
- (long long) (32 + bzctrllen + bzdatalen));
- if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
- if (((fd = open(argv[1], O_RDONLY, 0)) < 0)
- || ((oldsize = lseek(fd, 0, SEEK_END)) == -1) || ((oldStr =
- (u_char*) malloc(oldsize + 1)) == NULL)
- || (lseek(fd, 0, SEEK_SET) != 0)
- || (read(fd, oldStr, oldsize) != oldsize) || (close(fd) == -1))
- err(1, "%s", argv[1]);
- if ((newStr = (u_char*) malloc(newsize + 1)) == NULL)
- err(1, NULL);
- 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)))
- errx(1, "Corrupt patch\n");
- ctrl[i] = offtin(buf);
- };
- /* Sanity-check */
- if (newpos + ctrl[0] > newsize)
- errx(1, "Corrupt patch\n");
- /* Read diff string */
- lenread = BZ2_bzRead(&dbz2err, dpfbz2, newStr + newpos, ctrl[0]);
- if ((lenread < ctrl[0])
- || ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
- errx(1, "Corrupt patch\n");
- /* Add old data to diff string */
- for (i = 0; i < ctrl[0]; i++)
- if ((oldpos + i >= 0) && (oldpos + i < oldsize))
- newStr[newpos + i] += oldStr[oldpos + i];
- /* Adjust pointers */
- newpos += ctrl[0];
- oldpos += ctrl[0];
- /* Sanity-check */
- if (newpos + ctrl[1] > newsize)
- errx(1, "Corrupt patch\n");
- /* Read extra string */
- lenread = BZ2_bzRead(&ebz2err, epfbz2, newStr + newpos, ctrl[1]);
- if ((lenread < ctrl[1])
- || ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
- errx(1, "Corrupt patch\n");
- /* 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))
- err(1, "fclose(%s)", argv[3]);
- /* Write the new file */
- if (((fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0)
- || (write(fd, newStr, newsize) != newsize) || (close(fd) == -1))
- err(1, "%s", argv[2]);
- free(newStr);
- free(oldStr);
- return 0;
- }
- jint JNICALL Java_com_android_updatetest_util_PatchUtil_applyPatchToApk(JNIEnv *env,
- jobject obj, jstring old, jstring new , jstring patch){
- int argc=4;
- char * argv[argc];
- argv[0]="bspatch";
- argv[1]=(char*)((*env)->GetStringUTFChars(env,old, 0));
- argv[2]=(char*)((*env)->GetStringUTFChars(env,new, 0));
- argv[3]=(char*)((*env)->GetStringUTFChars(env,patch, 0));
- int ret = -1;
- ret = applypatch(argc, argv);
- (*env)->ReleaseStringUTFChars(env,old,argv[1]);
- (*env)->ReleaseStringUTFChars(env,new,argv[2]);
- (*env)->ReleaseStringUTFChars(env,patch,argv[3]);
- return ret;
- }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- Android.mk
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := libtest_bspatch
- LOCAL_SRC_FILES := bs_patch.c
- LOCAL_C_INCLUDES += external/bzip2
- LOCAL_STATIC_LIBRARIES := libbz
- include $(BUILD_SHARED_LIBRARY)
复制代码待续
|