From 342ff10a0846b89754704c8ce8385dc6a61ffcd5 Mon Sep 17 00:00:00 2001 From: sisong Date: Sat, 10 Jun 2023 20:59:54 +0800 Subject: [PATCH] update to v1.1.1; fix reasve; optimized android .so files size; --- README.md | 4 ++-- cmdline_doc.md | 6 +++--- img/com.tripadvisor.tripadvisor.png | Bin 2354 -> 1645 bytes img/com.ubercab.png | Bin 875 -> 765 bytes img/tv.danmaku.bili.png | Bin 2942 -> 3465 bytes 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e828cdb..50ab095 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # sfpatcher:针对应用商店的apk增量算法 -**v1.0.15 已正式上线**,为亿级手机终端用户提供更新服务,当前最新版本 v1.1.0 +**v1.0.15 已正式上线**,为亿级手机终端用户提供优化的更新服务,当前最新版本 v1.1.1 [**sfpatcher** 命令行工具下载](https://github.com/sisong/sfpatcher/releases)(支持Windows、Linux、MacOS), [命令行使用说明](https://github.com/sisong/sfpatcher/blob/master/cmdline_doc.md) 需要商业授权(含源代码&培训),请联系作者: @@ -41,7 +41,7 @@ - 针对应用商店的场景专门设计,优化补丁大小,支持大型游戏,patch时精确快速还原任意apk文件,能够用于用户交互场景。 - 多级可选的补丁包大小,极致的patch速度:提供比谷歌**archive-patcher**方案(+brotli-9压缩)下载补丁小10%的情况下,手机上patch速度是其8倍(这时补丁比BsDiff方案小约50%并且速度快得多)!补丁比其略大1%的情况下,手机上速度是其21倍!补丁比其小21%的情况下,平均速度是其3.5倍! (注1) - patch时的内存等资源占用可控;diff时支持多种方案限制patch时的最大内存占用到合适的约定水平。即支持patch时O(1)平均内存占用的优化补丁包(并且patch不使用临时文件)! -- 优化的用户体验:支持下载数据的同时就可以开始patch,不用将补丁文件保存到内存或硬盘上,结合快速的patch,很多时候下载完成时,就可以得到了完整的新版本apk文件。(因为补丁变小,下载时间也会变短,从而可能缩短整体更新时间。) +- 优化的用户体验:支持下载数据的同时就可以开始patch,不用将补丁文件保存到内存或硬盘上,结合快速的patch,很多时候下载完成时,就可以得到了完整的新版本apk文件。因为补丁变小,下载时间也会变短,从而可能缩短整体更新时间,也更省电省流量。 - 利用精确还原算法,对于初次下载的apk文件也能进行解压后的重压缩;从而节省用户初次下载apk时的流量。最多情况下平均比直接下载apk文件减少22%的数据,部分文件能减少35%以上的数据! - 支持从中断的位置继续patch的特性,节省程序被终止后再次执行程序时的打补丁时间。 - 高扩展性,框架支持多种压缩档案格式(apk、zip、zip64、jar、gz、tar等)和其嵌套(如apk中多个子apk); 档案格式本身和档案中数据的压缩算法都只是以插件的形式获得支持。patch端的执行,设计上不依赖于具体的档案格式。 diff --git a/cmdline_doc.md b/cmdline_doc.md index 10b4a1a..5137d3c 100644 --- a/cmdline_doc.md +++ b/cmdline_doc.md @@ -59,7 +59,7 @@ options: if newData not similar to oldData then diff speed++, big cache max used O(oldFileSize) memory, and build slow(diff speed--) -step-patchStepMemroySize - set patch step memory size, DEFAULT -sm-2m, recommended: 64k,512k,8m etc... + set patch step memory size, DEFAULT -step-2m, recommended: 64k,512k,8m etc... -pre set is always decode newArchiveFile (precompress), DEFAULT false; if set this option, outDiffFile maybe smaller, but maybe slower when patch; @@ -131,7 +131,7 @@ options: * **-pre 选项**:设置是否始终让新版本数据处于解压缩状态,默认不(即保持原压缩状态不解压);一般在diff过程中新旧数据都在解压缩状态进行匹配,当解压状态的部分新数据没有搜寻到匹配数据时,默认就会还原成压缩状态,这样有利于优化patch时的速度,减少需要重新压缩的数据量。 打开的情况下(即始终解压),一般输出文件会小一些(相当于解压后用更好的压缩算法重新压缩了数据)。 推荐用于当旧版本文件为空,并和-o-2和-c-lzma2一起用于新版本的初次下载优化,比如: -`$ sf_diff "" "new.apk" "recompressed.pat" -pre –o-2 -c-lzma2-9-32m -p-8` +`$ sf_diff "" "new.apk" "recompressed.pat" -pre -o-2 -c-lzma2-9-32m -p-8` * **-lp 选项**:设置解压出临时数据的最大内存占用;该值可以控制patch时的最大内存占用值。当设置-o-2或-o-3时默认值为最大2文件解压缩后数据大小的和;而使用-o-1时一般不用设置(推荐-lp-512k);如果patch时使用临时文件来存放临时解压出的old数据,那-lp的设置值无意义;设置过小,可能会使输出的补丁包变大。 为了控制patch时的最大内存,推荐始终设置该值,比如: @@ -228,7 +228,7 @@ patch端建议参数:`$ sf_patch "old.apk" "diff.pat" "out_new.apk" -lp -p-12` patch端建议参数:`$ sf_patch "old.apk" "diff.pat" "out_new.apk" -lp -p-14` * 对新版本的初次下载大小优化,并且保持最差patch速度勉强可接受: -`$ sf_diff "" "new.apk" "recompressed.pat" -pre –o-2 -c-lzma2-9-16m` +`$ sf_diff "" "new.apk" "recompressed.pat" -pre -o-2 -c-lzma2-9-16m` (patch时内存占用估算:0m+0m+16m,最大约30MB左右。) patch端建议参数:`$ sf_patch "" "recompressed.pat" "out_new.apk" -p-10` diff --git a/img/com.tripadvisor.tripadvisor.png b/img/com.tripadvisor.tripadvisor.png index 313b5fc922db22d36b715628a4ad987faba82a45..5de25eace9e21c541fbb479708fd5771a873b0ac 100644 GIT binary patch delta 1629 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 O00007-eN;>+9<^H8u3~^a=_J&CSgpA0HeX z9BgcCE-o(9)6<)qn^ICzOG``q{QUa*`oY1$v$L~ua&qVA=hoKNn3$MeUS2vnI_>T4 zii(PLb#*BzDWamHMn*CcrlarvJppA`4(w0zy%&_e<^jzuegYJlc+S9RGF3 z3?W%$FOuw;WH1=ufih^l$4op}p5jw{ioc3cV)ZCoSHMl8`$Tbqb1%9_6j;xv5jXt2 zr0K#==MBUiqKkcAFJJ=}Jl}VMS$;%vm-t5dr5D4{2_$`BC?av5^*@+KTosk-#03~F z(FU7VbYR=IWs9p~KO>mCmoS~kRB_JXE%BJeGvANrY;uq@_I>{~lsnA5r+ajsunkORK0rQZ?8Ac`11gRvsnK!rhDART$TT&TnDml)8 zHsYa$TVjc!C58wzeNJUqt(=jQc}jXtt{g1RS)Gs$eq?nBa2?ZTPr2U}qC-aSBaZ6D z1bb2qGe1?RzKi9As<;7VG9Huaji_wOV}DUKPI=empTlHmb2!s@@4; z6mQnBd$BbwAgiV(u497^U~xydz}oY`bnUWo&3{B9PH2Mc|| literal 875 zcmV-x1C;!UP)5`1lwY7zYOj^z`%!3JUV_^5Nm(T3T8V5D+#tHfCmK4h{|+92^xD z73=Hk>gwujY-}zrF4NP~o12?bQc_DxOZ@!&`uh6t@bGeSa_8sg*4Ea{%*>dWm}6sO zUS3{TS64bZIv*b&?d|R3u#z*6ot>)40o*{&{l2*5!7nE*V=pE|EbOlSkL)mOGy7TVI>2z zX0pHR**ie^)2h|a3Jp|))0l*YYC$ci1+}36K)T&WC8j70imf*Tsi$3rqx2>qhV^Wu zgNfOt=gqs`tbp18q~IY)=CA+>nd^2oli&?@BhWROm*@&mPt!UVGTmaV>MA=$oeUFs z*8&+v1)77~zFG$JJHJQ*(6zc!m(>CtGlKAd1*m*L7ehTISR3@_ZzqnE&Nzty`J?MN zS03N)nCakSGUTf@L8(lUt5NV&wn8I=oA4g+D4Y^4>w_p-u8}W@_P|V|g^$4#(GZ?Y z@@`htuaWGP&ABJTM?%j4gfRu^1weh!6UGudU}MtjNY>(2XOR0@B= zM7y#TGKH?g7c+PiBoN8TebR8{RJ?sJQS8A^63Bo002ovPDHLkV1o9K BnTP-Y diff --git a/img/tv.danmaku.bili.png b/img/tv.danmaku.bili.png index e78bdebcaeeb99c9481cc25dd08fecdec5deef72..aa6858f35fe01b4b4d45d2b3b1df823469fdd6ce 100644 GIT binary patch delta 3462 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 delta 2935 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 hF8}v%^2vQ-