移動產品熱更新的功能指標和實現架構

前言golang

熱更新能力是影響產品運營效率和用戶留存的關鍵能力,本文根據卓盟信息科技CTO王志海在七牛架構師實踐日上海站上的分享,介紹了卓盟旗下產品樂變熱更的產品設計、技術原理、理論基礎和架構,幫助你們更好的實現產品地優化。算法


我今天是來跟你們分享一下兩個方面的內容,一個是咱們的熱更新是怎麼作的,原理是怎麼樣,第二個是圍繞咱們這麼多年的經驗,也多是有哪些坑,包括遇到問題是怎麼解決的。但願是對在作熱更解決方案的朋友能有一些幫助。瀏覽器


1、熱更新的總體架構安全

首先,給你們介紹一下咱們熱更新的一個總體的結構。客戶端是這樣的,首先咱們熱更新的進程放在一個獨立的進程裏面,這樣的好處是什麼?若是咱們的客戶端剛啓動就crash了,同樣能熱更新保證能夠修復,這也是必定要放在獨立進程裏面的一個緣由。你們容易有一個誤解,是否是放在獨立進程裏面就是後臺常駐進程?其實這個不是這樣的,進程只是在需求的來去時運行它,可能咱們的一個APP的大小是30M,有多是下載的一個內容是3M左右,若是網速是在400-500K的話,可能下載的時間也就幾秒鐘,整個從下載到更新完也就是1,20秒。因此放在獨立進程裏面並不會增長系統的負擔。帶來的好處是客戶端crash了以後咱們同樣能夠把這個問題給修復。提供給運營人員使用的能夠是瀏覽器或者PC的工具,把版本是傳到管理後臺,管理後臺根據它傳過來的包計算與以前版本的一些差別,把結果是存在DB裏去,就決定了這個包進來以後升級的一個路線,360渠道的包進來升級360的版本,應用寶的進來升級應用寶的版本,而後客戶端這邊是訪問Portal的這個Sever給他返回一個有沒有新版本,若是有新版本再經過CDN網絡去下載,好比用七牛的CDN就能夠解決。這邊都是比較成熟的一個方案。服務器


2、熱更新的客戶端實現介紹微信

再看一下咱們的實現的機制。IOS是禁止熱更新的,因此咱們主要談一下安卓。須要更新的內容,一個是代碼(Java,C/C++),一個是資源,還有安卓比較特殊的四大組件。四大組件是系統安裝進來的時候就決定了,因此說咱們不能增長,這樣很麻煩,你的功能是會限的很死,一會我會詳細的給你們介紹咱們怎麼能作到新的版本里能夠新增新的組建,它的原理是怎樣的。各個部分的更新有不一樣的方案,Java部分能夠經過ClassLoader去把它給替換掉,native的部分咱們能夠經過修改ClassLoader的nativeLibraryDirectories,或者代碼裏直接loadLibrary的方式來調用新的libary也是能夠的。資源這一塊也是有多種的方案,好比I/O Remapping或者經過自定義的ResourceManager加載進來都是能夠的,組件這一塊咱們等一會再說。JavaHook也是一種方案,可是他的複雜度是會高不少,有JIT以後會更加複雜,不少時候是運行時候編譯的。這一塊咱們也有成熟的方案,但還沒到能夠商業化的程度。 網絡

咱們的熱更新的方案,是下載以後會把完整的新的版本都還原出來,還原出來以後也涉及到一個問題,當有新版本的時候,會對新版本進行一系列的管理,包括四大組件的管理,包的管理,資源管理等等,其中四大組件生命週期的管理是很重要的一部分。架構


3、熱更新架構與Android系統的關係app

安卓裏面的各大組件之間,Systerm Server 之間的通訊,不少都是經過Binder來通訊的,因此咱們能夠在客戶端這邊作一些代理,從而改變APP運行時候的執行路徑,經過這個方式能夠動態的把整個新版本加載起來運行。工具


4、新增組件處理機制

