android增量更新, Say yes

今天學(xué)習(xí)了一下增量更新,這個技術(shù)已經(jīng)出現(xiàn)很長時間了,但是現(xiàn)實中,估計只有大廠才利用了這一技術(shù)在做產(chǎn)品!
國內(nèi)有些第三方服務(wù)平臺,像友盟提供自動更新的服務(wù),也是用的增量方式!
其他的像QQ,Sina微博,陌陌,蘑菇街等都用到了,解壓一下它們的apk,看一下lib目錄:
QQ:libbspatch.so
微博:libbsdiffjni.so
陌陌:libbsdiff.so
蘑菇街:libpatcher.so
這些只不過so的名字不一樣而已,但都用到了增量更新.
其它的一些主流app解包后,都看到了libandfix.so這個庫,這個是阿里推出的一個支持ART和Dalvik的熱修復(fù)的框架,在線修復(fù)bug.

今天學(xué)習(xí)增量更新而非熱更新
主角:http://www.daemonology.net/bsdiff
官方說明:
(1)bsdiff 和 bspatch是編譯,安裝補丁到二進(jìn)制文件的一個工具,
(2)這個工具用到了bzip2的壓縮功能,所以補丁的大小小于新舊版本的一個差值
(3)bsdiff非常吃內(nèi)存

1.編譯生成工具

開干,我用的是ubuntu,點擊here下源代碼,編譯



解壓,可以看到一共5個文件

shone@Dell:~/Soft/bsdiff-4.3$ ls
bsdiff.1  bsdiff.c  bspatch.1  bspatch.c  Makefile

然后編譯make,報錯

Makefile:13: *** missing separator.  Stop.

查看一下Makefile


無奈,在網(wǎng)上找了一下,找到了解決方法.
http://kinggoo.com/bsdiffupdate.htm#respond
原因是:目標(biāo)體下一行的遣蚀,命令要用TAB鍵開頭莹妒,且不能隔一行卡啰。
也就是說在.ifndef的前面要有TAB開頭才可以~因為他是安裝的下一個子集命令。

接著編譯,結(jié)果報錯,找不到頭文件

bsdiff.c:33:19: fatal error: bzlib.h: No such file or directory
 #include <bzlib.h>
                   ^
compilation terminated.

先前說過bsdiff依賴bzip2,有圖


好,下載bzip2,解壓
http://www.bzip.org/downloads.html
make
sudo make install
安裝的時候,會創(chuàng)建一些文件,所以給權(quán)限
然后編譯

cc -O3  -lbz2    bsdiff.c   -o bsdiff
/tmp/cctTxPKV.o: In function `main':
bsdiff.c:(.text.startup+0x2aa): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0x9e9): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xb2c): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xc7b): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xccf): undefined reference to `BZ2_bzWriteClose'
bsdiff.c:(.text.startup+0xd22): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0xd4d): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xd73): undefined reference to `BZ2_bzWriteClose'
bsdiff.c:(.text.startup+0xdc6): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0xdf1): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xe17): undefined reference to `BZ2_bzWriteClose'
collect2: error: ld returned 1 exit status
make: *** [bsdiff] Error 1

第一個反應(yīng)還是,連接bzip2庫除了問題,其實不用makefile腳本也可以得到2個二進(jìn)制工具

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

仔細(xì)看下這個Makefile, bsdiff和bspatch分別是2個模塊,互不依賴,用make僅僅是多了可以指定目標(biāo)到/usr/local目錄,然后提供了一鍵安裝功能,就是部署二進(jìn)制工具和幫助(man)命令到/usr/local, Makefile僅僅是大項目管理的利器,還好這個文件不多,可以2次手動編譯就完成了!

gcc bsdiff.c -lbz2 -o bsdiff

好可以生成,bzip2庫之前已經(jīng)安裝在系統(tǒng)標(biāo)準(zhǔn)目錄

gcc bspatch.c -lbz2 -o bspatch

2個工具都可以正常生成!

linux下鏈接庫通常會去3個文件下找
/lib是內(nèi)核級的,/usr/lib是系統(tǒng)級的,/usr/local/lib是用戶級的

想了下,Makefile估計還是有點問題,然后自己改了下

CC=gcc

LDFLAGS=

