For the majority of mobile developers, App version update is a common thing. However, when you find that the package you just sent has urgent bugs that need to be fixed, you will not be calm, and you have to go through the tedious traditional App version update process, re-release a bug-fixing version, and then upload the Apk to various App stores, and users need to spend time to download and install it again in the App store. If the Bug is serious, some users may lose patience and simply uninstall the App, and you will lose your users.


The traditional update process has several disadvantages: first, it is time-consuming and costly to re-release the version; second, users need to go to the app store to download the version; third, they cannot fix bugs in time and have poor user experience. However, the emergence of H5 makes this situation a little turning point. The business logic that needs to be changed frequently is isolated in the way of H5 and then embedded in App. Why is it a small turnaround? Because you still have native code in your App, and you can’t guarantee that native code won’t Bug. And that’s where hot update comes in.


At present, there are many hot update technologies in China, such as Ali AndFix and Sophix. Wechat’s Tinker; Qzone super patch; Are you hungry Amigo; The Robust of Meituan has its own advantages and disadvantages. There are two main schemes to realize code repair: the bottom replacement of Ali system and the class loading of Tencent system. The underlying replacement is more limited, but can immediately load the patch package to achieve hot repair. Class loading requires a cold start for hot fixes to work, but with few restrictions and a wide range of fixes. If you are interested, you can go to know about it. I recommend a hot repair book “In-depth Exploration of The Principle of Android Hot repair Technology” by Ali engineers, which explains the principle of hot repair in detail. Today I will mainly teach you how to integrate Tencent’s Tinker-based hotfix framework Bugly into the project, and then I will start to talk about the steps of integration.


Step 1: Add the plugin dependencies to the build.gradle file in the root directory:

Executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables = new executables For example the classpath 1.0.4"com.tencent.bugly:tinker-support: latest.release"}}Copy the code

Add (example configuration) to the “build.gradle” file in the App Module:

android {
        defaultConfig {
        }
      }
      dependencies {
          compile "Com. Android. Support: multidex: 1.0.1." "// multiple dex configuration // comment out the original bugly repository //compile'com.tencent.bugly:crashreport:latest.release'Latest. Release indicates the latest version number. You can also specify a specific version number, for example, 2.3.2 compile'com. Tencent. Bugly: crashreport_upgrade: 1.3.4'
      }
Copy the code

In the app Module “build.gradle” file add:

// The dependency plugin script applies from:'tinker-support.gradle'
Copy the code

Note: You need to create tinker-support.gradle in the same directory as the tinker-support.gradle file.

apply plugin: 'com.tencent.bugly.tinker-support'

