热更新

柔情只为你懂 2022-06-10 23:40 598阅读 0赞

虽然有插件开发,但热更新少不了。

Center

当我们需要更新插件的时候使用的是插件开发,当我们需要更新宿主程序就需要使用热更新

热更新使用框架bsdiff和bzip2

我们需要在服务端使用新版apk和旧版apk生成差分包,由于服务端在windows下,所以生成动态文件(dll)

通过寻找bsdiff的入口函数在bsdiff.cpp中在,因为截止到现在我主要了解了一点c,所以把bsdiff.cpp改成了bsdiff.c

  1. int main(int argc,char *argv[])
  2. {
  3. int fd;
  4. u_char *old,*_new;
  5. off_t oldsize,newsize;
  6. off_t *I,*V;
  7. off_t scan,pos,len;
  8. off_t lastscan,lastpos,lastoffset;
  9. off_t oldscore,scsc;
  10. off_t s,Sf,lenf,Sb,lenb;
  11. off_t overlap,Ss,lens;
  12. off_t i;
  13. off_t dblen,eblen;
  14. u_char *db,*eb;
  15. u_char buf[8];
  16. u_char header[32];
  17. FILE * pf;
  18. BZFILE * pfbz2;
  19. int bz2err;
  20. if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
  21. /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
  22. that we never try to malloc(0) and get a NULL pointer */
  23. //org:
  24. //if(((fd=open(argv[1],O_RDONLY,0))<0) ||
  25. // ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
  26. // ((old=malloc(oldsize+1))==NULL) ||
  27. // (lseek(fd,0,SEEK_SET)!=0) ||
  28. // (read(fd,old,oldsize)!=oldsize) ||
  29. // (close(fd)==-1)) err(1,"%s",argv[1]);
  30. //new:
  31. //Read in chunks, don't rely on read always returns full data!
  32. if(((fd=open(argv[1],O_RDONLY|O_BINARY|O_NOINHERIT,0))<0) ||
  33. ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
  34. ((old=(u_char*)malloc(oldsize+1))==NULL) ||
  35. (lseek(fd,0,SEEK_SET)!=0))
  36. err(1,"%s",argv[1]);
  37. int r=oldsize;
  38. while (r>0 && (i=read(fd,old+oldsize-r,r))>0) r-=i;
  39. if (r>0 || close(fd)==-1) err(1,"%s",argv[1]);
  40. if(((I=(off_t*)malloc((oldsize+1)*sizeof(off_t)))==NULL) ||
  41. ((V=(off_t*)malloc((oldsize+1)*sizeof(off_t)))==NULL)) err(1,NULL);
  42. qsufsort(I,V,old,oldsize);
  43. free(V);

这里贴上前几行代码,只要调用这个函数就能得到差分包(.patch),
而从if(argc!=4) errx(1,”usage: %s oldfile newfile patchfile\n”,argv[0]);这行代码可以知道,argc这个参数必须等于4才可以正常执行,argv数组的第一个参数没有要求,从后面代码得到第二个参数为旧版apk的路径,第三个参数为新版apk的路径,第四个参数为生成的差分包的位置。

当我们差分的时候只要调用这个main函数并传递相应参数就可以得到差分包了,所以我们修改入口函数的名字,目的是当我们调用的时候采取执行。我们只需要在bsdiff这个文件下实现我们声明的native方法并调用入口函数。然后生成动态库文件放入服务端项目下用来辅助生成差分包

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class com_dongnaoedu_bsdiff_BsDiff */
  4. #ifndef _Included_com_dongnaoedu_bsdiff_BsDiff
  5. #define _Included_com_dongnaoedu_bsdiff_BsDiff
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class: com_dongnaoedu_bsdiff_BsDiff
  11. * Method: diff
  12. * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
  13. */
  14. JNIEXPORT void JNICALL Java_com_dongnaoedu_bsdiff_BsDiff_diff
  15. (JNIEnv *, jclass, jstring, jstring, jstring);
  16. #ifdef __cplusplus
  17. }
  18. #endif
  19. #endif
  20. public class BsDiff {
  21. /**
  22. * 差分
  23. *
  24. * @param oldfile
  25. * @param newfile
  26. * @param patchfile
  27. */
  28. public native static void diff(String oldfile, String newfile, String patchfile);
  29. static{
  30. System.loadLibrary("bsdiff");
  31. }
  32. }

这里只贴出了部分代码。这样我们就可以得到差分包,在服务器就可以获取这个差分包,然后我们需要从客户端下载这个差分包并与旧版apk进行合并生成新版apk,这样就可以省去部分流量。

合并的入口函数在bspatch文件中,下面为bspatch文件中native方法的实现,bspatch_main就是改了名字之后的入口函数

  1. //合并
  2. JNIEXPORT void JNICALL Java_com_dongnaoedu_appupdate_utils_BsPatch_patch
  3. (JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr, jstring patchfile_jstr){
  4. int argc = 4;
  5. char* oldfile = (char*)(*env)->GetStringUTFChars(env,oldfile_jstr, NULL);
  6. char* newfile = (char*)(*env)->GetStringUTFChars(env,newfile_jstr, NULL);
  7. char* patchfile = (char*)(*env)->GetStringUTFChars(env,patchfile_jstr, NULL);
  8. //参数(第一个参数无效)
  9. char *argv[4];
  10. argv[0] = "bspatch";
  11. argv[1] = oldfile;
  12. argv[2] = newfile;
  13. argv[3] = patchfile;
  14. bspatch_main(argc,argv);
  15. (*env)->ReleaseStringUTFChars(env,oldfile_jstr, oldfile);
  16. (*env)->ReleaseStringUTFChars(env,newfile_jstr, newfile);
  17. (*env)->ReleaseStringUTFChars(env,patchfile_jstr, patchfile);
  18. }

和差分类似,数组的第三个参数为生成的新版本apk路径

查分和合并使用bsdiff主要依赖于bzip2这个框架

然后我们就生成动态库文件(.so),因为安卓运行在linux平台所以生成的动态库文件和前面不同。自此我们生成了两个动态库文件,分别运行在服务端进行差分和运行在客户端进行合并。

System.getProperty(“os.name”)能输出系统名字,能用于判断运行的操作系统

System.load(“路径”)加载指定文件下的库文件

差分算法:比较新旧文件,标识出翔通部分,压缩不同部分和额外部分(主要以来bzip2)生成patch文件

合并算法:生成的patch文件和旧文件合成新文件

当然这些算法内部实现非常复杂

发表评论

表情:
评论列表 (有 0 条评论,598人围观)

还没有评论,来说两句吧...

相关阅读

    相关 更新

    单来说我的理解就是:当你的文件发现改变的时候页面自己就更新了。不用你再手动刷新页面。无刷新更新 常见的需求如赛事网页推送比赛结果、网页实时展示投票或点赞数据、在线评论或...

    相关 更新

    介绍下 webpack 热更新原理,是如何做到在不刷新浏览器的前提下更新页面   1.当修改了一个或多个文件; 2.文件系统接收更改并通知webpack; 3.we

    相关 webpack实现更新

    昨天看到公司有前端同事在研究`webpack`,今天有空正好找下资料也`look look` 我最早接触`webpack`是2019年6月-7月之间,当时对前端还是很模糊的,

    相关 更新

    虽然有插件开发,但热更新少不了。 ![Center][] 当我们需要更新插件的时候使用的是插件开发,当我们需要更新宿主程序就需要使用热更新 热更新使用框架bsdif