CFLAGS=-Wall -O3 -g -lbz2


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


all:            bsdiff bspatch
bsdiff:         bsdiff.c
        $(CC) bsdiff.c  $(CFLAGS) $(LDFLAGS) -o  bsdiff
bspatch:        bspatch.c
        $(CC) bspatch.c  $(CFLAGS) $(LDFLAGS) -o  bspatch


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

這樣make就可以成功生成2個工具了


Makefile的規(guī)則
  目標(biāo) : 需要的條件 (注意冒號兩邊有空格)
    命令 〉「住(注意前面用tab鍵開頭)
  解釋一下:
  1 目標(biāo)可以是一個或多個,可以是Object File求厕,也可以是執(zhí)行文件年柠,甚至可以是一個標(biāo)簽。
  2 需要的條件就是生成目標(biāo)所需要的文件或目標(biāo)
  3 命令就是生成目標(biāo)所需要執(zhí)行的腳本

2.生成補丁文件

差分生成補丁方式
bsdiff old_version.apk new_version.apk diff.patch
分別是3個參數(shù),老版本,新版本,補丁
還沒有apk,首要任務(wù)先生成2個版本的apk
這里要把補丁合成功能移植到手機客戶端上,那么就要用到NDK了

bsdiff是二進(jìn)制差分工具,其對應(yīng)的bspatch是相應(yīng)的補丁合成工具

鏡頭切換到androidstudio上

2.1 先定義一個調(diào)度native層的類

public class Updater {

    public static native void applyPatch(String oldPath, String newPath, String patchPath);

}

2.2 生成.h頭文件

因為as的版本原因,生成.h的方式也不一樣,我用的androidstudio版本是2.1.1v,網(wǎng)上方法大多不可行,正確的姿勢是

shone@Dell:~/Public/work_androidstudio/PatchUpdate/app/build/intermediates/classes/debug$ javah com.sugar.patch.Updater

主要是先編譯一下模塊,然后進(jìn)入到debug目錄,用javah命令
好了,如果沒有問題,會看見一個.h文件


2.3 編寫補丁合成代碼

<1>首先建立一個jni的文件夾,將.h頭文件移動過來
<2>因為補丁合成用到bzip2解壓,所以要把zip2的包拷貝過來
<3>然后將bspatch.c拷貝到j(luò)ni下面
bspatch.c實際上只有2個函數(shù),一個offtin和main(),增加一個native函數(shù)

JNIEXPORT void JNICALL Java_com_sugar_patch_Updater_applyPatch
  (JNIEnv *env, jclass clazz, jstring old_path, jstring new_path, jstring patch){
      int argc=4;
      char * argv[argc];
      argv[0]="bspatch";
      argv[1]=(*env)->GetStringUTFChars(env, old_path, 0);
      argv[2]=(*env)->GetStringUTFChars(env, new_path, 0);
      argv[3]=(*env)->GetStringUTFChars(env, patch, 0);

      int ret = domain(argc, argv);

       (*env)->ReleaseStringUTFChars(env,old_path, argv[1]);
       (*env)->ReleaseStringUTFChars(env,new_path, argv[2]);
       (*env)->ReleaseStringUTFChars(env,patch, argv[3]);
       return ret;
}

懂jni的都知道,這個函數(shù)名是不能亂寫的,必須把.h頭文件的那個聲明函數(shù)拷貝過來,然后參數(shù)修改和增加主體,java調(diào)native會傳值到這個函數(shù)里來!
然后這里會調(diào)用main()方法,這里我把main方法名字改成了domain,因為main是C程序的入口,這里不需要這個入口
下面是我自己的測試案例:

native代碼寫好了,那么java需要傳入3個參數(shù)的值

java核心代碼
String oldVersionPath = AppUtils.getOldVersionPath(context.get());
Updater.applyPatch(oldVersionPath, newVersionPath, downPatchPath);

這里需要三個路徑,定義常量

public interface Contants {

    String rootDir = Environment.getExternalStorageDirectory().getAbsolutePath()
            + File.separator + "PatchCache" + File.separator;
    String downPatchPath = rootDir + "apk.patch";
    String newVersionPath = rootDir + "PatchUpdate_v_2_0.apk";
}