def bakPath = file("${buildDir}/bakApk/") /** * Enter the base package directory generated by each build */ def baseApkDir ="app-0208-15-10-00"/** * For details about plug-in parameters, see */ tinkerSupport {// Enable tinker-support. The default value is tinker-supporttrue
    enable = true// Specify the archive directory. The default is the current module subdirectory tinker autoBackupApkDir ="${bakPath}"// Whether to enable overwriting tinkerPatch configuration. The default valuefalse/ / open tinkerPatch configuration is not effective after that without adding tinkerPatch overrideTinkerPatchConfiguration =trueWhen compiling the patch package, you must specify the apK of the baseline version. The default value is null. If this value is null, it indicates that the patch package is not compiled"${bakPath}/${baseApkDir}/app-release.apk"// Corresponding tinker plug-in applyMapping baseApkProguardMapping ="${bakPath}/${baseApkDir}/app-release-mapping.txt"// applyResourceMapping baseApkResourceMapping ="${bakPath}/${baseApkDir}/app-release-R.txt"// Base and patch packages are built with different Tinkerids and must be unique tinkerId ="1.0.0 - base"// buildAllFlavorsDir = when building multichannel patches"${bakPath}/${baseApkDir}"// Whether to enable the hardening mode. The default value is false.(supported from tinker-spport 1.0.7) // isProtectedApp =true// Whether to enable reflection Application modeenableProxyApplication = false
supportHotpugComponent = true} /** * Generally speaking, we do not need to make any changes to the following parameters * For detailed description of each parameter please refer to: * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 */ tinkerPatch { //oldApk ="${bakPath}/${appName}/app-release.apk"
    ignoreWarning = false
    useSign = true
    dex {
        dexMode = "jar"
        pattern = ["classes*.dex"]
        loader = []
    }
    lib {
        pattern = ["lib/*/*.so"]
    }

    res {
        pattern = ["res/*"."r/*"."assets/*"."resources.arsc"."AndroidManifest.xml"]
        ignoreChange = []
        largeModSize = 100
    }

    packageConfig {
    }
    sevenZip {
        zipArtifact = "Com. Tencent. Mm: SevenZip: 1.1.10"
//        path = "/usr/local/bin/7za"
    }
    buildConfig {
        keepDexApply = false
        //tinkerId = "1.0.1 - base"
        //applyMapping = "${bakPath}/${appName}/app-release-mapping.txt"// Optional, set the mapping file. It is recommended to keep the proGuard obfuscation mode of the old APK //applyResourceMapping ="${bakPath}/${appName}/app-release-R.txt"// Optional, set r.txt file to keep ResId allocation through old APK file}}Copy the code

Step 3: Initialize the SDK enableProxyApplication = false this is the access method recommended by Tinker, which increases the access cost somewhat, but has better compatibility. After integrating the Bugly upgrade SDK, we need to customize ApplicationLike to implement the Application code (here is an example) as follows: Custom Application

public class MyApplication extends TinkerApplication {
    public MyApplication() {
        super(ShareConstants.TINKER_ENABLE_ALL, "xxx.xxx.MyApplicationLike"."com.tencent.tinker.loader.TinkerLoader".false); }}Copy the code

Don’t forget to add MyApplication to the Name attribute under the Application TAB in AndroidMenifest.

Custom ApplicationLike

public class MyApplicationLike extends DefaultApplicationLike {
    public MyApplicationLike(Application application, int tinkerFlags,
            boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,
            long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }


    @Override
    public void onCreate() { super.onCreate(); // When debugging, change the third parameter to Buglytrue
        Bugly.init(getApplication(), "fb2bada5b4".true); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Override public void onBaseContextAttached(Context base) { super.onBaseContextAttached(base); // you must install multiDex whatever tinker is installed! MultiDex.install(base); / / install tinker / / TinkerManager installTinker (this); Replace it with the following method provided by Bugly: beta.installtinker (this); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) { getApplication().registerActivityLifecycleCallbacks(callbacks); }}Copy the code

EnableProxyApplication = true call bugly.init (getApplication(), “fb2Bada5b4 “, true) directly in your Application’s onCreate() method;


In AndroidMainfest.xml, do the following configuration: Permissions configuration

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Copy the code

Step 5: Obfuscation configuration To avoid obfuscating the SDK, add the following configuration to the Proguard obfuscation file:

-dontwarn com.tencent.bugly.** -keep public class com.tencent.bugly.**{*; }Copy the code

If you use the support-V4 package, you also need to configure the following obfuscation rules:

-keep class android.support.**{*; }Copy the code

So far, the Bugly framework has been successfully integrated


Next, test the hot fix


1. Compile the baseline configuration tinkerId of the baseline

AssembleRelease (assembleRelease)

This will generate the base package, obfuscated configuration file, and resource Id file for each compilation in the build/bakApk path, as shown below:

Start the app-release.apk generated in the previous step. After startup, the SDK will automatically report the networking data. We will request the patch policy for each cold startup and report the current version number and tinkerId, so that the background can correspond the unique tinkerId to a version.


2, the baseline version of the bug before fixing

After repair


3. Modify the APK path, Mapping file path, resId file path and tinkerId to be repaired according to the patch package generated by the baseline version

Execute the task that builds the fix pack

Outputs /patch in build/outputs/patch directory:


4. Upload the patch package to the platform upload the patch package to the platform and deliver the editing rule

After selecting the file, the target version will be automatically identified. If “App version not matched to available patch” appears, if your baseline version has not been reported to the Internet, the patch package generated based on this version will not be matched. After starting the app-release.apk generated before, the SDK will automatically report the Internet data after starting


5. Test the patch application effect. The baseline version App crashed when clicking the display text, but the null pointer we created before was abnormal. I configured the Beta. CanNotifyUserRestart = true, so will the pop-up dialog, remind user to update the application. Tinker needs another cold startup to make the patch take effect. After clicking to restart the application, it will exit, and then restart APK. Click to display text, and the text content will be displayed as the repaired content, and the previous null pointer exception will be successfully repaired.


Bugly also supports full capacity upgrade, abnormal report, statistics, operation details can see Bugly official documentation: https://bugly.qq.com/docs/ this demo: https://github.com/isJoker/WanBuglyHotFixDemo