Android-增量更新
前言
在我們平常開發app時候,版本1.0迭代到2.0的時候目前還有不少開發得應用是全量更新,也就是重新下載整個2.0的安裝包,重新安裝到手機,其實是有些浪費資源,使用者體驗也不是很好,雖然現在是無限流量,一個app老是出現讓使用者更新全量包,極其影響使用者體驗,而增量更新可以解決2.0-1.0的差分包的大小,使用者只需要在old.apk上更新new.apk的差分包,合成新的apk即可,更新資料包會大大降低,相對上也提高了使用者體驗,獲得手機root全新還可以不知不覺讓app更新安裝完成,這種體驗相對較高,今天就來了解一下如果做到android-apk的增量更新技術。
增量更新流程
增量更新分三部分:1、安裝手機當前應用old.apk
2、利用工具bsdiff 去生成 old.apk 和 new.apk 之間的差分包
3、從伺服器下載生成的差分包到本地sd卡,和當前手機安裝的old.apk進行合併安裝即可
正文
實現增量更新,現在有各種合併差分包的開源庫,比如:bsdiff、hdiff,我們只需要獲得原始碼直接使用即可。
bsdiff下載地址:
http://www.daemonology.net/bsdiff/
bsdiff依賴bizp2(zip壓縮庫)
http://nchc.dl.sourcefore.net/project/gnuwin32/bzip2/1.0.5/bzip2-1.0.5-src.zip
翻牆下載,下載解壓完是這樣的:
最後我會提供提供一下window下的工具(bsdiff-v4.3-win-x64)
把下載好的bspatch.c檔案 放置到cpp目錄下,放入之後會有很多報錯資訊,首先將CMakeLists.txt的新增bsdiff
add_library新增
package com.note.zlgx; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.io.File; public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.tv_version); textView.setText(BuildConfig.VERSION_NAME); Button button = findViewById(R.id.sample_text); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //1.下載new.apk new AsyncTask<Void,Void,File>(){ @Override protected File doInBackground(Void... voids) { String old = getApplication().getApplicationInfo().sourceDir; bspatch(old,"/sdcard/patch","/sdcard/bestChoice/new.apk"); return new File("sdcard/bestChoice/new.apk"); } @Override protected void onPostExecute(File file) { Intent intent = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } else { // 第二個引數,即第一步中配置的authorities String packageName = getApplication().getPackageName(); Uri contentUri = FileProvider.getUriForFile(MainActivity.this, "com.note.zlgx.fileProvider", file); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); // 宣告需要的臨時許可權 } startActivity(intent); } }.execute(); //2.合併安裝 } }); } /** * * @param oldapk 當前執行apk * @param patch 差分包檔案 * @param output 合併之後的新apk輸入路徑 */ native void bspatch(String oldapk,String patch,String output); }
bspatch 定義JNI方法,呼叫so庫方法,進行合併patch喝old.apk查分包
JNI方法區程式碼
extern "C"
JNIEXPORT void JNICALL
Java_com_note_zlgx_MainActivity_bspatch(JNIEnv *env, jobject instance, jstring oldapk_,
jstring patch_, jstring output_) {
const char *oldapk = env->GetStringUTFChars(oldapk_, 0);
const char *patch = env->GetStringUTFChars(patch_, 0);
const char *output = env->GetStringUTFChars(output_, 0);
char * argv[4] = {"", const_cast<char *>(oldapk), const_cast<char *>(output),
const_cast<char*>(patch)};
main(4,argv);
// TODO
env->ReleaseStringUTFChars(oldapk_, oldapk);
env->ReleaseStringUTFChars(patch_, patch);
env->ReleaseStringUTFChars(output_, output);
}