oldVersionPath為app在手機上的安裝包路徑,從ApplicationInfo這個類獲得,newVersionPath為新版本apk包合成地址,downPatchPath為補丁地址

為了測試,這里把補丁文件apk.patch會先放到sd卡/PatchCache/這個目錄下,等app合成完成后,新的apk會輸出到sd卡/PatchCache/下


然后有了合成后的,就可以安裝更新了

AppUtils.install(context.get(), newVersionPath);

服務(wù)端差分補丁

shone@Dell:~/Soft/bsdiff-4.3$ ls
app_v_1_0.apk  bsdiff    bsdiff.c  bspatch.1  Makefile
app_v_2_0.apk  bsdiff.1  bspatch   bspatch.c

app_v_1_0.apkapp_v_2_0.apk分別是1.0和2.0版本,測試的話
我下了幾張高清圖片放到了2.0版本的assets下面,這樣2.0版本的apk大小會比較大,1.0版本大小是1.7M,2.0版本是16.9M,差分后apk.patch有14M!

shone@Dell:~/Soft/bsdiff-4.3$ ./bsdiff app_v_1_0.apk app_v_2_0.apk apk.patch
shone@Dell:~/Soft/bsdiff-4.3$ ls
apk.patch  app_v_1_0.apk  app_v_2_0.apk  bsdiff  bsdiff.1  bsdiff.c  bspatch  bspatch.1  bspatch.c  Makefile

好了,分析到這了
下面是我的測試項目,可以自己測測
https://github.com/shonegg/PatchUpdate

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末梯轻,一起剝皮案震驚了整個濱河市食磕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喳挑,老刑警劉巖彬伦,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伊诵,居然都是意外死亡单绑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門日戈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孙乖,你說我怎么就攤上這事浙炼》菅酰” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵弯屈,是天一觀的道長蜗帜。 經(jīng)常有香客問我,道長资厉,這世上最難降的妖魔是什么厅缺? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮宴偿,結(jié)果婚禮上湘捎,老公的妹妹穿的比我還像新娘。我一直安慰自己窄刘,他們只是感情好窥妇,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娩践,像睡著了一般活翩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翻伺,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天材泄,我揣著相機與錄音,去河邊找鬼吨岭。 笑死拉宗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的未妹。 我是一名探鬼主播簿废,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼络它!你這毒婦竟也來了族檬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤化戳,失蹤者是張志新(化名)和其女友劉穎单料,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體点楼,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡扫尖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掠廓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片换怖。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蟀瞧,靈堂內(nèi)的尸體忽然破棺而出沉颂,到底是詐尸還是另有隱情条摸,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布铸屉,位于F島的核電站钉蒲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏彻坛。R本人自食惡果不足惜顷啼,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昌屉。 院中可真熱鬧钙蒙,春花似錦、人聲如沸怠益。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜻牢。三九已至烤咧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抢呆,已是汗流浹背煮嫌。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抱虐,地道東北人昌阿。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像恳邀,于是被迫代替她去往敵國和親懦冰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1.概述 1.1.什么是應(yīng)用增量更新 當(dāng)我們要更新一個應(yīng)用的時候谣沸,以前很多更新的做法是下載一個新版本去覆蓋一個舊版...
    揚靈閱讀 3,152評論 8 19
  • 增量更新在Android開發(fā)中是一種很常見的技術(shù)乳附。 增量更新的原理 增量更新的原理非常簡單内地,就是將本地apk與服務(wù)...
    re冷星閱讀 1,561評論 3 3
  • @[增量更新,差分包,bsdiff/patch] 背景 隨著Android app的不斷迭代升級,功能越來越多赋除,a...
    SunYo閱讀 14,426評論 2 7
  • 9月21日阱缓,夜宿洪椿坪。 洪椿坪位于峨眉山天池峰下举农,海拔1120米處的山腰里荆针。是我們四天三夜的行走活動中,在山上第...
    文曉玲閱讀 924評論 4 8
  • 姓名:陳權(quán) 公司:青檸養(yǎng)車 【知~學(xué)習(xí)】 《阿米巴經(jīng)營》音頻打卡第11天 《輕課口語》打卡第370天 【行~實踐】...
    水青檸閱讀 141評論 0 0