下面就給你們詳細的介紹一下若是新的版本增長一個Activity,咱們是怎麼作到的?首先,系統可以看到的必定是已經在安裝的這個包內定義的一個組件,若是咱們第一個版本只有一個Activity,那第二個版本增長了一個Activity,應該怎麼作呢?

首先第一步,先在AndroidManifest.xml裏面定義一些組件。可能你們這裏會有一些疑問,其實咱們不知道會增長什麼組件,包括名字我並不知道,其實沒有關係,這裏只是一個佔位符,咱們只要定義放在那裏就能夠了。舉一個例子,好比說咱們新的版本,增長了一個ActivityA 。第一步也就是咱們剛纔說的在第一個版本里面定義一些預留的組件,這裏咱們定義的是ProxyActivity。第二步,當新的版本去啓動ActivityA 的時候,首先客戶端這邊,在進程起來的時候咱們會作這樣的一個代理,至關於把這個客戶端的ActivtyManager改爲了咱們本身的實現,在startActivity的時候咱們會把這個intent裏面原本它是要啓動ActivityA換成咱們預先定義的Proxy Activity,而後到了AMS那邊,它能夠看獲得,這個Activity已經在版本里面定義了,因此它是可以正常工做的,它調用ScheduleLaunchActivity的時候,它回調回來的是咱們剛纔改過的Proxy Activity,但新的版本里沒有ProxyActivity這個類,因此咱們得再把他改回去,改爲原來有的ActivityA,因此咱們會把ActivityThread裏面的Callback換成咱們的,而後在handleMessage裏面再把msg.obj.intent這個類名再換回原來的,這樣ClassLoade裏面就能找到ActivityA了,後面的均可以正常工做了,這就是新增組建很關鍵的一個地方。是否是必定要在AndroidManifest中定義ProxyActivity呢在某些狀況不須要的,咱們是能夠複用,若是咱們新增的這個ActivityA和以前的Activity有相同的theme/process屬性,其實咱們是能夠是複用他以前的Activity,由於對於系統來講僅僅是一個名字而已,只要找到他就能夠了。


5、熱更新的實踐經驗

一、熱更新的主要特色和指標


給你們介紹一下咱們這麼年作熱更的經驗和心得。一個好的熱更方案,應該包括哪些功能,每一個功能會遇到什麼問題,這些問題咱們是怎麼解決的?相信這些會對你們有一些幫助。主要涉及的點有幾大方面,包括可更新的範圍,用戶的感知程度等等,那咱們就逐一的把這些給過一下。

(1)可更新的範圍

更新的範圍就是咱們剛纔所提到的,有這麼幾大塊,Java代碼,native代碼,資源,組件。實際上是當前市面上有不少熱更的方案,或多或少都有一些地方都不能更新,不是說不能用,所帶來的問題是什麼?第一個,作版本更新的時候會當心翼翼,就是我不肯定我此次更新的東西會不會致使和以前的版本不兼容。好比只能更新Java代碼,組件不能更新,新版本中新的Activity,以前你沒定義的就會有問題。固然也不是全部東西都能更新,它是受限於系統的,舉個例子來講像權限就是受限制的,若是你的第一個版本沒有定義權限,那新的版本下來的話,這個權限是沒有辦法獲取的。固然這個問題解決不了不等於說它是一個問題,咱們是能夠經過其餘的方案,好比說咱們在它在傳版本的時候咱們就來校驗他新老版本的一些權限是否有新增的,給它一些提醒,能預防的問題也是解決問題的一個方法。

(2)差分能力

