First, you should understand the following concepts: Incremental update: When an APK of a recent version is upgraded, a new installation package is combined based on the differences between the two APKs (the difference package is generated) and the upgrade is performed within the application (the APK file needs to be reinstalled). Hot update: load the dex file dynamically when the release has bugs, and fix the bugs without affecting the APK (no need to reinstall the APK file).

So incremental updates are essentially different from hot updates! The concept should be clear…

This article focuses on the following aspects:

  • Some tools for Android incremental updates
  • Android Incremental Update configuration (JNI configuration)
  • Android incremental update development
  • Some of the problems with Android
  • Share the Demo address

1. Tools for incremental updates

To do a good job, you must sharpen your tools. So tools are important! Here first and everyone to introduce the corresponding tools!!

  • 1.1 BsDIFF-4.3 Download Address (Used to generate a new installation package)

  • 1.2bzip2-1.0.6 is used to supplement the missing code of C in BSDIff
  • 1.3 Bsdiff-v4.3-WIN-x64 is used to generate the corresponding difference package

Since you’re having a hard time finding it, so… so… I’m not prepared either! Haha!! Joke, here is my Baidu net disk address (incremental update tool extraction code for R1WS), if invalid! Contact me in time!

2. Incremental update configuration (JNI configuration)

In fact, I get a headache every time I configure the JNI environment, but I can’t help it for work. One thing I discovered later was, how could you integrate quickly if the project didn’t have the NDK? Here I always create a new NDK project and then copy it!!

2.1 Import the bspatch.c file (this is in BSdiff-4.3, it is very kind!!)

In fact, when you import this file, you’ll notice that. A bunch of fucking red… Are you kidding me? Don’t worry, it’ll be all right after!!

2.2 Files required to import the bspatch.c file

Remember that Bzip2 I asked you to play? In fact, it has to be something in this!! You can get both of them, but as an ambitious programmer, how is that possible? So what files do you need to import? Take a look at the following code (there is a Makefile in bzip):

OBJS= blocksort.o  \
      huffman.o    \
      crctable.o   \
      randtable.o  \
      compress.o   \
      decompress.o \
      bzlib.o
Copy the code

That’s what you need! I put my import file schematic put on, according to the name of direct import good!

There are some potholes to tread:

  1. Android Studio3.+ is different from the previous one when importing bzlib.h:
//#include <bzlib.h>
// This is the only way to import a new version
#include "bzip/bzlib.h"
Copy the code
  1. There is a main method in the bspatch.c file. It is best to change the name to something else to prevent other C code from using the same main method and causing errors!

2.3 Configuring the JNI Environment

This I feel is the most trival, actually configure these really good vexed,,, line not whine!!

2.3.1 Create a method to generate bsPath!

In fact, this is a JNI method, do not forget to load lib! Native_lib should look like this!!

#include <jni.h>
#include <string>

// This is mainly for importing methods
extern "C" {
extern int p_main(int argc, char *argv[]);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_angle_netupdatademo_MainActivity_bsPath(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);

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

The content of this we will dish him later!!

2.3.2 Configuring the cmakelists. TXT file

In fact, I think it is necessary to systematically study this piece, so here we do not do too much introduction, MY notes write very detailed!!

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
        # This is equivalent to an alias reference, where an alias is set
        ${bzip_source}
)

System library, log output log
find_library(
        log-lib

        log)

Libraries that need to be linked or compiled
target_link_libraries(
        native-lib

        ${log-lib})
Copy the code

That’s basically it!!

2.3.3 Build. Gradle of app configures corresponding content

This is actually in the c++ demo to add the corresponding CPU architecture compatibility

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.angle.netupdatademo"
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "2.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""// Compatible with CPI architecture abiFilters'armeabi-v7a'
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com. Android. Support: appcompat - v7:28.0.0'
    implementation 'com. Android. Support. The constraint, the constraint - layout: 1.1.3'
    testImplementation 'junit: junit: 4.12'
}
Copy the code

There’s not much to say here either, check out some articles on JNI configuration for these suggestions!


All the above configuration is over!! Is not very annoying, nothing, soon to see the sunrise!!

3. Development of incremental updates

In fact, generally incremental update is to dynamically download the patch file from the server in the Splash page, put it in a folder, and then generate a new package through the previous apK installation path, and finally install it. That’s basically the process!

So here are some things to work out:

  • Pathc file generation
  • Obtain the installation path of old.apk
  • How do I generate a new installation package

Decomposing missions are easy to do!

3.1 Generation of patch files

Bsdiff old. Apk new. Apk patch: bsdiff old.

3.2 Obtaining the installation path of old.apk

It’s actually pretty simple, one line of code

String oldApk = getApplicationInfo().sourceDir;
Copy the code

3.3 How do I Generate a New APK File

Here we are going to use the JNI method that we did not have disks before!

#include <jni.h>
#include <string>

// This is mainly for importing methods
extern "C" {
extern int p_main(int argc, char *argv[]);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_angle_netupdatademo_MainActivity_bsPath(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)};
    p_main(4, argv);

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

If you look at the code in the middle, this p_main is the main method that I told you to change, it takes four arguments, and then it goes strong. This is actually some knowledge of C, I do not understand. But the code is easy to understand!

Then, call this method to generate a corresponding APK!!

4. Some problems encountered

  • If the version span is too large, you can simply update the appropriate APK installation package. No need for subcontracting! It is well understood that the version span is too large, there is no difference between the subcontracting and the new package, there is no need to do difference!

5. The Demo address

The Demo address

Use the method to generate an APK (old) and then add content in the generated APK (new). Generate disassemble and subcontract! Then put both in the root directory of the SD card to install the old APK and click Update!!