The role of the Tinker,

As a mobile developer, often encounter will be because of some small bugs need to send version of the problem, it also belongs to the small problems, such as some big problems, if through the user to update to repair the efficiency is too slow, or have not updated the user, so the bugs will remain on the user’s phone, this is very dangerous. Tinker was designed to solve this problem by modifying a small amount of code, generating subpackages, and then downloading very small updates without users feeling at all. It is wechat’s official Hot patch solution for Android. It supports dynamic distribution of code, So library and resources, So that applications can be updated without the need for reinstallation.

Of course, you can also use Tinker to update your plugin. Tinker is a substitute for updates, but in order to accommodate a single responsibility, I would recommend releasing the update directly if it is needed, and using Tinker if it is to fix minor bugs.

Tinker source Github address

Access (Experience the inner journey)

Looking for a document

First open the Github address and go to the access guide at the bottom. OK, what if there is no Chinese version? (It was later found that there was a document in Chinese, but it was not attached to his Github homepage)

According to other bloggers and bloggers, in order to access Tinker and use it, you must also access Bugly. (WTF?

Look at other hot update frameworks.

It turns out that all of the major channels have stopped updating, but Tinker is still updating. For sustainability, Tinker has no choice.

But Tinker doesn’t have the same access documentation, so let’s see how Bugly handles it first. After opening the official website of Bugly, I found a new continent. The original Tinker access process was all in Bugly’s official documents. It almost made me cry.

Bugly official website address

Bugly hot update document address when accessing Tinker please take this article and the official document to use

To access

1. Create my product on the official website of Bugly and record my AppId

2. Add plug-in dependencies

Add the following to the build.gradle file in the project root directory:

buildscript { repositories { jcenter() mavenCentral() } dependencies { classpath "Com. Tencent. Bugly: tinker - support: 1.1.5" classpath (' com. Tencent. Tinker: tinker - patch - gradle - plugin: 1.9.14.6 ')}}Copy the code

Add (note the comments in signingConfigs) to the build.gradle file in the app Module:

Apply plugin: 'com.android.application' // Tinker plugin plugin apply from: 'tinker-support.gradle' android {// This must be configured, SigningConfigs {release {storeFile file('D:\ xxx.jks ') storePassword 'XXX' keyAlias 'XXX' signingConfigs {release {storeFile file('D:\ xxx.jks ') storePassword 'XXX' keyAlias 'XXX' keyPassword 'XXX' } debug { storeFile file('D:\XXX.jks') storePassword 'XXX' keyAlias 'XXX' keyPassword 'XXX' } } defaultConfig { multiDexEnabled true ndk { abiFilters "arm64-v8a", "Armeabi-v7a"} // Recommend dexOptions {jumboMode = true} buildTypes {release {// confuse minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField("boolean", "LOG_ERROR", "False ") // Note that signingConfig SigningConfigs. release} DEBUG {minifyEnabled true shrinkResources true proguardFiles is mandatory getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField("boolean", "LOG_ERROR", "True ") // Notice that signingConfig signingConfigs.debug}} compileOptions {sourceCompatibility JavDowns.version_1_8 is mandatory targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { // tinker implementation "Com. Android. Support: multidex:" 1.0.1 / / dex configuration implementation 'com. Tencent. Bugly: crashreport_upgrade: 1.3.6' Implementation 'com. Tencent. Tinker: tinker - android - lib: 1.9.14.6'}Copy the code

Tinker-support. gradle file does not exist. This file is the main file that we packaged. ‘tinker-support.gradle’ will do.

3. Create tinker-support.gradle

apply plugin: 'com.tceh.bugly. Tinker-support' def bakPath = file("${buildDir}/bakApk ") def baseApkDir = file("${buildDir}/bakApk" "App-release-folder" // Enter the base package directory generated for each build. //def myTinkerId = "base-" + rootProject.versionName // Used to generate the base package (do not change) def MyTinkerId = "patch-" + RootProject. versionName + ".0" Patch -${versionName}.x.x) tinkerSupport {// Enable tinker-support, default true enable = true // specify the archive directory, Default Value Subdirectory of the current Module tinker autoBackupApkDir = "${bakPath}" // Whether to enable the function of overwriting tinkerPatch configurations. The default value is false. Without adding tinkerPatch overrideTinkerPatchConfiguration = true / / compile patches, must specify the baseline version of the apk, the default value is empty if / / is empty, // @{link tinkerpatch. oldApk} baseApk = "${bakPath}/${baseApkDir}/app-release.apk" // ApplyMapping baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt" // ApplyResourceMapping baseApkResourceMapping = "${bakPath}/${baseApkDir}/ app-release-r.table "// Whether to enable the hardening mode, The default value is false.(supported starting from Tinker-spport 1.0.7) // isProtectedApp = false // Whether to enable reflection Application mode enableProxyApplication = true // Whether new non-export activities are supported (note: SupportHotplugComponent = true // Different tinkerIDS should be specified for both base and patch packages. TinkerId = "${myTinkerId}" // buildAllFlavorsDir = "${bakPath}/${baseApkDir}"} tinkerPatch { tinkerEnable = true 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"} buildConfig {keepDexApply = false}}Copy the code

There are a few points to note here:

  • This file must be in your app at the same level as build.gradle in your app
  • Only the leproxyApplication = true is enabled, then comment apply from: ‘Tinker-support. gradle’ will disable Tinker. EnableProxyApplication should be equal to false if you’re overriding application according to the official document, So if you want to stop Tinker, you also need to deal with the Application.
  • BakPath, baseApkDir, myTinkerId, bakPath, baseApkDir, myTinkerId, bakPath, baseApkDir, myTinkerId, baseApkDir, myTinkerId, bakPath, baseApkDir, myTinkerId, baseApkDir, myTinkerId

4. Initialize Bugly+Tinker

public class MyApplication extends Application { private static MyApplication appContext; @Override public void onCreate() { super.onCreate(); appContext = this; configTinker(); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // you must install multiDex whatever tinker is installed! MultiDex.install(getApplication()); // Install tinker This interface is only used for reflection Application access. Beta.installTinker(); } public static synchronized MyApplication getApplication() { return appContext; } /** * Initialize Tinker */ private void configTinker(){// Whether to enable hot update beta. enableHotfix = true; To download the Beta patch. / / whether open canAutoDownloadPatch = true; CanAutoPatch = true; . / / whether to prompt the user to restart the Beta canNotifyUserRestart = false; BetaPatchListener = new betaPatchListener () {@override public void onPatchReceived(String s) { Logutil. e(TAG, "patch download address:" + s); } @Override public void onDownloadReceived(long l, long l1) { LogUtil.e(TAG, String.format(Locale.getDefault(), "%s %d%%", Beta.strNotificationDownloading, (int) (l1 == 0 ? 0 : l * 100 / l1))); } @override public void onDownloadSuccess(String s) {logutil. e(TAG, "download successful "); } @override public void onDownloadFailure(String s) {logutil. e(TAG, "download failed "); } @override public void onApplySuccess(String s) {logutil. e(TAG, "patch applied successfully "); } @override public void onApplyFailure(String s) {logutil. e(TAG, "patch failed "); } @Override public void onPatchRollback() { } }; / / the second parameter are true development equipment, in the background of Bugly patches, you can choose to all users or development equipment Bugly. SetIsDevelopmentDevice (getApplication (), true); / / multi-channel requirement into / / the String channel. = WalleChannelReader getChannel (getApplication ()); // Bugly.setAppChannel(getApplication(), channel); IsDebug is in debug mode bugly.init (getApplication(), appId, isDebug); }}Copy the code

AndroidManifestFile only permissions on the line, 1.3.1 version has been compatible with FileProvider, confused reference official documentation, here not to repeat. At this point, Tinker access is complete.

Release process

First we need to know about two nouns

  • Benchmark package: the APK we post online, the package that users use normally
  • Patch pack: Based on the difference pack generated by the base pack, fixes bugs in the base pack. Users using the base pack can download the patch pack and fix bugs by patching

Perform thermal repair

If an online problem is found, it should be solved by hot fix (rather than APP upgrade) after evaluation. After we fix the bug file, follow the following process:

1. Put the production package apk (the generated package apk and the Mapping file must be backed up when packaging) in the following position in the project. The directory address must be the directory of variables bakPath+baseApkDier in the tinker-support.gradle file.

This directory needs to be created and not automatically generated by Tinker. At first I thought Tinker would generate it automatically, which caused me to keep getting errors when I was patching.

This is the full path to the base package apk and mapping files, we must put the base package in this directory and the name must be app-release.apk, of course you can change the baseApk variable if you want to use a different name. The mapping in the same way.

2. Change tinkerId as the version number of the patch package, which is usually +1 based on “patch-” + RootProject. versionName + “. “Patch -” + RootProject. versionName + “.1”, if multiple base packages are typed, add numbers to distinguish: “patch-” + RootProject. versionName + “.2”

3. Double-click the following command to generate the patch

4. If the patch is generated normally, go to the patch_signed_7zip.apk directory to find the patch package

5. Upload patch package to Bugly background (the target version is the combination of versionName+versionCode, which is the version defined by Bugly for our benchmark package, independent of TinkerId) :

Solutions for difficult and miscellaneous diseases

1. Compatibility issues with higher Gradle versions:

I am currently using version 3.6.4. There seems to be a compatibility issue with version 4.0 or above. I don't know if I have fixed it now.Copy the code

2. Manifest files<queries>Label adaptation:

Android11 need to configure to configure this tag is used to jump to the third party applications, we know that gradle version 4.1 + can be applicable, if less than 4.1, so gradle choose version should be 4.0.1 3.6.4 radar echoes captured / 3.5.4 / rule 3.4.3/3.3.3Copy the code

3. Problems that may occur when using and packaging the base package:

2. Back up the APK and Mapping files every time you release the APK, because different versions may have different bugs. The path of the base package must be correct, otherwise the base package will fail to be found. 4. The signature file must be configured in app build.gradle. TinkerId must be changed every time you modify the patch package; otherwise, errors will occur during patch installation. 6. Under the same base package, many patch packages are releasedCopy the code

4, Tinker conflicts with viewBinding

Need to upgrade the Tinker v1.9.14.6 version and in the engineering build. Gradle join: inside the classpath (' com. Tencent. Tinker: Tinker - patch - gradle - plugin: 1.9.14.6 ')Copy the code

5. Compatible with Google Play

Refer to https://github.com/Tencent/tinker/issues/1314Copy the code