第二塊是差分能力,可使用BSDIFF/BSPATCH,這個算法是MD5匹配的,也就是說咱們的代碼沒有任何的更新,只是從新編譯一次,用戶安裝了兩個不一樣版本的包,若是我是基於第一個版本作的差分包,其實第二個版本打不上去的,由於它的MD5已經變了。這裏所常見的問題是什麼?你們經過應用商店更新APP的時候常常會有這樣的體驗,有的時候它是會提示你,一個100M的包你下10M就夠了,有的時候要下100M才能夠,這是什麼緣由形成的呢?主要是渠道那邊會對咱們傳到應用商店李的包會打一些標記,好比說我傳到360的包,它爲了跟蹤APP的活躍狀況,包括用戶的付費等等,它在移動端,Web端的手機助手上的包是不同的,基於一個版本作的差分包是不能打到別的上面去。這個問題咱們是這樣解決的,咱們使用的一個叫文件級差分的方式,咱們會把這個新老版本的包給解開,咱們會計算裏面每個文件的差別,再把這個差別發回客到戶端,再來去把它還原。若是咱們發現你的包的MD5沒有,跟我服務端提上去的包不同,咱們會把這個包相關的每一個文件信息傳到服務器,根據它和這個服務器已有的包的差別,從新生成一個差分包,咱們把它叫作遠程的一個差分計算的方法。有的時候,咱們會發現,一樣的版本是改動的並不大,可是差分包的算法差異很大。是由於兩個版本之間的壓縮的等級不同,這個時候若是你直接拿整個包來算的話,可能算出來的差分包的大小和你原包的大小是很接近的。那這個解決方案也是相似的,也是經過這種差分的方式,把包解開以後,再去逐個算裏面文件的MD5,這個方法理論上面是可以是作的很小的,可是當前有一個弊端,由於新的版本是在客戶端從新合成apk的,因此有一些信息是會丟失,MD5和原來傳在服務器上的MD5是不同的,有些加固的算法可能會校驗這個包的MD5,因此這個是一個平衡,在你的差分包大小和安全性等等方面找了一個折中。

(3)用戶感知度控制

更新版本的時候相信你們有這樣的體驗,好比說你們玩遊戲的時候,遊戲有一個新的版本須要資源內更,進來以後也無論你是什麼網絡就直接給你下載了,對於用戶來講這並非一個特別好的體驗。另外就算是Wi-Fi的網絡進來以後,可能用戶也不必定想更新。一個良好的一個用戶感知的體驗應該是,若是是要消耗用戶流量是要告知用戶,在Wi-Fi網絡下咱們儘量的把自動的更新給作掉。另一個方面呢,當咱們的新的版本更新完以後咱們能夠是給用戶一個推送,說明新的版本有那些功能讓用戶來體驗,合理的適度的推送是對用戶的推進是有提高的。

(4)AB測試和灰度發佈

藉助版本的更新咱們能夠作一些AB測試和灰度的發佈。好比說有一個新的功能,這個新的功能到底怎麼作並非咱們的產品經理拍腦殼決定的,要看數聽說話的,那這個時候應該怎麼作呢,咱們會把不一樣實現的策略都把他作好,讓不一樣的用戶去更新不一樣的內容,而後咱們再對比哪一個方案更好。常見的問題:第一,要把採樣埋點預先設計好。有多是咱們的數據出來了,這個方案的數據會更好,可是若是第一次採樣點埋得不夠,咱們就不知道是究竟是什麼緣由。第二,咱們在對比的時候只對比一個維度,若是說AB兩個方案,每一個方案是有三個緯度,可能A的總的數據比B更好,可是A可能並非最優的方案,有可能A裏面第一個點是好的,可是其餘兩個點比B更差,因此說維度多了會有一些干擾因素在裏面,出來的結果不必定是客觀和最優的。第三,樣本的選擇要公平。常見的一個錯誤,想試兩個功能到底怎麼樣,在A渠道試A方案,B渠道試B方案,這個並非那麼準確,由於不一樣的渠道用戶的屬性是有差距的,你在不一樣的渠道試不同的功能,出來的結果不必定準確和客觀。這個解決方案有兩種,一種是叫作客戶端隨機方法,一種是叫服務端隨機方法。客戶端隨機有客戶端決定客戶端具體的表現。服務端隨機的方法就是,我給客戶端隨機的下發不一樣的版原本更新。他們各有優缺點,客戶端隨機的方法它把用戶網絡的差別很平均的給隨機了,服務端隨機的優勢是能夠把數據差的那個方案的用戶給更過來就能夠了。具體選擇哪一種能夠根據你們實際的須要來選擇。第四,樣本的數量要足夠,若是說樣本不夠的話,遇到的經常使用的問題是數據會反覆,第一天我發現A的方案更好,次日變成B的會更好。和AB測試相似的是灰度發佈,當咱們有新的版本準備上線的時候,不要讓全部的用戶都更新,咱們能夠是先小批量的試一下,沒有問題的話是再讓全部用戶更新是會更好。

