web123456

Android NDK implements incremental updates based on bsdiff

Android implements bsdiff function based on NDK

Prepare

Download the required C file and decompress it directly

bsdiff
bzip(bsdiff dependency library)

The required files have been downloaded by the project prepare directory

Project creation

Studio new c++ project
1. Unzip bzip to src/main/cpp/bzip directory (you can delete files that are not .c or .h, and keep the file reference project)
2. Unzip bsdiff to src/main/cpp/ directory
3. Configuration
#Related bzip directory
 file(GLOB bzip bzip/*.c)
 #Add c/c++ libraries that need to participate in the compilation
 add_library( # Sets the name of the library.
         patch # default native-lib

         # Sets the library as a shared library.
         SHARED
         # Provides a relative path to your source file(s).
         ${bzip}
        
        
           # default
         )
        
   #Include the bzip directory, no need to write the package path
 include_directories(bzip)
4. Create tool classes
public class PatchUtil {
     static {
         ("patch"); // default native-lib
     }


     public static native int bsPatch(String old, String patch, String output);

     public static native int bsDiff(String old, String newfile, String patch);
 }

Use the shortcut key ALT+ENTER to automatically generate jni methods

5. Implement bsdiff and bspatch functions
// Declare external c methods, bsdiff, and bspatch have main methods, remember to change them to different method names
 extern "C" {
		 extern int main(int argc, const char *argv[]);
		 extern int diff_main(int argc, const char *argv[]);
 }
 
  extern "C" JNIEXPORT jint JNICALL
 Java_me_leon_patch_PatchUtil_bsDiff(JNIEnv *env, jclass thiz, jstring old, jstring newfile_,jstring patch_) {
	
     // Turn jstring to char * because the parameters of bspatch need to be
     const char *oldApk = env->GetStringUTFChars(old, 0);
     const char *newFile = env->GetStringUTFChars(newfile_, 0);
     const char *output = env->GetStringUTFChars(patch_, 0);
    
     // Call bsDiff c method
     const char *argv[] = {"", oldApk, newFile, output};
     int r = diff_main(4, argv);

    
     // jstring release
     // C/C++ does not have the gc function of java, and resources need to be manually released
     env->ReleaseStringUTFChars(old, oldApk);
     env->ReleaseStringUTFChars(newfile_, newFile);
     env->ReleaseStringUTFChars(patch_, output);
     return r;

 }



 extern "C" JNIEXPORT jint JNICALL
 Java_me_leon_patch_PatchUtil_bsPatch(JNIEnv *env, jclass thiz, jstring old,
									  jstring patch_,
                                      jstring output_) {
     // Turn jstring to char *
     const char *oldApk = jstringToChar(env, old);
     const char *patch = jstringToChar(env, patch_);
     const char *output = jstringToChar(env, output_);
    
     // Call bsPatch c method
     const char *argv[] = {"", oldApk, output, patch};
     int r = main(4, argv);
   
     // Resource Release
     env->ReleaseStringUTFChars(old, oldApk);
     env->ReleaseStringUTFChars(patch_, patch);
     env->ReleaseStringUTFChars(output_, output);
     return r;
 }
6. Compile and run the code

CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

Reason: In the higher version of ndk, the default abiFilters is armeabi-v7a

Solution: Add in module defaultConfig closure

ndk{
     abiFilters "arm64-v8a","armeabi-v7a","x86","x86_64"
}
7. After the compilation is successful, write a test program and test the two methods of PatchUtil

Please implement the page and functions by yourself, add two Buttons to realize the PatchUtil function

If you use an app or demo, please prepare the test file first.

adb push   /sdcard/
adb push   /sdcard/
8. Read permissions for manifest file configuration file (higher versions require dynamic authorization)
 <uses-permission android:name=".WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name=".READ_EXTERNAL_STORAGE" />

 <uses-permission android:name=".REQUEST_INSTALL_PACKAGES"/>
9. Test

The return result is 0, which means success. You can use the adb command to view the file status.

adb shell
cd /sdcard
ll

Encapsulate lib for others to use

  • Call the gradle command to generate the so library
graldew build
  • Create a new Android lib project, with the same package name as C++ project
  • copy
  • Copy all folders under \build\intermediates\merged_native_libs\release\out\lib to src/main/jniLibs
  • Use (refer to the use of demo)
    • Introduced through implementation project
    • You can also upload it to jcenter or maven private server and implementaion directly

Attached with a personal package and test library:

implementation 'me.leon406:patch:1.0.1'
 #If it cannot be used, please add it to the project repositories closure
 #maven {url "/leon4062/maven"}

Project address: /Leon406/Patch

refer to:

CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

Android incremental update (used by bsdiff)