Android NDK develops the application of two parts (2) (incremental updates are the same)

Posted by AJReading on Mon, 15 Jul 2019 22:28:39 +0200

Catalog

Android NDK Develops Two Songs (1) The First Knowledge (JNI General Knowledge and NDK Configuration)
Android NDK develops the application of two parts (2) (incremental updates are the same)

Preface

A previous blog about JNI and NDK on Eclipse Android JNI and Android NDK Literacy Now let's start to study NDK development in detail on the basis of this article and Android Studio.

This article refers to the Great God of Hong Yang. Android Incremental Update Completely Resolves that Incremental is not Hot Repair In the process of learning, I found that Android Studio's support for NDK is becoming more and more friendly, and there is no need to create new files one by one as before. Too many principles will not be repeated, mainly demonstrating the operation changes under the new version.

It is suggested that you read the blog of Hongyang God first and then come back here.

If there is no NDK environment, please refer to Configuration of Android NDK Development Trilogy (1) (AS-NDK Friendly Integration)

New projects

My project here is called BadPatchDemo.


android_studio_new_native_project.png

Check Include C++ support at the same time

If cmake is not installed (a cross-platform C/C++ project compilation and configuration tool), then AS will prompt to install cmake and follow the prompt to complete the installation.


android_studio_install_cmake.png

NDK Development

We found that app/src/main/has an additional cpp folder, which is the directory where our source files are stored.

Add third party code

The premise is that you install bsdiff as in Hongyang Dashen's blog. Because the job of generating differential packages should be on the server, we only integrate bspatch to merge differential packages with old installation packages.

You can download the code, here is the screening of some source code

Link: https://pan.baidu.com/s/1dEHNhx3 password: abnf

After decompression, we directly copy bspatch.c and bzip into the cpp folder, and then switch to the project view editor app/CMakeLists.txt.

Then add the code that needs to be compiled

src/main/cpp/bzip2/blocksort.csrc/main/cpp/bzip2/bzip2.csrc/main/cpp/bzip2/bzip2recover.csrc/main/cpp/bzip2/bzlib.csrc/main/cpp/bzip2/compress.csrc/main/cpp/bzip2/crctable.csrc/main/cpp/bzip2/decompress.csrc/main/cpp/bzip2/huffman.csrc/main/cpp/bzip2/randtable.csrc/main/cpp/bspatch.c

android_studio_add_sourcefiles.png

Finally, click the Synchronization button

Exposing interfaces

We create a new C/C++ Header File - > bspatch. h under the cpp directory mail, and add the following code

#ifndef BSDPATCHDEMO_BSPATCH_H
#define BSDPATCHDEMO_BSPATCH_H
#endif 
//BSDPATCHDEMO_BSPATCH_Hint 
doPatch(int argc, char *argv[]);

doPatch is renamed from the main function of bspatch.c, because when we execute a command under the command line, we actually call the main function of the command line tool. The latter parameters are passed into the main function as strings. The argc represents the number of parameters, and the argv contains the specific content of the parameters.

For example:

mv test /root/
argc = 3
argv[0] = mv
argv[1] = test
argv[2] = /root/

Write native code

We built a new BsdUtil

package com.example.bsdpatchdemo;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;

import java.io.File;

/**
 * Created by August on 2017/3/18.
 */

public class BsdUtil {

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

    /**
     * Native patching method
     *
     * @param oldApk
     * @param patchFile
     * @param newApk
     */
    public static native void patch(String oldApk, String patchFile, String newApk);


    /**
     * Getting the path of its own APK
     *
     * @param context
     * @return
     */
    public static String getOriginalApk(Context context) {
        return context.getApplicationInfo().sourceDir;
    }

