android包名更换后升级方案,Android增量升级方案
背景
隨著業務的發展,安裝包的體積也在不斷的增大,這時候,如果要版本更新,用戶不得不去下載完整的安裝包。但是如果使用增量升級方案,用戶只需要下載新舊版本的差異包,然后在本地合成就行,這樣省時省力。我們可以看下某產品使用增量升級時的數據:xxx.2.4.0000.apk 32MB
xxx.2.5.0000.apk 28MB
差異包 6.3MB
其中增量包就是上文提到的差異包,可見用戶每次升級只需下載差異包就行,省時省力。
原理
其原理就是,我們在服務器端先拿新版本安裝包和舊版本安裝包進行對比,在生成差異包之后下發,之后客戶端根據對應的差異包和本地舊版本安裝包合成,便生成了新版本安裝包
實現
0x01 下載編譯差分合并工具:
apk文件的差分和合并都是使用的開源的二進制比較工具?bsdiff實現,值得注意的是,該工具依賴bizp2這個庫。在下載完畢后,直接make便可以編譯工具,不過我在一臺蘋果機器上編譯的時候出現了一點問題,那時候make文件沒法正確的讀取,所以我修改了make文件,讀者編譯的時候(僅限mac, linux)只需要運行install.sh腳本就行。這部分的代碼我已經單獨抽出來作為一個repo,讀者喜歡可以自行star,然后下載編譯?repo
0x02 生成差異包
如果你剛剛編譯成了bsdiff,在命令行里面輸入bsdiff或者bspatch就會出現如下的信息:
其中bsdiff用于比較新舊文件的差異部分并生成差異包,bspatch根據之前差異包和舊文件生成新文件,我們可以從這兩個可執行文件的報錯信息看出該命令如何使用。我們這里有兩個文件:new.so 和 old.so
之后我們運行 diff old.so new.so patch.so便生成了差異包patch.so
0x03 合成新版本
通過剛剛的介紹,我們已經在Android端實現了相關的庫,只需要簡單的調用YPatch.patch(oldFilePath,?newFilePath,?patchFilePatch)
便可以將新版本存放到newFilePath指定的目錄下
結合Small框架
上面好像都是在講原理,沒有具體的實踐講解的話,估計讀者還是不懂,我們現在就結合Small框架來看看如何做到增量更新。
對于我們的Small框架,我們要知道,它把每個插件都編譯成.so文件,然后存放到app的native目錄下,不過,如果它發現自己的download目錄有新的插件,那么就會去加載download目錄下的插件,并且這種加載優先權是最大的,也就是說它會優先加載download目錄下的插件。所以,如果我們要做增量更新,舊文件就從app的native目錄進行讀取,然后從服務器端下載增量包,最后合成的文件存放到download目錄下,這樣每次插件啟動都會到download目錄下加載新的插件。
實現://其中pluginUri對應的是bundle.json中插件對應的uri
//下文有介紹
String?packageName?=?parsePackageName(context,?pluginUri);????????if?(TextUtils.isEmpty(packageName))?{
Log.e(TAG,?"can't?parse?plugin's?package?name,?check?if?assets/bundle.json?is?deleted");????????????return;
}????????//?small框架的約定就是,插件名字是以lib+包名.so明明的
//?比如如果我們插件的包名是com.chan.app.setting
//?那么對于插件名就是libcom_chan_app_setting.so
final?String?soName?=?"lib"?+?packageName.replaceAll("\\.",?"_")?+?".so";????????//找到舊版本的插件安裝包
final?File?oldPlugin?=?new?File(context.getApplicationInfo().nativeLibraryDir,?soName);????????//新版本都存放到small指定的download目錄下
final?File?newPlugin?=?new?File(FileUtils.getDownloadBundlePath(),?soName);????????//開始下載patch
OkHttpClient?okHttpClient?=?new?OkHttpClient();
Request?request?=?new?Request.Builder().url(uri).build();
Call?call?=?okHttpClient.newCall(request);
call.enqueue(new?Callback()?{????????????@Override
public?void?onFailure(Request?request,?IOException?e)?{
}????????????@Override
public?void?onResponse(Response?response)?throws?IOException?{????????????????//保存從服務器端下載的增量包
File?patch?=?new?File(FileUtils.getDownloadBundlePath(),?"patch.so");
FileOutputStream?fileOutputStream?=?new?FileOutputStream(patch);????????????????byte[]?content?=?response.body().bytes();
fileOutputStream.write(content);
fileOutputStream.flush();
fileOutputStream.close();????????????????//合成的新插件安裝包存放文職有new?Plugin指定
YPatch.patch(oldPlugin.getAbsolutePath(),?newPlugin.getAbsolutePath(),?patch.getAbsolutePath());
}
});
可以看到這個函數中出現的pluginUri,它其實對應的是bundle.json中插件的uri:{
"version":?"1.0.0",
"bundles":?[
{
"uri":?"main",
"pkg":?"com.chan.app.main",
"rules":?{
"item":?".ItemActivity"
}????},
{
"uri":?"setting",
"pkg":?"com.chan.app.setting",
"rules":?{
"index":?".MainActivity"
}????}
]}
也就是這里的main, setting
而這個bundle.json就是宿主中asset下的small配置文件:
示例代碼:OkSmall.merge(LaunchActivity.this,?"setting",?"http://192.168.1.100:8080/patch.so");
Toast.makeText(LaunchActivity.this,?"重啟應用后更新生效",?Toast.LENGTH_SHORT).show();
至此,所有的內容已經介紹完畢
要踩的坑
更新插件的時候要記得把插件的versionCode加大,比如 我們這里的setting插件:
要記得加大11行的數值,不然加載還是不成功的
引用
總結
以上是生活随笔為你收集整理的android包名更换后升级方案,Android增量升级方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS下设置vim的tab键为4格
- 下一篇: 4*4矩阵式键盘识别技术c语言程序,4×