目錄
增量更新
最近換了個新手機,號稱2019年的android機皇一加7plus。面對這90z的屏幕,原本不玩遊戲的我也入了王者農藥的坑!不過很少玩,所以基本上每次玩都要下載補丁更新才能玩。今天我們就來講一下Android應用的增量更新。
介紹
優點:
節省用戶更新新版本的流量、時間、內存空間。
基本流程如下:
- app端開發人員打包新版本上傳到服務器,new_version.apk
- 服務器通過bsdiff(依賴bzip2)兩個c庫,與原來純在服務器上面的舊版本進行差分,生成補丁包patch
- app下載補丁包patch,與手機上安裝的舊版本old_version.apk合成新的apk
- 安裝新的apk
效果
步驟
1、準備bsdiff和bzip2(生成補丁,合成新版本必須用到的工具)
mac/linux系統下:
下載bsdiff庫:http://www.daemonology.net/bsdiff/
由上圖可知,bsdiff庫和bspatch依賴bzip庫,所以我們還要下載一個bzip庫:https://sourceforge.net/projects/bzip2/
//待更新
window系統下:
已經給大家編譯好,包括bsdiff,bspatch,bzip2,大家直接下載就好
https://download.csdn.net/download/u014736095/11869005
2、配置Android項目ndk環境
這裏不詳細展開來說,提供一個比較便捷的方法,新創建一個ndk的項目,把一下重要文件複製進來即可!
module的build.gradle文件
//...
android {
//...
defaultConfig {
//...
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
3、引入項目bspatch.c和bzip2的庫
如下圖,引入bspatch.c庫,用於將舊版本apk與補丁patch合成新版本apk文件。
bspatch.c所依賴的bzip2庫也要複製進來。
4、c庫代碼(至關重要)
修改CMakeLists.txt配置文件
# 設置構建本機庫所需的CMake最低版本。
cmake_minimum_required(VERSION 3.4.1)
# 聲明一個文件夾所有的c文件
file(GLOB bzip2_resource bzip2-1.0.6/*.c)
add_library( # 設置庫的名稱。
native-lib
#將庫設置爲共享庫。
SHARED
# 提供源文件的相對路徑。
native-lib.cpp
bspatch.c
${bzip2_resource}
)
# 引入一個目錄
include_directories(bzip2-1.0.6)
find_library(
log-lib
log )
target_link_libraries(
native-lib
${log-lib} )
重新編譯可能無法通過,會有異常,作以下修改即可
重新編譯即可。
Activity中聲明一個native函數
/**
* 合成新的apk安裝包
* @param oldApk 舊版本
* @param patch 補丁
* @param newApk 新版本
* @return
*/
public native String increaseUpdate(String oldApk,String patch,String newApk);
編輯native-lib.cpp,聲明函數與之關聯,注意這個函數的命名是有規律的,Java_{類名路徑,分割用“_”}_{方法名}
5、編寫更新的代碼
涉及到文件讀寫,需要配置申請權限,併兼容高版本
AndroidManifest.xml
<manifest >
<!--存儲-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--位未知來源權限,適配8.0-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application
>
<!--四大組件之一 內容提供者 可以跨進程使用,7.0安裝必須使用它-->
<provider
android:authorities="com.bluetree.myapplication.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resource xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path name="haah" path="." />
</paths>
</resource>
合成新版本apk,
new AsyncTask<Void, Void, File>() {
@Override
protected File doInBackground(Void... voids) {
createNewFile(newApkPath);
increaseUpdate(oldApkPath, patchPath, newApkPath);
return new File(newApkPath);
}
@Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
if(file == null) return;
installApk(file);
}
}.execute();
/**
* 創建一個文件
* @param path
* @return
*/
private File createNewFile(String path) {
File file = new File(path);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
/**
* 安裝應用
* @param file
*/
private void installApk(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
//兼容7.0
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
} else {
// 聲明需要的臨時權限
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// 第二個參數,即第一步中配置的authorities
String packageName = getApplication().getPackageName();
Uri contentUri = FileProvider.getUriForFile(MainActivity.this, packageName + ".fileprovider", file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
6、製作差分包
製作兩個版本,必須用相同的證書,否者不成功
unix下:bsdiff/. {舊版本} {新版本} {補丁名字}
win下命令:bsdiff {舊版本} {新版本} {補丁名字}
7、測試
標準情況下,補丁包的是在服務器上生成的,手機客戶端從服務器上下載補丁patch,與手機上存在的舊版本,合成新的版本(通過調用bspatch.c中的main方法進行合成),然後安裝!所以合成後,手機硬盤上會產生新的安裝包。這個版本實際上與之前打包出來的新版本大小是一致的。
- 手機上安裝app_old.apk
- 把補丁patch複製到手機儲存根目錄下(模擬從服務器下載補丁)
- 點擊“update”(增量更新)
注意事項:
1、mac或者Linux系統中,需要在bsdff文件夾中進行make指令編譯
2、bspatch.c文件記需要重新導入bzlib.h
3、正確編寫CMakeList文件
4、記得調用bspatch.c中的main()方法所傳進去的數組元素順序
總結
實際上增量更新的核心就是兩部分,
- 會使用工具將新版本與舊版本進行差分,生成補丁包
- 會配置項目的NDK環境,調用bspatch.c庫中的代碼,將下載的補丁包+舊版本合併成新版本。
建議先下載完整的項目下來體驗一下,然後看着源碼一步一步學習!否則很多坑,最好能夠下載這篇文章裏的庫,導入你的項目,這樣可以省去折騰因爲版本差異導致的問題!