Introduction to Android incremental updates

To be clear, Android incremental updates and hot fixes are different technical concepts.

Hot fix is generally used when the released app has bugs that need to be fixed. Developers modify the code and issue patches, so that the application can be updated without re-installation. Mainstream solutions include Tinker, AndFix, etc.

The purpose of incremental update is to reduce the volume of the package that needs to be downloaded to update the APP. For example, the volume of APK package is several hundred meters, but sometimes the update only needs to download more than ten meters of the installation package to complete the update.

The principle of incremental update is simply to find the differences between the new version and the old version through the binary algorithm, and extract the differences to generate the so-called patch package (differential subcontract). When the mobile terminal checks the update, it only needs to apply to the server to download the corresponding patch package, and then merge the difference package with its old version APK to generate the latest version APK. The final installation of the apK generated by the merge completes the version update.

The realization of the function is mainly with the help of third party difference tools, equivalent to doing records, convenient later recall.

Demonstration of incremental update process

There are two main processes for incremental updates. First, the background compares the latest APK (V1.0.1) with the previous version (v1.0.0) and generates subcontracting. The second step is to download the corresponding subpackage on the mobile terminal and merge it locally to generate the complete latest APK and guide the user to install it.

For apK package difference and merge, need to use the BSDIff tool to achieve

Download bsdiff_win_exe.zip and unzip it locally

Where bsdiff.exe is the tool used by Window to generate subcontracting, and bspatch is the tool used to synthesize subcontracting

2.1 Generation of subcontracting

First of all, type an old APK (v1.0.0.apk) and a new APk (v1.0.1.apk) respectively and store them in the directory that you extracted previously.

Then open the Windows command line tool, switch to the directory, and type the command bsdiff v1.0.0.apk v1.0.1.apk patch.patch

You can see the generated subpackage patch.patch in the directory

2.2 Composite subcontracting

Keep in the current directory and type bspatch v1.0.0.apk new.apk patch.patch

You will see the complete installation package new.apk synthesized in the current directory

The generated new.apk is exactly the same as v1.0.1.apk, just install it.

Incremental updates for Android applications

The above procedure is to demonstrate the process and is now applied to the Android side. During the incremental update process, Android mobile is only responsible for downloading and merging subpackages and guiding users to install them. Therefore, assume that the corresponding subcontracting has been downloaded. There are three main steps: the first is to obtain its own old APK path; The second is to integrate the difference tool into Android. The third is to call the method to merge the subcontracting and guide the user to install.

3.1 Obtaining the Installed Old APK Path

// Get the current running APK path
String oldApk = getApplicationInfo().sourceDir;
Copy the code

3.2 Integrate the differential merge function into Android

Bsdiff open source tool source for. C file, that is, the Android side needs to configure JNI (following is based on CMake).

To facilitate integration, required functions have been packaged into the SO package. You can import the SO package directly. Skip this step. Baidu Web disk link (extraction code: 8IA7)

Bsdiff source code depends on BsZip, so you need to download both source code; Or Baidu web disk download (extraction code: PSBU)

3.2.1 Import required Source files

  • Unzip the bsdiff-4.3.tar.gz file and copy the bspatch.c file to your Android CPP directory

  • Unzip the bzip2-1.0.6.tar.gz file and copy the required source files to the Android CPP /bzip directory as shown

  • Modify the contents of the bspatch.c file

(1) Modify the import declaration of bzlib.h: open the bspatch. C file and modify the header file

2) Find the main method and rename it execute_patch

3.2.2 Configuring the CMakLists. TXT file

Cmake_minimum_required (VERSION 3.4.1 track)# find the path of the specified pattern in the file system, such as /* file matching the root directory (note the path)
file(GLOB bzip_source ${CMAKE_SOURCE_DIR}/bzip/*.c)

# set up local dynamic library compilation to generate dynamic library
add_library(
        # module name
        native-lib
        # Dynamic library/sharing ok
        SHARED

        # the source file
        native-lib.cpp

        Configure the corresponding file references
        bspatch.c

        ${bzip_source}
)

find_library(
        log-lib

        log)

target_link_libraries(
        native-lib

        ${log-lib})
Copy the code

3.2.3 Adding calling methods to native-lib. CPP

extern "C" {
extern int execute_patch(int argc, char *argv[]);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_utilities_BsPatchUtil_patch(JNIEnv *env, jobject instance, jstring oldApk_, jstring patch_, jstring output_) {

    // Convert a Java string to a char pointer
    const char *oldApk = env->GetStringUTFChars(oldApk_, 0);
    const char *patch = env->GetStringUTFChars(patch_, 0);
    const char *output = env->GetStringUTFChars(output_, 0);
    //bspatch ,oldfile ,newfile ,patchfile
    char *argv[] = {"".const_cast<char *>(oldApk), const_cast<char *>(output),
                    const_cast<char *>(patch)};
    execute_patch(4, argv);

    // Release the corresponding pointer gc
    env->ReleaseStringUTFChars(oldApk_, oldApk);
    env->ReleaseStringUTFChars(patch_, patch);
    env->ReleaseStringUTFChars(output_, output);
}
Copy the code

Note: The Java_com_example_myapplication_utilities_BsPatchUtil_patch method name needs to be changed based on the actual definition

3.3 Defining methods: The Java layer uses composition functionality

Define a BsPatchUtil class and call c code :(this method name corresponds to the Java_com_example_myapplication_utilities_BsPatchUtil_patch method name mentioned above)

public class BsPatchUtil {
    static {
        System.loadLibrary("native-lib");
    }

    / * * *@paramOldApkPath Old APK file path *@paramNewApkPath New APK file path *@paramPatchPath Storage path of the generated subpackage */
    public static  native void patch(String oldApkPath, String newApkPath, String patchPath);

}
Copy the code

3.4 Composite subcontracting

// The path to the installed old APK
val oldApk = applicationInfo.sourceDir

// Subcontract path
val patch = ...

// Store path of the synthesized new APK
val output = ...

// Synthesize apK package
BsPatchUtil.patch(oldApk, patch, output)
Copy the code

Synthetic subcontracting needs to run in child threads to prevent blocking the main thread. Finally, boot the user to install the newly generated APK.