    /**
     * Install the specified apk
     *
     * @param context
     * @param apk
     */
    public static void install(Context context, String apk) {
        Intent intent = new Intent();
        intent.setDataAndType(Uri.fromFile(new File(apk)),
                "application/vnd.android.package-archive");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
}

We saw patch blossom, and then we clicked on the hint and asked as to help us create the method. Then we moved it directly to the corresponding C/C++ file.

Now we need to introduce the header file bspatch.h, which just exposed the method.

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

JNIEXPORT void JNICALL
Java_com_example_bsdpatchdemo_BsdUtil_patch(JNIEnv *env, jclass type, jstring oldApk_,
                                            jstring patchFile_, jstring newApk_) {
    const char *oldApk = env->GetStringUTFChars(oldApk_, 0);
    const char *patchFile = env->GetStringUTFChars(patchFile_, 0);
    const char *newApk = env->GetStringUTFChars(newApk_, 0);

    // TODO
    char *argv[] = {(char *) "bspatch", (char *) oldApk, (char *) newApk, (char *) patchFile};
    doPatch(4, argv);


    env->ReleaseStringUTFChars(oldApk_, oldApk);
    env->ReleaseStringUTFChars(patchFile_, patchFile);
    env->ReleaseStringUTFChars(newApk_, newApk);
}

Write calling code

activity_main

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:onClick="patch"
    android:text="old app"
    android:textSize="20sp" />

MainActivity

package com.example.bsdpatchdemo;

import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.io.File;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void patch(View v) {
        String oldApk = BsdUtil.getOriginalApk(this);
        String newApk = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "newApk.apk";
        String patchFile = "/storage/sdcard0/p.patch";
        BsdUtil.patch(oldApk, patchFile, newApk);
        BsdUtil.install(this, newApk);
    }

}

When it comes to read and write permissions, don't forget to add them to Android Manifest

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Compile

Build - > Build APK, when compiling, I exploded a link error here, which is estimated to be caused by improper configuration of C++ and C language.

Solution

  • Change native-lib.cpp to native-lib.c

  • At the same time, change native-lib.cpp in CMakeLists.txt to native-lib.c.

  • Then the object-oriented writing in native-lib.c is changed back to the process-oriented writing in C language.
#include <jni.h>
#include "bspatch.h"

JNIEXPORT void JNICALL
Java_com_example_bsdpatchdemo_BsdUtil_patch(JNIEnv *env, jclass type, jstring oldApk_,
                                            jstring patchFile_, jstring newApk_) {
    const char *oldApk = (*env)->GetStringUTFChars(env, oldApk_, 0);
    const char *patchFile = (*env)->GetStringUTFChars(env, patchFile_, 0);
    const char *newApk = (*env)->GetStringUTFChars(env, newApk_, 0);

    char *argv[] = {(char *) "bspatch", (char *) oldApk, (char *) newApk, (char *) patchFile};
    doPatch(4, argv);


    (*env)->ReleaseStringUTFChars(env, oldApk_, oldApk);
    (*env)->ReleaseStringUTFChars(env, patchFile_, patchFile);
    (*env)->ReleaseStringUTFChars(env, newApk_, newApk);
}

Compile APK again

test

  • Now what we get is that the old APK is renamed old.apk and installed on the mobile phone.

  • Then we change the old app in activity_main to new app, and then build a new apk, renamed new.apk.

  • With two apk s, we can generate differential packages
yubindeMacBook-Pro:Desktop August$ bsdiff old.apk new.apk p.patch
yubindeMacBook-Pro:Desktop August$ adb push p.patch /storage/sdcard0/p.patch
[100%] /storage/sdcard0/p.patch

android_bspatch.gif

Although there is no need to install hot repair, almost all of the hot repair frameworks on the market are based on runtime repair, so there are many compatibility problems. But incremental updates are updated by merging differential packages. As long as the differential packages are correct, there will be almost no compatibility problems. Many applications only need to modify. Code, but the resource file is unchanged. At this time, incremental updates can subtract the size of the resource file, so as to save traffic updates.

In the end

In fact, the main purpose of this blog is to explain the new version of Android Studio's NDK development, incremental updates are just one of the application analysis. In fact, this process has become a migration. You can also find some C libraries, image compression, audio and video conversion, and so on, and then transplant to Android, which is also interesting.

Topics: Android cmake Java C