(5)精細化更新

除了版本更新以外還應該提供一些更加精細的控制,這裏舉了幾個例子分別來講明適用於哪些場景,解決哪些問題。第一,咱們能夠按照機型或者系統的版本更新。爲何有這個需求,相信你們都有遇到這樣的狀況,常常有一個BUG在某個特定的機型或者是特定的系統版本纔有,最好的解決方案是我只更新有問題的用戶,你更新的越多越容易出錯。若是咱們很肯定這個問題只在那一個機型那一個系統版本出現,咱們就只針對這個機型來修復,不想幹的用戶就能夠不走這個更新過程。第二,咱們能夠是根據用戶的不一樣來更新不一樣的版本,好比用小米手機就有這樣的一個特色,若是你用的是穩定版本,它是不會給你作自動更新的,若是你用的是開發版本,那一週可能要給你更新兩次。第三,能夠按照不一樣的區更新。好比一些O2O的產品,它不少都是跟線下門店有一些活動的,可能此次在廣東有活動,下次在上海有活動,在這種狀況下他們可能但願在廣州作活動時只有廣東的用戶看到這個功能,而不是全部的用戶都更新這個功能以後看到只有廣東的用戶來參加,這樣的體驗很差。最後一點,若是咱們可以對用戶進行一個準確的畫像,理論上能夠根據不一樣的標籤把不一樣的用戶更新不一樣的版本。好比在遊戲領域徹底能夠作到我爲大玩家用戶來定製一個版本,讓他玩的更爽。其餘玩家我也能夠更新更加適合於他們一些版本。

(6)版本退回

版本回退是指出現緊急狀況下,能夠先回退到一個能正常工做的版本。具體有兩個表現:若是安裝的就是要回退的目標版本,這種狀況下我只須要讓他啓動老版本就能夠了。還有一種狀況是用戶直接安裝的就是新版本,咱們會作一個逆向的差分,原來咱們是從A到B算一個差分包,如今咱們反過來,就能夠直接把新版本更新爲老版本,帶來的好處是我能夠快速的響應,運營人員只須要在後臺操做一下,告訴他會退到哪個版本就能夠了。而不是讓開發去緊急的查看這個問題,基於以前的代碼來打一個包,版本控制若是不是那麼的嚴格,會容易出問題。

(7)運營支撐能力

那最後再給你們介紹一下,定時上線和預下載這個兩個很實用的東西。好比說雙十一的快到了,若是咱們想針對雙十一開發一個特殊版本,讓用戶能在那一天就看到新版本的這些功能,咱們能夠怎麼作呢?咱們能夠在後臺設置一個到雙十一零點能讓全部用戶看到這個版本,走應用商店的問題是沒辦法保證每一個渠道過審的時間是怎樣的,使用熱更的方案的話,全部的控制都是掌握在本身手上,能夠本身決定用戶什麼時間看到這個新版本。結合定時上線這個功能,還有一個,通常而言咱們建議跟預下載一塊兒用,如何去用呢?好比說咱們爲雙十一準備的版本,通常會提早一個星期作好了並經過了測試,在這種狀況下咱們可讓用戶在無線環境下就已經下載這個版本了,可是這個版本並不會生效,是等到雙十一零點定時上線之後,已經下載的用戶會自動切換到新版本,沒有下載的用戶會提示他有個強更。若是這個時間比較長超過一個星期,根據咱們上面介紹的這個狀況,通常而言,95%的用戶在一週以內會連一次Wi-Fi,一個星期的時間絕大多數用戶都會更新國新版本。


二、各類熱更方案的對比


那最後是一個簡單的和各個熱更方案的對比,咱們就不詳細介紹了,總的來講,樂變的熱更新方案是最牛逼的!

個人分享就到這裏,謝謝你們


本文分享自微信公衆號 - GoCN(golangchina)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索